--- a/NEWS Thu Feb 14 09:18:55 2008 +0000
+++ b/NEWS Tue Feb 19 08:22:20 2008 +0000
@@ -6,6 +6,40 @@
Changes in version 1.4.0:
+* Realtime interface changes:
+ - 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 (alias/position, slave configurations).
+ - 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_memory().
+ - Replaced the process data pointers in the Pdo entry registration
+ functions with a process data offset, that is now returned by
+ ecrt_domain_reg_pdo_entry(). This was necessary for the external
+ domain memory. An additional advantage is, that the returned offset value
+ is directly usable.
+ - Replaced ecrt_slave_pdo_mapping/add/clear() with
+ ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
+ Pdo configuration. Pdo entries mapped in this way can now immediately be
+ registered. The Pdo mapping and the configuration are described with the
+ new data types ec_pdo_info_t and ec_pdo_entry_info_t.
+ - 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().
+ - 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_domain_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.
* Added 8139too driver for kernel 2.6.22, thanks to Erwin Burgstaller.
* Added e1000 driver for kernel 2.6.22.
* Allow gaps in PDO mapping read from CoE.
--- a/TODO Thu Feb 14 09:18:55 2008 +0000
+++ b/TODO Tue Feb 19 08:22:20 2008 +0000
@@ -11,9 +11,7 @@
* Realtime interface changes:
- PDO configuration.
- SDO access.
- - Replace process data pointers with offset.
- External memory for domains.
- - Separate slave configuration from slave structure.
* Mailbox handler
* Read PDO mapping via CoE during bus scan.
* SDO write access in sysfs.
@@ -22,6 +20,11 @@
* Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for
applications.
* Update documentation.
+* READMEs for examples.
+* Calculate expected working counter for domains.
+* Distributed clocks.
+* Support slaves, that don't support the LRW datagram, only LRD/LWR.
+* Implement all EtherCAT datagram types.
Future issues:
@@ -30,10 +33,7 @@
to replace lsec.
- Step 2: Move kernel threads to user space daemon with a TCP interface
replacing the cdev.
-* Distributed clocks.
* Redundancy with 2 network adapters.
-* Support slaves, that don't support the LRW datagram, only LRD/LWR.
-* PDO reading in IDLE mode.
* Interface/buffers for asynchronous domain IO.
Smaller issues:
@@ -42,12 +42,9 @@
* Clear sync managers in INIT.
* Simplify FSMs with <state>_enter() functions.
* Read out CRC counters.
-* Calculate expected working counter for domains.
* Optimize alignment of process data.
* Evaluate EEPROM contents after writing.
* Configure slave ports to automatically open on link detection.
-* Calculate cycle time of operation state machine.
-* Locking for serveral slave variables for sysfs access.
* Interrupt master state machines state scan for other jobs.
* Master state machine, slave configuration: Do not check every slave on
a cycle.
@@ -55,7 +52,6 @@
Less important issues:
-* Implement all EtherCAT datagram types.
* File access over EtherCAT (FoE).
* Allow VLAN tagging.
* Determine number of frames, the NIC can handle.
--- a/documentation/graphs/fsm_slave_conf.dot Thu Feb 14 09:18:55 2008 +0000
+++ b/documentation/graphs/fsm_slave_conf.dot Tue Feb 19 08:22:20 2008 +0000
@@ -8,6 +8,7 @@
enter_sdoconf [shape=point,label=""]
enter_mapconf [shape=point,label=""]
enter_pdo_sync [shape=point,label=""]
+ enter_saveop [shape=point,label=""]
start -> init [weight=10]
init -> init
@@ -18,8 +19,8 @@
clear_fmmus -> error
clear_fmmus -> enter_mbox_sync [weight=10]
enter_mbox_sync -> end [label="INIT req."]
- enter_mbox_sync -> preop
- enter_mbox_sync -> mbox_sync [label="mailbox SMs", weight=10]
+ enter_mbox_sync -> preop [label="No mailboxes"]
+ enter_mbox_sync -> mbox_sync [label="Has mailboxes", weight=10]
mbox_sync -> mbox_sync
mbox_sync -> error
mbox_sync -> preop [weight=10]
@@ -27,8 +28,9 @@
preop -> error
preop -> end [label="PREOP req."]
preop -> enter_sdoconf [weight=10]
- enter_sdoconf -> enter_mapconf
- enter_sdoconf -> sdoconf [label="SDOs to configure", weight=10]
+ enter_sdoconf -> enter_saveop [label="No configuration"]
+ enter_sdoconf -> enter_mapconf [label="No SDO configs"]
+ enter_sdoconf -> sdoconf [label="SDO configs", weight=10]
sdoconf -> sdoconf
sdoconf -> error
sdoconf -> enter_mapconf [weight=10]
@@ -42,11 +44,12 @@
pdo_sync -> pdo_sync
pdo_sync -> error
pdo_sync -> enter_fmmu [weight=10]
- enter_fmmu -> saveop
+ enter_fmmu -> enter_saveop
enter_fmmu -> fmmu [label="FMMUs to configure", weight=10]
fmmu -> fmmu
fmmu -> error
- fmmu -> saveop [weight=10]
+ fmmu -> enter_saveop [weight=10]
+ enter_saveop -> saveop
saveop -> saveop
saveop -> error
saveop -> end [label="SAVEOP req."]
--- a/examples/mini/mini.c Thu Feb 14 09:18:55 2008 +0000
+++ b/examples/mini/mini.c Tue Feb 19 08:22:20 2008 +0000
@@ -44,6 +44,8 @@
#define FREQUENCY 100
//#define KBUS
+#define PDOS
+#define MAPPING
/*****************************************************************************/
@@ -53,7 +55,7 @@
static ec_master_t *master = NULL;
static ec_domain_t *domain1 = NULL;
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
-static ec_master_status_t master_status, old_status = {};
+static ec_master_state_t master_state, old_state = {};
// data fields
#ifdef KBUS
@@ -61,17 +63,20 @@
static void *r_outputs;
#endif
-static void *r_dig_out;
-static void *r_ana_out;
-static void *r_count;
-static void *r_freq;
-
-#if 1
-const static ec_pdo_reg_t domain1_pdo_regs[] = {
- {"2", Beckhoff_EL2004_Outputs, &r_dig_out},
- {"3", Beckhoff_EL4132_Output1, &r_ana_out},
- {"#888:1", Beckhoff_EL5101_Value, &r_count},
- {"4", Beckhoff_EL5101_Frequency, &r_freq},
+#ifdef MAPPING
+const ec_pdo_info_t mapping[] = {
+ {EC_DIR_INPUT, 0x1A00}, // channel 1
+ {EC_DIR_INPUT, 0x1A01} // channel 2
+};
+#endif
+
+#ifdef PDOS
+static uint8_t off_ana_in;
+static uint8_t off_ana_out;
+
+const static ec_pdo_entry_reg_t domain1_regs[] = {
+ {0, 1, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
+ {0, 2, Beckhoff_EL4102, 0x3001, 1, &off_ana_out},
{}
};
#endif
@@ -91,7 +96,7 @@
// process data
// k_pos = EC_READ_U32(r_ssi);
- EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
+ //EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
if (counter) {
counter--;
@@ -101,24 +106,24 @@
blink = !blink;
spin_lock(&master_lock);
- ecrt_master_get_status(master, &master_status);
+ ecrt_master_state(master, &master_state);
spin_unlock(&master_lock);
- if (master_status.bus_status != old_status.bus_status) {
- printk(KERN_INFO PFX "bus status changed to %i.\n",
- master_status.bus_status);
+ if (master_state.bus_state != old_state.bus_state) {
+ printk(KERN_INFO PFX "bus state changed to %i.\n",
+ master_state.bus_state);
}
- if (master_status.bus_tainted != old_status.bus_tainted) {
+ if (master_state.bus_tainted != old_state.bus_tainted) {
printk(KERN_INFO PFX "tainted flag changed to %u.\n",
- master_status.bus_tainted);
+ master_state.bus_tainted);
}
- if (master_status.slaves_responding !=
- old_status.slaves_responding) {
+ if (master_state.slaves_responding !=
+ old_state.slaves_responding) {
printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
- master_status.slaves_responding);
+ master_state.slaves_responding);
}
- old_status = master_status;
+ old_state = master_state;
}
#ifdef KBUS
@@ -158,10 +163,10 @@
int __init init_mini_module(void)
{
-#if 1
- ec_slave_t *slave;
-#endif
-
+#ifdef MAPPING
+ ec_slave_config_t *sc;
+#endif
+
printk(KERN_INFO PFX "Starting...\n");
if (!(master = ecrt_request_master(0))) {
@@ -177,49 +182,25 @@
goto out_release_master;
}
-#if 1
- printk(KERN_INFO PFX "Configuring alternative PDO mapping...\n");
- if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5101)))
- goto out_release_master;
-
- if (ecrt_slave_pdo_mapping(slave, EC_DIR_INPUT, 2, 0x1A00, 0x1A02))
- goto out_release_master;
-#endif
-
- printk(KERN_INFO PFX "Registering PDOs...\n");
-#if 1
- if (ecrt_domain_register_pdo_list(domain1, domain1_pdo_regs)) {
- printk(KERN_ERR PFX "PDO registration failed!\n");
- goto out_release_master;
- }
-#endif
-
-#ifdef KBUS
- if (!(slave = ecrt_master_get_slave(master, "0", Beckhoff_BK1120)))
- goto out_release_master;
-
- if (!ecrt_domain_register_pdo_range(
- domain1, slave, EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
- printk(KERN_ERR PFX "PDO registration failed!\n");
- goto out_release_master;
- }
-
- if (!ecrt_domain_register_pdo_range(
- domain1, slave, EC_DIR_INPUT, 0, 4, &r_inputs)) {
- printk(KERN_ERR PFX "PDO registration failed!\n");
- goto out_release_master;
- }
-#endif
-
-#if 0
- if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5001)))
- goto out_release_master;
-
- if (ecrt_slave_conf_sdo8(slave, 0x4061, 1, 0))
- goto out_release_master;
-#endif
-
-#if 1
+#ifdef MAPPING
+ printk(KERN_INFO PFX "Configuring Pdo mapping...\n");
+ if (!(sc = ecrt_master_slave_config(master, 0, 1, Beckhoff_EL3162))) {
+ printk(KERN_ERR PFX "Failed to get slave configuration.\n");
+ goto out_release_master;
+ }
+
+ if (ecrt_slave_config_mapping(sc, 2, mapping)) {
+ printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n");
+ goto out_release_master;
+ }
+#endif
+
+ printk(KERN_INFO PFX "Registering PDO entries...\n");
+#ifdef PDOS
+ if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
+ printk(KERN_ERR PFX "PDO entry registration failed!\n");
+ goto out_release_master;
+ }
#endif
printk(KERN_INFO PFX "Activating master...\n");
--- a/include/ecrt.h Thu Feb 14 09:18:55 2008 +0000
+++ b/include/ecrt.h Tue Feb 19 08:22:20 2008 +0000
@@ -41,6 +41,44 @@
* 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 (alias/position, slave configurations).
+ * - 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_memory().
+ * - Replaced the process data pointers in the Pdo entry registration
+ * functions with a process data offset, that is now returned by
+ * ecrt_domain_reg_pdo_entry(). This was necessary for the external
+ * domain memory. An additional advantage is, that the returned offset value
+ * is directly usable.
+ * - Replaced ecrt_slave_pdo_mapping/add/clear() with
+ * ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
+ * Pdo configuration. Pdo entries mapped in this way can now immediately be
+ * registered. The Pdo mapping and the configuration are described with the
+ * new data types ec_pdo_info_t and ec_pdo_entry_info_t.
+ * - 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().
+ * - 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_domain_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.
+ *
+ * @{
*/
/*****************************************************************************/
@@ -83,127 +121,422 @@
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 */
-struct ec_slave;
-typedef struct ec_slave ec_slave_t; /**< \see ec_slave */
-
-/*****************************************************************************/
-
-/** Bus status.
- * This is used in ec_master_status_t.
+/*****************************************************************************/
+
+/** Bus state.
+ *
+ * This is used in ec_master_state_t.
*/
typedef enum {
- 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;
-
-/*****************************************************************************/
-
-/** Master status.
- * This is used for the output parameter of ecrt_master_get_status().
+ 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_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 responding slaves */
-}
-ec_master_status_t;
-
-/*****************************************************************************/
-
-/** List entry for domain PDO registrations.
- * This type is used as a parameter for the ecrt_domain_register_pdo_list()
- * convenience function.
+ 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;
+
+/*****************************************************************************/
+
+/** 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 {
- 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 */
- uint8_t pdo_entry_subindex; /**< PDO entry subindex */
- void **data_ptr; /**< address of the process data pointer */
-}
-ec_pdo_reg_t;
-
-/*****************************************************************************/
-
-/** Direction type for PDO mapping and range registration functions.
+ 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 {
- EC_DIR_OUTPUT, /**< values written by master */
- EC_DIR_INPUT /**< values read by master */
-}
-ec_direction_t;
+ 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 list. */
+} 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. */
+ uint8_t *offset; /**< Pointer to a variable to store the Pdo's
+ offset in the process data. */
+} ec_pdo_entry_reg_t;
/******************************************************************************
* Global functions
*****************************************************************************/
-ec_master_t *ecrt_request_master(unsigned int master_index);
-void ecrt_release_master(ec_master_t *master);
-
+/** 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 */
+ );
+
/******************************************************************************
* Master methods
*****************************************************************************/
-void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
- void (*release_cb)(void *), void *cb_data);
-
-ec_domain_t *ecrt_master_create_domain(ec_master_t *master);
-
-ec_slave_t *ecrt_master_get_slave(const ec_master_t *master,
- const char *address, uint32_t vendor_id, uint32_t product_code);
-ec_slave_t *ecrt_master_get_slave_by_pos(const ec_master_t *master,
- uint16_t position, 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);
-
-void ecrt_master_get_status(const ec_master_t *master, ec_master_status_t *s);
+/** 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
+ *****************************************************************************/
+
+/** Specify the Pdo mapping and (optionally) the Pdo configuration.
+ *
+ * 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_info_t complete_mapping[] = {
+ * {EC_DIR_INPUT, 0x1600, 2, { // channel 1
+ * {0x7000, 0, 16}, // value
+ * {0x7000, 1, 8}, // status
+ * }},
+ * {EC_DIR_INPUT, 0x1601, 2, { // channel 2
+ * {0x7001, 0, 16}, // value
+ * {0x7001, 1, 8}, // status
+ * }}
+ * };
+ *
+ * if (ecrt_slave_config_mapping(slave_config_ana_in, 2, complete_mapping)) {
+ * // 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 no Pdo configuration is
+ * specified 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)) {
+ * // error
+ * }
+ * \endcode
+ *
+ * \return zero on success, else non-zero
+ */
+int ecrt_slave_config_mapping(
+ ec_slave_config_t *sc, /**< Slave configuration. */
+ unsigned int n_entries, /**< Number of Pdos in \a pdos to map. */
+ const ec_pdo_info_t pdos[] /**< List with Pdo mapping. */
+ );
+
+/** 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. */
+ );
/******************************************************************************
* Domain methods
*****************************************************************************/
-int ecrt_domain_register_pdo(ec_domain_t *domain, ec_slave_t *slave,
- uint16_t pdo_entry_index, uint8_t pdo_entry_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);
-
-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);
-
-/******************************************************************************
- * Slave methods
- *****************************************************************************/
-
-int ecrt_slave_conf_sdo8(ec_slave_t *slave, uint16_t sdo_index,
- uint8_t sdo_subindex, uint8_t value);
-int ecrt_slave_conf_sdo16(ec_slave_t *slave, uint16_t sdo_index,
- uint8_t sdo_subindex, uint16_t value);
-int ecrt_slave_conf_sdo32(ec_slave_t *slave, uint16_t sdo_index,
- uint8_t sdo_subindex, uint32_t value);
-
-void ecrt_slave_pdo_mapping_clear(ec_slave_t *, ec_direction_t);
-int ecrt_slave_pdo_mapping_add(ec_slave_t *, ec_direction_t, uint16_t);
-int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...);
+/** Registers a single Pdo entry for a domain.
+ *
+ * \return On success, the function returns the offset in the domain's process
+ * data, which can be zero or greater. On failure, it returns a value
+ * less than zero.
+ */
+
+int ecrt_domain_reg_pdo_entry(
+ ec_domain_t *domain, /**< Domain. */
+ 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. */
+ );
+
+/** 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 memory to store the domain's process data.
+ *
+ * Call this after all Pdo entries have been registered. Since interface
+ * version 1.4, you'll have to provide an external memory for the domain
+ * process data.
+ *
+ * The size of the allocated memory must be at least the return value of
+ * ecrt_domain_size(), after all Pdo entries have been registered.
+ */
+void ecrt_domain_memory(
+ ec_domain_t *domain, /**< Domain. */
+ uint8_t *memory /**< Address of the memory to store the process
+ data in. */
+ );
+
+/** 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. */
+ );
/******************************************************************************
* Bitwise read/write macros
@@ -324,4 +657,6 @@
/*****************************************************************************/
+/** @} */
+
#endif
--- a/master/Kbuild.in Thu Feb 14 09:18:55 2008 +0000
+++ b/master/Kbuild.in Tue Feb 19 08:22:20 2008 +0000
@@ -33,9 +33,10 @@
obj-m := ec_master.o
-ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu.o slave.o \
- datagram.o domain.o mailbox.o canopen.o fsm_sii.o fsm_change.o \
- fsm_coe.o fsm_coe_map.o fsm_mapping.o fsm_slave.o fsm_master.o xmldev.o
+ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu_config.o \
+ slave.o slave_config.o pdo_mapping.o datagram.o domain.o mailbox.o \
+ canopen.o fsm_sii.o fsm_change.o fsm_coe.o fsm_coe_map.o fsm_mapping.o \
+ fsm_slave.o fsm_master.o xmldev.o
ifeq (@ENABLE_EOE@,1)
ec_master-objs += ethernet.o
--- a/master/Makefile.am Thu Feb 14 09:18:55 2008 +0000
+++ b/master/Makefile.am Tue Feb 19 08:22:20 2008 +0000
@@ -39,7 +39,7 @@
device.c device.h \
pdo.c pdo.h \
sync.c sync.h \
- fmmu.c fmmu.h \
+ fmmu_config.c fmmu_config.h \
domain.c domain.h \
doxygen.c \
ethernet.c ethernet.h \
@@ -55,6 +55,8 @@
master.c master.h \
module.c \
slave.c slave.h \
+ slave_config.c slave_config.h \
+ pdo_mapping.c pdo_mapping.h \
xmldev.c xmldev.h
modules:
--- a/master/domain.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/domain.c Tue Feb 19 08:22:20 2008 +0000
@@ -41,29 +41,14 @@
#include <linux/module.h>
#include "globals.h"
+#include "master.h"
+#include "slave_config.h"
+
#include "domain.h"
-#include "master.h"
-
-/*****************************************************************************/
-
-/**
- Data registration type.
-*/
-
-typedef struct
-{
- struct list_head list; /**< list item */
- ec_slave_t *slave; /**< slave */
- const ec_sync_t *sync; /**< sync manager */
- off_t sync_offset; /**< pdo offset */
- void **data_ptr; /**< pointer to process data pointer(s) */
-}
-ec_data_reg_t;
/*****************************************************************************/
void ec_domain_clear(struct kobject *);
-void ec_domain_clear_data_regs(ec_domain_t *);
ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
/*****************************************************************************/
@@ -92,25 +77,24 @@
/*****************************************************************************/
-/**
- Domain constructor.
- \return 0 in case of success, else < 0
-*/
-
-int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */
- ec_master_t *master, /**< owning master */
- unsigned int index /**< domain index */
- )
+/** Domain constructor.
+ *
+ * \return 0 in case of success, else < 0
+ */
+int ec_domain_init(
+ ec_domain_t *domain, /**< EtherCAT domain. */
+ ec_master_t *master, /**< Parent master. */
+ unsigned int index /**< Index. */
+ )
{
domain->master = master;
domain->index = index;
domain->data_size = 0;
domain->base_address = 0;
- domain->response_count = 0xFFFFFFFF;
+ domain->working_counter = 0xFFFFFFFF;
domain->notify_jiffies = 0;
domain->working_counter_changes = 0;
- INIT_LIST_HEAD(&domain->data_regs);
INIT_LIST_HEAD(&domain->datagrams);
// init kobject and add it to the hierarchy
@@ -164,8 +148,8 @@
void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
{
+ ec_domain_t *domain;
ec_datagram_t *datagram, *next;
- ec_domain_t *domain;
domain = container_of(kobj, ec_domain_t, kobj);
@@ -174,91 +158,21 @@
kfree(datagram);
}
- ec_domain_clear_data_regs(domain);
-
kfree(domain);
}
/*****************************************************************************/
-/**
- * Registers a PDO entry.
+/** Allocates a domain datagram and appends it to the list.
+ *
* \return 0 in case of success, else < 0
*/
-
-int ec_domain_reg_pdo_entry(
- ec_domain_t *domain, /**< EtherCAT domain */
- ec_sync_t *sync, /**< sync manager */
- const ec_pdo_entry_t *entry, /**< PDO entry to register */
- void **data_ptr /**< pointer to the process data pointer */
+int ec_domain_add_datagram(
+ ec_domain_t *domain, /**< EtherCAT domain. */
+ uint32_t offset, /**< Logical offset. */
+ size_t data_size /**< Size of the data. */
)
{
- ec_data_reg_t *data_reg;
- const ec_pdo_t *other_pdo;
- const ec_pdo_entry_t *other_entry;
- unsigned int bit_offset, byte_offset;
-
- // Calculate offset (in sync manager) for process data pointer
- bit_offset = 0;
- list_for_each_entry(other_pdo, &sync->pdos, list) {
- list_for_each_entry(other_entry, &other_pdo->entries, list) {
- if (other_entry == entry)
- goto out;
- bit_offset += other_entry->bit_length;
- }
- }
-out:
- byte_offset = bit_offset / 8;
-
- // 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(sync->slave, domain, sync)) {
- EC_ERR("FMMU configuration failed.\n");
- kfree(data_reg);
- return -1;
- }
-
- data_reg->slave = sync->slave;
- data_reg->sync = sync;
- data_reg->sync_offset = byte_offset;
- data_reg->data_ptr = data_ptr;
- list_add_tail(&data_reg->list, &domain->data_regs);
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Clears the list of the data registrations.
-*/
-
-void ec_domain_clear_data_regs(ec_domain_t *domain /**< EtherCAT domain */)
-{
- ec_data_reg_t *data_reg, *next;
-
- list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) {
- list_del(&data_reg->list);
- kfree(data_reg);
- }
-}
-
-/*****************************************************************************/
-
-/**
- Allocates a process data datagram and appends it to the list.
- \return 0 in case of success, else < 0
-*/
-
-int ec_domain_add_datagram(ec_domain_t *domain, /**< EtherCAT domain */
- uint32_t offset, /**< logical offset */
- size_t data_size /**< size of the datagram data */
- )
-{
ec_datagram_t *datagram;
if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
@@ -281,50 +195,47 @@
/*****************************************************************************/
-/**
- Creates a domain.
- Reserves domain memory, calculates the logical addresses of the
- corresponding FMMUs and sets the process data pointer of the registered
- process data.
- \return 0 in case of success, else < 0
-*/
-
-int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
- uint32_t base_address /**< logical base address */
- )
-{
- ec_data_reg_t *data_reg;
- ec_slave_t *slave;
- ec_fmmu_t *fmmu;
- unsigned int i, j, datagram_count;
- uint32_t pdo_off, pdo_off_datagram;
- uint32_t datagram_offset, log_addr;
- size_t datagram_data_size, sync_size;
- ec_datagram_t *datagram;
+/** Finishes a domain.
+ *
+ * This allocates the necessary datagrams and writes the correct logical
+ * addresses to every configured FMMU.
+ *
+ * \retval 0 in case of success
+ * \retval <0 on failure.
+ */
+int ec_domain_finish(
+ ec_domain_t *domain, /**< EtherCAT domain. */
+ uint32_t base_address /**< Logical base address. */
+ )
+{
+ uint32_t datagram_offset;
+ size_t datagram_data_size;
+ unsigned int datagram_count, i;
+ ec_slave_config_t *sc;
+ ec_fmmu_config_t *fmmu;
domain->base_address = base_address;
- // calculate size of process data and allocate memory
- domain->data_size = 0;
+ // Cycle through all domain FMMUS, add the logical base address and assign
+ // as many PDO entries as possible to the datagrams.
datagram_offset = base_address;
datagram_data_size = 0;
datagram_count = 0;
- list_for_each_entry(slave, &domain->master->slaves, list) {
- for (j = 0; j < slave->fmmu_count; j++) {
- fmmu = &slave->fmmus[j];
- if (fmmu->domain == domain) {
- fmmu->logical_start_address = base_address + domain->data_size;
- sync_size = ec_sync_size(fmmu->sync);
- domain->data_size += sync_size;
- if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) {
- if (ec_domain_add_datagram(domain, datagram_offset,
- datagram_data_size)) return -1;
- datagram_offset += datagram_data_size;
- datagram_data_size = 0;
- datagram_count++;
- }
- datagram_data_size += sync_size;
+ list_for_each_entry(sc, &domain->master->configs, list) {
+ for (i = 0; i < sc->used_fmmus; i++) {
+ fmmu = &sc->fmmu_configs[i];
+ if (fmmu->domain != domain)
+ continue;
+
+ fmmu->logical_start_address += base_address;
+ if (datagram_data_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
+ if (ec_domain_add_datagram(domain, datagram_offset,
+ datagram_data_size)) return -1;
+ datagram_offset += datagram_data_size;
+ datagram_data_size = 0;
+ datagram_count++;
}
+ datagram_data_size += fmmu->data_size;
}
}
@@ -336,41 +247,9 @@
datagram_count++;
}
- if (datagram_count) {
- // set all process data pointers
- list_for_each_entry(data_reg, &domain->data_regs, list) {
- for (i = 0; i < data_reg->slave->fmmu_count; i++) {
- fmmu = &data_reg->slave->fmmus[i];
- if (fmmu->domain == domain && fmmu->sync == data_reg->sync) {
- pdo_off =
- fmmu->logical_start_address + data_reg->sync_offset;
- // search datagram
- list_for_each_entry(datagram, &domain->datagrams, list) {
- log_addr = EC_READ_U32(datagram->address);
- pdo_off_datagram = pdo_off - log_addr;
- if (pdo_off >= log_addr &&
- pdo_off_datagram < datagram->mem_size) {
- *data_reg->data_ptr = datagram->data +
- pdo_off_datagram;
- }
- }
- if (!data_reg->data_ptr) {
- EC_ERR("Failed to assign data pointer!\n");
- return -1;
- }
- break;
- }
- }
- }
-
- EC_INFO("Domain %u - Allocated %u bytes in %u datagram%s.\n",
- domain->index, domain->data_size, datagram_count,
- datagram_count == 1 ? "" : "s");
- } else { // !datagram_count
- EC_WARN("Domain %u contains no data!\n", domain->index);
- }
-
- ec_domain_clear_data_regs(domain);
+ EC_INFO("Domain %u with logical offset %u contains %u bytes in %u"
+ " datagram%s.\n", domain->index, domain->base_address,
+ domain->data_size, datagram_count, datagram_count == 1 ? "" : "s");
return 0;
}
@@ -399,143 +278,39 @@
* Realtime interface
*****************************************************************************/
-/**
- * Registers a PDO for a domain.
- * \return 0 on success, else non-zero
- * \ingroup RealtimeInterface
- */
-
-int ecrt_domain_register_pdo(
- ec_domain_t *domain, /**< EtherCAT domain */
- 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_sync_t *sync;
- const ec_pdo_t *pdo;
- const ec_pdo_entry_t *entry;
- unsigned int i;
-
- // 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 != pdo_entry_index ||
- entry->subindex != pdo_entry_subindex) continue;
- // PDO entry found
- if (ec_domain_reg_pdo_entry(domain, sync, entry, data_ptr)) {
- return -1;
- }
- return 0;
- }
- }
- }
-
- EC_ERR("PDO entry 0x%04X:%u is not mapped in slave %u.\n",
- pdo_entry_index, pdo_entry_subindex, slave->ring_position);
- return -1;
-}
-
-/*****************************************************************************/
-
-/**
- * Registers a bunch of data fields.
- * \attention The list has to be terminated with a NULL structure ({})!
- * \return 0 in case of success, else < 0
- * \ingroup RealtimeInterface
- */
-
-int ecrt_domain_register_pdo_list(
- ec_domain_t *domain, /**< EtherCAT domain */
- const ec_pdo_reg_t *pdo_regs /**< array of PDO registrations */
- )
-{
- const ec_pdo_reg_t *reg;
- ec_slave_t *slave;
+int ecrt_domain_reg_pdo_entry(ec_domain_t *domain, ec_slave_config_t *sc,
+ uint16_t index, uint8_t subindex)
+{
+ return ec_slave_config_reg_pdo_entry(sc, domain, index, subindex);
+}
+
+/*****************************************************************************/
+
+int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
+ const ec_pdo_entry_reg_t *regs)
+{
+ const ec_pdo_entry_reg_t *reg;
+ ec_slave_config_t *sc;
+ int ret;
- 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)))
+ for (reg = regs; reg->index; reg++) {
+ if (!(sc = ecrt_master_slave_config(domain->master, reg->alias,
+ reg->position, 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))
+ if ((ret = ecrt_domain_reg_pdo_entry(domain, sc, reg->index,
+ reg->subindex)) < 0)
return -1;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * 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 %u of slave %u to %u.\n",
- sync->index, slave->ring_position, sync_length);
- }
- }
-
- list_add_tail(&data_reg->list, &domain->data_regs);
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Processes received process data and requeues the domain datagram(s).
- \ingroup RealtimeInterface
-*/
-
-void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */)
+
+ *reg->offset = ret;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+void ecrt_domain_process(ec_domain_t *domain)
{
unsigned int working_counter_sum;
ec_datagram_t *datagram;
@@ -552,9 +327,9 @@
}
}
- if (working_counter_sum != domain->response_count) {
+ if (working_counter_sum != domain->working_counter) {
domain->working_counter_changes++;
- domain->response_count = working_counter_sum;
+ domain->working_counter = working_counter_sum;
}
if (domain->working_counter_changes &&
@@ -562,12 +337,12 @@
domain->notify_jiffies = jiffies;
if (domain->working_counter_changes == 1) {
EC_INFO("Domain %u working counter change: %u\n", domain->index,
- domain->response_count);
+ domain->working_counter);
}
else {
- EC_INFO("Domain %u: %u WC changes. Current response count: %u\n",
+ EC_INFO("Domain %u: %u working counter changes. Currently %u\n",
domain->index, domain->working_counter_changes,
- domain->response_count);
+ domain->working_counter);
}
domain->working_counter_changes = 0;
}
@@ -575,12 +350,7 @@
/*****************************************************************************/
-/**
- Places all process data datagrams in the masters datagram queue.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
+void ecrt_domain_queue(ec_domain_t *domain)
{
ec_datagram_t *datagram;
@@ -591,24 +361,20 @@
/*****************************************************************************/
-/**
- Returns the state of a domain.
- \return 0 if all datagrams were received, else -1.
- \ingroup RealtimeInterface
-*/
-
-int ecrt_domain_state(const ec_domain_t *domain /**< EtherCAT domain */)
-{
- return domain->state;
+void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
+{
+ state->working_counter = domain->working_counter;
+ state->wc_state = EC_WC_ZERO; // FIXME
}
/*****************************************************************************/
/** \cond */
-EXPORT_SYMBOL(ecrt_domain_register_pdo);
-EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
-EXPORT_SYMBOL(ecrt_domain_register_pdo_range);
+EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry);
+EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry_list);
+//EXPORT_SYMBOL(ecrt_domain_size);
+//EXPORT_SYMBOL(ecrt_domain_memory);
EXPORT_SYMBOL(ecrt_domain_process);
EXPORT_SYMBOL(ecrt_domain_queue);
EXPORT_SYMBOL(ecrt_domain_state);
--- a/master/domain.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/domain.h Tue Feb 19 08:22:20 2008 +0000
@@ -58,19 +58,18 @@
struct ec_domain
{
- struct kobject kobj; /**< kobject */
- struct list_head list; /**< list item */
- unsigned int index; /**< domain index (just a number) */
- ec_master_t *master; /**< EtherCAT master owning the domain */
- size_t data_size; /**< size of the process data */
- struct list_head datagrams; /**< process data datagrams */
- uint32_t base_address; /**< logical offset address of the process data */
- unsigned int response_count; /**< number of responding slaves */
- unsigned int state; /**< domain error state */
- struct list_head data_regs; /**< PDO data registrations */
- unsigned int working_counter_changes; /**< working counter changes
- since last notification */
- unsigned long notify_jiffies; /**< time of last notification */
+ struct kobject kobj; /**< kobject. */
+ struct list_head list; /**< List item. */
+ unsigned int index; /**< Index (just a number). */
+ ec_master_t *master; /**< EtherCAT master owning the domain. */
+ size_t data_size; /**< Size of the process data. */
+ struct list_head datagrams; /**< Datagrams for process data exchange. */
+ uint32_t base_address; /**< Logical offset address of the process data. */
+ unsigned int working_counter; /**< Last working counter value. */
+ unsigned int state; /**< Error state. */
+ unsigned int working_counter_changes; /**< Working counter changes
+ since last notification. */
+ unsigned long notify_jiffies; /**< Time of last notification. */
};
/*****************************************************************************/
@@ -78,7 +77,7 @@
int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
void ec_domain_destroy(ec_domain_t *);
-int ec_domain_alloc(ec_domain_t *, uint32_t);
+int ec_domain_finish(ec_domain_t *, uint32_t);
/*****************************************************************************/
--- a/master/fmmu.c Thu Feb 14 09:18:55 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/******************************************************************************
- *
- * $Id$
- *
- * 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 FMMU methods.
-*/
-
-/*****************************************************************************/
-
-#include "globals.h"
-#include "slave.h"
-#include "master.h"
-#include "fmmu.h"
-
-/*****************************************************************************/
-
-/**
- * FMMU Constructor.
- */
-
-void ec_fmmu_init(
- ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
- ec_slave_t *slave, /**< EtherCAT slave */
- unsigned int index /**< FMMU index */
- )
-{
- fmmu->slave = slave;
- fmmu->index = index;
-}
-
-/*****************************************************************************/
-
-/**
- * Initializes an FMMU configuration page.
- * The referenced memory (\a data) must be at least EC_FMMU_SIZE bytes.
- */
-
-void ec_fmmu_config(
- const ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
- uint8_t *data /**> configuration memory */
- )
-{
- size_t sync_size = ec_sync_size(fmmu->sync);
-
- if (fmmu->slave->master->debug_level) {
- EC_DBG("FMMU%u: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
- fmmu->index, fmmu->logical_start_address,
- sync_size, fmmu->sync->physical_start_address,
- ((fmmu->sync->control_register & 0x04) ? "out" : "in"));
- }
-
- EC_WRITE_U32(data, fmmu->logical_start_address);
- EC_WRITE_U16(data + 4, sync_size); // size of fmmu
- EC_WRITE_U8 (data + 6, 0x00); // logical start bit
- EC_WRITE_U8 (data + 7, 0x07); // logical end bit
- EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address);
- EC_WRITE_U8 (data + 10, 0x00); // physical start bit
- EC_WRITE_U8 (data + 11, ((fmmu->sync->control_register & 0x04)
- ? 0x02 : 0x01));
- EC_WRITE_U16(data + 12, 0x0001); // enable
- EC_WRITE_U16(data + 14, 0x0000); // reserved
-}
-
-/*****************************************************************************/
--- a/master/fmmu.h Thu Feb 14 09:18:55 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/******************************************************************************
- *
- * $Id$
- *
- * 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 FMMU structure.
-*/
-
-/*****************************************************************************/
-
-#ifndef _EC_FMMU_H_
-#define _EC_FMMU_H_
-
-#include "../include/ecrt.h"
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-/** size of an FMMU configuration page */
-#define EC_FMMU_SIZE 16
-
-/*****************************************************************************/
-
-/**
- * FMMU configuration.
- */
-
-typedef struct
-{
- const ec_slave_t *slave; /**< EtherCAT slave, the FMMU belongs to */
- unsigned int index; /**< FMMU index */
- const ec_domain_t *domain; /**< domain */
- const ec_sync_t *sync; /**< sync manager */
- uint32_t logical_start_address; /**< logical start address */
-}
-ec_fmmu_t;
-
-/*****************************************************************************/
-
-void ec_fmmu_init(ec_fmmu_t *, ec_slave_t *, unsigned int);
-
-void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
-
-/*****************************************************************************/
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fmmu_config.c Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 FMMU configuration methods.
+ */
+
+/*****************************************************************************/
+
+#include "globals.h"
+#include "slave_config.h"
+#include "master.h"
+
+#include "fmmu_config.h"
+
+/*****************************************************************************/
+
+/** FMMU configuration constructor.
+ *
+ * Inits an FMMU configuration, sets the logical start address and adds the
+ * process data size for the mapped PDOs of the given direction to the domain
+ * data size.
+ */
+void ec_fmmu_config_init(
+ ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
+ ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
+ ec_domain_t *domain, /**< EtherCAT domain. */
+ ec_direction_t dir /**< PDO direction. */
+ )
+{
+ fmmu->sc = sc;
+ fmmu->domain = domain;
+ fmmu->dir = dir;
+
+ fmmu->logical_start_address = domain->data_size;
+ fmmu->data_size = ec_pdo_mapping_total_size(&sc->mapping[dir]);
+ domain->data_size += fmmu->data_size;
+}
+
+/*****************************************************************************/
+
+/** Initializes an FMMU configuration page.
+ *
+ * The referenced memory (\a data) must be at least EC_FMMU_PAGE_SIZE bytes.
+ */
+void ec_fmmu_config_page(
+ const ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
+ const ec_sync_t *sync, /**< Sync manager. */
+ uint8_t *data /**> Configuration page memory. */
+ )
+{
+ if (fmmu->sc->master->debug_level) {
+ EC_DBG("FMMU: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
+ fmmu->logical_start_address, fmmu->data_size,
+ sync->physical_start_address,
+ (sync->control_register & 0x04) ? "out" : "in");
+ }
+
+ EC_WRITE_U32(data, fmmu->logical_start_address);
+ EC_WRITE_U16(data + 4, fmmu->data_size); // size of fmmu
+ EC_WRITE_U8 (data + 6, 0x00); // logical start bit
+ EC_WRITE_U8 (data + 7, 0x07); // logical end bit
+ EC_WRITE_U16(data + 8, sync->physical_start_address);
+ EC_WRITE_U8 (data + 10, 0x00); // physical start bit
+ EC_WRITE_U8 (data + 11, (sync->control_register & 0x04) ? 0x02 : 0x01);
+ EC_WRITE_U16(data + 12, 0x0001); // enable
+ EC_WRITE_U16(data + 14, 0x0000); // reserved
+}
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fmmu_config.h Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 FMMU configuration structure.
+ */
+
+/*****************************************************************************/
+
+#ifndef _EC_FMMU_CONFIG_H_
+#define _EC_FMMU_CONFIG_H_
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** FMMU configuration.
+ */
+typedef struct
+{
+ const ec_slave_config_t *sc; /**< EtherCAT slave config. */
+ const ec_domain_t *domain; /**< Domain. */
+ ec_direction_t dir; /**< PDO direction. */
+
+ uint32_t logical_start_address; /**< Logical start address. */
+ unsigned int data_size; /**< Covered PDO size. */
+}
+ec_fmmu_config_t;
+
+/*****************************************************************************/
+
+void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
+ ec_domain_t *, ec_direction_t);
+
+void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
+ uint8_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/fsm_coe_map.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_coe_map.c Tue Feb 19 08:22:20 2008 +0000
@@ -59,8 +59,6 @@
void ec_fsm_coe_map_action_next_pdo(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_action_next_pdo_entry(ec_fsm_coe_map_t *);
-void ec_fsm_coe_map_clear_pdos(ec_fsm_coe_map_t *);
-
/*****************************************************************************/
/**
@@ -74,7 +72,7 @@
{
fsm->state = NULL;
fsm->fsm_coe = fsm_coe;
- INIT_LIST_HEAD(&fsm->pdos);
+ ec_pdo_mapping_init(&fsm->mapping);
}
/*****************************************************************************/
@@ -85,27 +83,7 @@
void ec_fsm_coe_map_clear(ec_fsm_coe_map_t *fsm /**< finite state machine */)
{
- ec_fsm_coe_map_clear_pdos(fsm);
-}
-
-/*****************************************************************************/
-
-/**
- * Clear FSM PDOs.
- */
-
-void ec_fsm_coe_map_clear_pdos(
- ec_fsm_coe_map_t *fsm /**< finite state machine */
- )
-{
- ec_pdo_t *pdo, *next;
-
- // free all PDOs
- list_for_each_entry_safe(pdo, next, &fsm->pdos, list) {
- list_del(&pdo->list);
- ec_pdo_clear(pdo);
- kfree(pdo);
- }
+ ec_pdo_mapping_clear(&fsm->mapping);
}
/*****************************************************************************/
@@ -188,7 +166,7 @@
EC_DBG("Reading PDO mapping of sync manager %u of slave %u.\n",
fsm->sync_index, slave->ring_position);
- ec_fsm_coe_map_clear_pdos(fsm);
+ ec_pdo_mapping_clear_pdos(&fsm->mapping);
if (!(entry = ec_sdo_get_entry(fsm->sync_sdo, 0))) {
EC_ERR("SDO 0x%04X has no subindex 0 on slave %u.\n",
@@ -269,15 +247,14 @@
{
ec_sync_t *sync = fsm->slave->sii_syncs + fsm->sync_index;
- ec_pdo_t *pdo;
-
- // exchange sync manager PDO mapping
- ec_sync_clear_pdos(sync);
- list_for_each_entry(pdo, &fsm->pdos, list) {
- ec_sync_add_pdo(sync, pdo);
- }
+
+ if (ec_pdo_mapping_copy(&sync->mapping, &fsm->mapping)) {
+ fsm->state = ec_fsm_coe_map_state_error;
+ return;
+ }
+
sync->mapping_source = EC_SYNC_MAPPING_COE;
- ec_fsm_coe_map_clear_pdos(fsm);
+ ec_pdo_mapping_clear_pdos(&fsm->mapping);
// next sync manager
fsm->sync_index++;
@@ -316,8 +293,8 @@
ec_pdo_init(fsm->pdo);
fsm->pdo->index = EC_READ_U16(fsm->request.data);
- fsm->pdo->type =
- ec_sync_get_pdo_type(fsm->slave->sii_syncs + fsm->sync_index);
+ fsm->pdo->dir =
+ ec_sync_direction(fsm->slave->sii_syncs + fsm->sync_index);
if (fsm->slave->master->debug_level)
EC_DBG(" PDO 0x%04X.\n", fsm->pdo->index);
@@ -331,19 +308,11 @@
return;
}
- if (fsm->pdo_sdo->name && strlen(fsm->pdo_sdo->name)) {
- if (!(fsm->pdo->name = (char *)
- kmalloc(strlen(fsm->pdo_sdo->name) + 1, GFP_KERNEL))) {
- EC_ERR("Failed to allocate PDO name.\n");
- ec_pdo_clear(fsm->pdo);
- kfree(fsm->pdo);
- fsm->state = ec_fsm_coe_map_state_error;
- return;
- }
- memcpy(fsm->pdo->name, fsm->pdo_sdo->name,
- strlen(fsm->pdo_sdo->name) + 1);
- } else {
- fsm->pdo->name = NULL;
+ if (ec_pdo_set_name(fsm->pdo, fsm->pdo_sdo->name)) {
+ ec_pdo_clear(fsm->pdo);
+ kfree(fsm->pdo);
+ fsm->state = ec_fsm_coe_map_state_error;
+ return;
}
if (!(entry = ec_sdo_get_entry(fsm->pdo_sdo, 0))) {
@@ -356,7 +325,7 @@
return;
}
- list_add_tail(&fsm->pdo->list, &fsm->pdos);
+ list_add_tail(&fsm->pdo->list, &fsm->mapping.pdos);
ec_sdo_request_init_read(&fsm->request, entry);
fsm->state = ec_fsm_coe_map_state_pdo_entry_count;
@@ -463,28 +432,25 @@
return;
}
+ ec_pdo_entry_init(pdo_entry);
pdo_entry->index = pdo_entry_info >> 16;
pdo_entry->subindex = (pdo_entry_info >> 8) & 0xFF;
pdo_entry->bit_length = pdo_entry_info & 0xFF;
if (!pdo_entry->index && !pdo_entry->subindex) {
- char gapname[] = "Gap";
-
// we have a gap in the PDO, next PDO entry
if (fsm->slave->master->debug_level) {
EC_DBG(" PDO entry gap: %u bit.\n",
pdo_entry->bit_length);
}
- if (!(pdo_entry->name = (char *)
- kmalloc(strlen(gapname) + 1, GFP_KERNEL))) {
- EC_ERR("Failed to allocate GAP entry name.\n");
+ if (ec_pdo_entry_set_name(pdo_entry, "Gap")) {
+ ec_pdo_entry_clear(pdo_entry);
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
- memcpy(pdo_entry->name, gapname, strlen(gapname) + 1);
list_add_tail(&pdo_entry->list, &fsm->pdo->entries);
fsm->pdo_subindex++;
ec_fsm_coe_map_action_next_pdo_entry(fsm);
@@ -494,6 +460,7 @@
if (!(sdo = ec_slave_get_sdo(fsm->slave, pdo_entry->index))) {
EC_ERR("Slave %u has no SDO 0x%04X.\n",
fsm->slave->ring_position, pdo_entry->index);
+ ec_pdo_entry_clear(pdo_entry);
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
@@ -503,27 +470,22 @@
EC_ERR("Slave %u has no SDO entry 0x%04X:%u.\n",
fsm->slave->ring_position, pdo_entry->index,
pdo_entry->subindex);
+ ec_pdo_entry_clear(pdo_entry);
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
- if (entry->description && strlen(entry->description)) {
- if (!(pdo_entry->name = (char *)
- kmalloc(strlen(entry->description) + 1, GFP_KERNEL))) {
- EC_ERR("Failed to allocate PDO entry name.\n");
- kfree(pdo_entry);
- fsm->state = ec_fsm_coe_map_state_error;
- return;
- }
- memcpy(pdo_entry->name, entry->description, strlen(entry->description) + 1);
- } else {
- pdo_entry->name = NULL;
+ if (ec_pdo_entry_set_name(pdo_entry, entry->description)) {
+ ec_pdo_entry_clear(pdo_entry);
+ kfree(pdo_entry);
+ fsm->state = ec_fsm_coe_map_state_error;
+ return;
}
if (fsm->slave->master->debug_level) {
- EC_DBG(" PDO entry 0x%04X \"%s\" (%u bit).\n",
- pdo_entry->index, pdo_entry->name ? pdo_entry->name : "???",
+ EC_DBG(" PDO entry 0x%04X \"%s\" (%u bit).\n", pdo_entry->index,
+ pdo_entry->name ? pdo_entry->name : "???",
pdo_entry->bit_length);
}
--- a/master/fsm_coe_map.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_coe_map.h Tue Feb 19 08:22:20 2008 +0000
@@ -51,8 +51,8 @@
typedef struct ec_fsm_coe_map ec_fsm_coe_map_t; /**< \see ec_fsm_coe_map */
/**
+ * \todo doc
*/
-
struct ec_fsm_coe_map
{
void (*state)(ec_fsm_coe_map_t *); /**< CoE mapping state function */
@@ -66,7 +66,7 @@
uint8_t sync_subindices; /**< number of mapped PDOs */
uint16_t sync_subindex; /**< current subindex in mapping SDO */
- struct list_head pdos; /**< list of mapped PDOs */
+ ec_pdo_mapping_t mapping; /**< Mapping to apply. */
ec_pdo_t *pdo; /**< current PDO */
ec_sdo_t *pdo_sdo; /**< current PDO SDO */
uint8_t pdo_subindices; /**< number of PDO entries */
--- a/master/fsm_mapping.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_mapping.c Tue Feb 19 08:22:20 2008 +0000
@@ -31,16 +31,17 @@
*
*****************************************************************************/
-/**
- \file
- EtherCAT PDO mapping state machine.
-*/
+/** \file
+ * EtherCAT PDO mapping state machine.
+ */
/*****************************************************************************/
#include "globals.h"
#include "master.h"
#include "mailbox.h"
+#include "slave_config.h"
+
#include "fsm_mapping.h"
/*****************************************************************************/
@@ -56,11 +57,10 @@
/*****************************************************************************/
-/**
- * Constructor.
- */
-
-void ec_fsm_mapping_init(ec_fsm_mapping_t *fsm, /**< mapping state machine */
+/** Constructor.
+ */
+void ec_fsm_mapping_init(
+ ec_fsm_mapping_t *fsm, /**< mapping state machine */
ec_fsm_coe_t *fsm_coe /**< CoE state machine to use */
)
{
@@ -70,20 +70,18 @@
/*****************************************************************************/
-/**
- * Destructor.
- */
-
-void ec_fsm_mapping_clear(ec_fsm_mapping_t *fsm /**< mapping state machine */)
-{
-}
-
-/*****************************************************************************/
-
-/**
- * Start PDO mapping configuration state machine.
- */
-
+/** Destructor.
+ */
+void ec_fsm_mapping_clear(
+ ec_fsm_mapping_t *fsm /**< mapping state machine */
+ )
+{
+}
+
+/*****************************************************************************/
+
+/** Start PDO mapping configuration state machine.
+ */
void ec_fsm_mapping_start(
ec_fsm_mapping_t *fsm, /**< mapping state machine */
ec_slave_t *slave /**< slave to configure */
@@ -95,10 +93,10 @@
/*****************************************************************************/
-/**
+/** Get running state.
+ *
* \return false, if state machine has terminated
*/
-
int ec_fsm_mapping_running(
const ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -109,13 +107,13 @@
/*****************************************************************************/
-/**
- * Executes the current state of the state machine.
+/** Executes the current state of the state machine.
+ *
* If the state machine's datagram is not sent or received yet, the execution
* of the state machine is delayed to the next cycle.
+ *
* \return false, if state machine has terminated
*/
-
int ec_fsm_mapping_exec(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -126,10 +124,10 @@
/*****************************************************************************/
-/**
+/** Get execution result.
+ *
* \return true, if the state machine terminated gracefully
*/
-
int ec_fsm_mapping_success(
const ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -138,27 +136,28 @@
}
/******************************************************************************
- * state functions
+ * State functions.
*****************************************************************************/
-/**
- * Start mapping configuration.
- */
-
+/** Start mapping configuration.
+ */
void ec_fsm_mapping_state_start(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
{
+ if (!fsm->slave->config) {
+ fsm->state = ec_fsm_mapping_state_end;
+ return;
+ }
+
fsm->dir = EC_DIR_OUTPUT;
ec_fsm_mapping_next_sync(fsm);
}
/*****************************************************************************/
-/**
- * Process mapping of next sync manager.
- */
-
+/** Process mapping of next sync manager.
+ */
void ec_fsm_mapping_next_sync(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -171,18 +170,25 @@
}
if (!(fsm->sync = ec_slave_get_pdo_sync(fsm->slave, fsm->dir))) {
- // no sync manager found for this direction
+ EC_WARN("next_sync(): No sync manager!\n");
fsm->dir++;
continue;
}
- fsm->dir++;
- if (fsm->sync->alt_mapping)
+ fsm->mapping = &fsm->slave->config->mapping[fsm->dir];
+
+ if (ec_pdo_mapping_equal(&fsm->sync->mapping, fsm->mapping)) {
+ // the mapping for this direction does not have to be altered
+ fsm->dir++;
+ continue;
+ } else {
+ fsm->dir++;
break;
+ }
}
if (fsm->slave->master->debug_level) {
- EC_DBG("Configuring PDO mapping for SM%u of slave %i.\n",
+ EC_DBG("Configuring PDO mapping for SM%u of slave %u.\n",
fsm->sync->index, fsm->slave->ring_position);
}
@@ -201,34 +207,23 @@
/*****************************************************************************/
-/**
- * Process mapping of next PDO.
- */
-
+/** Process mapping of next PDO.
+ */
ec_pdo_t *ec_fsm_mapping_next_pdo(
- ec_fsm_mapping_t *fsm, /**< mapping state machine */
- struct list_head *list /**< current PDO list item */
- )
-{
- ec_pdo_t *pdo;
-
- do {
- list = list->next;
- if (list == &fsm->sync->pdos)
- return NULL; // no next PDO
- pdo = list_entry(list, ec_pdo_t, list);
- }
- while (pdo->sync_index != fsm->sync->index);
-
- return pdo;
-}
-
-/*****************************************************************************/
-
-/**
- * Set the number of mapped PDOs to zero.
- */
-
+ const ec_fsm_mapping_t *fsm, /**< mapping state machine */
+ const struct list_head *list /**< current PDO list item */
+ )
+{
+ list = list->next;
+ if (list == &fsm->mapping->pdos)
+ return NULL; // no next PDO
+ return list_entry(list, ec_pdo_t, list);
+}
+
+/*****************************************************************************/
+
+/** Set the number of mapped PDOs to zero.
+ */
void ec_fsm_mapping_state_zero_count(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -245,8 +240,7 @@
// map all PDOs belonging to the current sync manager
// find first PDO
- if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
- fsm, &fsm->sync->pdos))) {
+ if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->mapping->pdos))) {
if (fsm->slave->master->debug_level)
EC_DBG("No PDOs to map for SM%u of slave %u.\n",
fsm->sync->index, fsm->slave->ring_position);
@@ -271,10 +265,8 @@
/*****************************************************************************/
-/**
- * Add a PDO to the sync managers mapping.
- */
-
+/** Add a PDO to the sync managers mapping.
+ */
void ec_fsm_mapping_state_add_pdo(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -289,8 +281,7 @@
}
// find next PDO
- if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
- fsm, &fsm->pdo->list))) {
+ if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->pdo->list))) {
// no more PDOs to map. write PDO count
fsm->sdodata.subindex = 0;
EC_WRITE_U8(&fsm->sdo_value, fsm->pdo_count);
@@ -322,10 +313,8 @@
/*****************************************************************************/
-/**
- * Set the number of mapped PDOs.
- */
-
+/** Set the number of mapped PDOs.
+ */
void ec_fsm_mapping_state_pdo_count(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -351,10 +340,8 @@
* Common state functions
*****************************************************************************/
-/**
- State: ERROR.
-*/
-
+/** State: ERROR.
+ */
void ec_fsm_mapping_state_error(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
@@ -363,10 +350,8 @@
/*****************************************************************************/
-/**
- State: END.
-*/
-
+/** State: END.
+ */
void ec_fsm_mapping_state_end(
ec_fsm_mapping_t *fsm /**< mapping state machine */
)
--- a/master/fsm_mapping.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_mapping.h Tue Feb 19 08:22:20 2008 +0000
@@ -63,6 +63,7 @@
ec_direction_t dir; /**< current PDO direction */
ec_sync_t *sync; /**< current sync manager */
+ const ec_pdo_mapping_t *mapping; /**< Mapping to assign. */
ec_pdo_t *pdo; /**< current PDO */
ec_sdo_data_t sdodata; /**< SDO configuration data */
uint16_t sdo_value; /**< SDO value */
--- a/master/fsm_master.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_master.c Tue Feb 19 08:22:20 2008 +0000
@@ -205,7 +205,7 @@
fsm->topology_change_pending = 1;
fsm->slaves_responding = datagram->working_counter;
- EC_INFO("%i slave%s responding.\n",
+ EC_INFO("%u slave%s responding.\n",
fsm->slaves_responding,
fsm->slaves_responding == 1 ? "" : "s");
@@ -483,12 +483,11 @@
down(&master->config_sem);
if (!master->allow_config) {
up(&master->config_sem);
- }
- else {
+ } else {
master->config_state = EC_REQUEST_IN_PROGRESS;
fsm->config_error = 0;
up(&master->config_sem);
-
+
// check for pending slave configurations
if (ec_fsm_master_action_configure(fsm))
return;
@@ -911,6 +910,9 @@
EC_INFO("Bus scanning completed in %u ms.\n",
(u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ);
+ // Attach slave configurations
+ ec_master_attach_slave_configs(master);
+
#ifdef EC_EOE
// check if EoE processing has to be started
ec_master_eoe_start(master);
--- a/master/fsm_master.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_master.h Tue Feb 19 08:22:20 2008 +0000
@@ -44,7 +44,7 @@
#include "globals.h"
#include "../include/ecrt.h"
#include "datagram.h"
-#include "slave.h"
+//#include "slave.h"
#include "canopen.h"
#include "fsm_slave.h"
--- a/master/fsm_slave.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_slave.c Tue Feb 19 08:22:20 2008 +0000
@@ -41,8 +41,9 @@
#include "globals.h"
#include "master.h"
#include "mailbox.h"
+#include "fsm_mapping.h"
+#include "slave_config.h"
#include "fsm_slave.h"
-#include "fsm_mapping.h"
/*****************************************************************************/
@@ -569,12 +570,12 @@
break;
case 0x0032:
if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
- cat_size * 2, EC_TX_PDO))
+ cat_size * 2, EC_DIR_INPUT)) // TxPdo
goto end;
break;
case 0x0033:
if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
- cat_size * 2, EC_RX_PDO))
+ cat_size * 2, EC_DIR_OUTPUT)) // RxPdo
goto end;
break;
default:
@@ -662,8 +663,8 @@
// clear FMMU configurations
ec_datagram_npwr(datagram, slave->station_address,
- 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
- memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
+ 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+ memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_conf_state_clear_fmmus;
}
@@ -729,7 +730,7 @@
if (!slave->sii_mailbox_protocols) {
// no mailbox protocols supported
if (master->debug_level)
- EC_DBG("Slave %i does not support mailbox communication.\n",
+ EC_DBG("Slave %u does not support mailbox communication.\n",
slave->ring_position);
ec_fsm_slave_conf_enter_preop(fsm);
return;
@@ -740,41 +741,41 @@
slave->ring_position);
}
- if (slave->sii_sync_count >= 2) {
- // configure sync managers
+ if (slave->sii_sync_count >= 2) { // mailbox configuration provided
ec_datagram_npwr(datagram, slave->station_address, 0x0800,
- EC_SYNC_SIZE * slave->sii_sync_count);
- memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
+ EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
+ memset(datagram->data, 0x00,
+ EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
for (i = 0; i < 2; i++) {
- ec_sync_config(&slave->sii_syncs[i],
- datagram->data + EC_SYNC_SIZE * i);
+ ec_sync_config(&slave->sii_syncs[i], slave->sii_syncs[i].length,
+ datagram->data + EC_SYNC_PAGE_SIZE * i);
}
} else { // no mailbox sync manager configurations provided
ec_sync_t sync;
if (master->debug_level)
- EC_DBG("Slave %i does not provide"
+ EC_DBG("Slave %u does not provide"
" mailbox sync manager configurations.\n",
slave->ring_position);
ec_datagram_npwr(datagram, slave->station_address, 0x0800,
- EC_SYNC_SIZE * 2);
- memset(datagram->data, 0x00, EC_SYNC_SIZE * 2);
+ EC_SYNC_PAGE_SIZE * 2);
+ memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
ec_sync_init(&sync, slave, 0);
sync.physical_start_address = slave->sii_rx_mailbox_offset;
- sync.length = slave->sii_rx_mailbox_size;
sync.control_register = 0x26;
sync.enable = 1;
- ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
+ ec_sync_config(&sync, slave->sii_rx_mailbox_size,
+ datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
ec_sync_init(&sync, slave, 1);
sync.physical_start_address = slave->sii_tx_mailbox_offset;
- sync.length = slave->sii_tx_mailbox_size;
sync.control_register = 0x22;
sync.enable = 1;
- ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
+ ec_sync_config(&sync, slave->sii_tx_mailbox_size,
+ datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
}
fsm->retries = EC_FSM_RETRIES;
@@ -877,15 +878,22 @@
{
ec_slave_t *slave = fsm->slave;
- // No CoE configuration to be applied?
- if (list_empty(&slave->sdo_confs)) { // skip SDO configuration
+ if (!slave->config) {
+ EC_DBG("Slave %u is not configured.\n", slave->ring_position);
+ ec_fsm_slave_conf_enter_saveop(fsm);
+ return;
+ }
+
+ // No CoE configuration to be applied? FIXME
+ if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
ec_fsm_slave_conf_enter_mapconf(fsm);
return;
}
// start SDO configuration
fsm->state = ec_fsm_slave_conf_state_sdoconf;
- fsm->sdodata = list_entry(fsm->slave->sdo_confs.next, ec_sdo_data_t, list);
+ fsm->sdodata =
+ list_entry(fsm->slave->config->sdo_configs.next, ec_sdo_data_t, list);
ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
}
@@ -911,9 +919,9 @@
}
// Another SDO to configure?
- if (fsm->sdodata->list.next != &fsm->slave->sdo_confs) {
- fsm->sdodata = list_entry(fsm->sdodata->list.next,
- ec_sdo_data_t, list);
+ if (fsm->sdodata->list.next != &fsm->slave->config->sdo_configs) {
+ fsm->sdodata =
+ list_entry(fsm->sdodata->list.next, ec_sdo_data_t, list);
ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
return;
@@ -982,21 +990,34 @@
{
ec_slave_t *slave = fsm->slave;
ec_datagram_t *datagram = fsm->datagram;
- unsigned int i;
+ unsigned int i, offset, num_syncs;
+ const ec_sync_t *sync;
+ ec_direction_t dir;
+ uint16_t size;
if (!slave->sii_sync_count) {
ec_fsm_slave_conf_enter_fmmu(fsm);
return;
}
+ if (slave->sii_mailbox_protocols) {
+ offset = 2; // slave has mailboxes
+ } else {
+ offset = 0;
+ }
+ num_syncs = slave->sii_sync_count - offset;
+
// configure sync managers for process data
- ec_datagram_npwr(datagram, slave->station_address, 0x0800,
- EC_SYNC_SIZE * slave->sii_sync_count);
- memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
-
- for (i = 0; i < slave->sii_sync_count; i++) {
- ec_sync_config(&slave->sii_syncs[i],
- datagram->data + EC_SYNC_SIZE * i);
+ ec_datagram_npwr(datagram, slave->station_address,
+ 0x0800 + EC_SYNC_PAGE_SIZE * offset,
+ EC_SYNC_PAGE_SIZE * num_syncs);
+ memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * num_syncs);
+
+ for (i = 0; i < num_syncs; i++) {
+ sync = &slave->sii_syncs[i + offset];
+ dir = ec_sync_direction(sync);
+ size = ec_pdo_mapping_total_size(&slave->config->mapping[dir]);
+ ec_sync_config(sync, size, datagram->data + EC_SYNC_PAGE_SIZE * i);
}
fsm->retries = EC_FSM_RETRIES;
@@ -1047,7 +1068,9 @@
{
ec_slave_t *slave = fsm->slave;
ec_datagram_t *datagram = fsm->datagram;
- unsigned int j;
+ unsigned int i;
+ const ec_fmmu_config_t *fmmu;
+ const ec_sync_t *sync;
if (!slave->base_fmmu_count) { // skip FMMU configuration
ec_fsm_slave_conf_enter_saveop(fsm);
@@ -1056,10 +1079,18 @@
// configure FMMUs
ec_datagram_npwr(datagram, slave->station_address,
- 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
- memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
- for (j = 0; j < slave->fmmu_count; j++) {
- ec_fmmu_config(&slave->fmmus[j], datagram->data + EC_FMMU_SIZE * j);
+ 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+ memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+ for (i = 0; i < slave->config->used_fmmus; i++) {
+ fmmu = &slave->config->fmmu_configs[i];
+ if (!(sync = ec_slave_get_pdo_sync(slave, fmmu->dir))) {
+ fsm->state = ec_fsm_slave_state_error;
+ EC_ERR("Failed to determine PDO sync manager for FMMU on slave"
+ " %u!\n", slave->ring_position);
+ return;
+ }
+ ec_fmmu_config_page(fmmu, sync,
+ datagram->data + EC_FMMU_PAGE_SIZE * i);
}
fsm->retries = EC_FSM_RETRIES;
--- a/master/globals.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/globals.h Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
*
*****************************************************************************/
-/**
- \file
- Global definitions and macros.
-*/
+/** \file
+ * Global definitions and macros.
+ */
/*****************************************************************************/
@@ -46,112 +45,121 @@
#include "../globals.h"
/******************************************************************************
- * EtherCAT master
+ * EtherCAT master
*****************************************************************************/
-/** clock frequency for the EoE state machines */
+/** Clock frequency for the EoE state machines. */
#define EC_EOE_FREQUENCY 1000
-/** datagram timeout in microseconds */
+/** Datagram timeout in microseconds. */
#define EC_IO_TIMEOUT 500
-/** number of state machine retries on datagram timeout */
+/** Number of state machine retries on datagram timeout. */
#define EC_FSM_RETRIES 3
/** Seconds to wait before fetching SDO dictionary
after slave entered PREOP state. */
#define EC_WAIT_SDO_DICT 3
-/** minimum size of a buffer used with ec_state_string() */
+/** Minimum size of a buffer used with ec_state_string(). */
#define EC_STATE_STRING_SIZE 32
-/** maximum EEPROM size in words, to avoid infinite reading. */
+/** Maximum EEPROM size in words, to avoid infinite reading. */
#define EC_MAX_EEPROM_SIZE 1024
/******************************************************************************
- * EtherCAT protocol
+ * EtherCAT protocol
*****************************************************************************/
-/** size of an EtherCAT frame header */
+/** Size of an EtherCAT frame header. */
#define EC_FRAME_HEADER_SIZE 2
-/** size of an EtherCAT datagram header */
+/** Size of an EtherCAT datagram header. */
#define EC_DATAGRAM_HEADER_SIZE 10
-/** size of an EtherCAT datagram footer */
+/** Size of an EtherCAT datagram footer. */
#define EC_DATAGRAM_FOOTER_SIZE 2
-/** size of the EtherCAT address field */
+/** Size of the EtherCAT address field. */
#define EC_ADDR_LEN 4
-/** resulting maximum data size of a single datagram in a frame */
+/** Resulting maximum data size of a single datagram in a frame. */
#define EC_MAX_DATA_SIZE (ETH_DATA_LEN - EC_FRAME_HEADER_SIZE \
- EC_DATAGRAM_HEADER_SIZE - EC_DATAGRAM_FOOTER_SIZE)
-/** word offset of first EEPROM category. */
+/** Word offset of first EEPROM category. */
#define EC_FIRST_EEPROM_CATEGORY_OFFSET 0x40
-/*****************************************************************************/
-
-/**
- Convenience macro for printing EtherCAT-specific information to syslog.
- This will print the message in \a fmt with a prefixed "EtherCAT: ".
- \param fmt format string (like in printf())
- \param args arguments (optional)
-*/
-
+/** Size of a sync manager configuration page. */
+#define EC_SYNC_PAGE_SIZE 8
+
+/** Maximum number of FMMUs per slave. */
+#define EC_MAX_FMMUS 16
+
+/** Size of an FMMU configuration page. */
+#define EC_FMMU_PAGE_SIZE 16
+
+/*****************************************************************************/
+
+/** Convenience macro for printing EtherCAT-specific information to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
#define EC_INFO(fmt, args...) \
printk(KERN_INFO "EtherCAT: " fmt, ##args)
-/**
- Convenience macro for printing EtherCAT-specific errors to syslog.
- This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
- \param fmt format string (like in printf())
- \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT-specific errors to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
#define EC_ERR(fmt, args...) \
printk(KERN_ERR "EtherCAT ERROR: " fmt, ##args)
-/**
- Convenience macro for printing EtherCAT-specific warnings to syslog.
- This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
- \param fmt format string (like in printf())
- \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT-specific warnings to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
#define EC_WARN(fmt, args...) \
printk(KERN_WARNING "EtherCAT WARNING: " fmt, ##args)
-/**
- Convenience macro for printing EtherCAT debug messages to syslog.
- This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
- \param fmt format string (like in printf())
- \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT debug messages to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
#define EC_DBG(fmt, args...) \
printk(KERN_DEBUG "EtherCAT DEBUG: " fmt, ##args)
-/**
- Convenience macro for defining read-only SysFS attributes.
- This results in creating a static variable called attr_\a NAME. The SysFS
- file will be world-readable.
- \param NAME name of the attribute to create.
-*/
-
+/** Convenience macro for defining read-only SysFS attributes.
+ *
+ * This results in creating a static variable called attr_\a NAME. The SysFS
+ * file will be world-readable.
+ *
+ * \param NAME name of the attribute to create.
+ */
#define EC_SYSFS_READ_ATTR(NAME) \
static struct attribute attr_##NAME = { \
.name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO \
}
-/**
- Convenience macro for defining read-write SysFS attributes.
- This results in creating a static variable called attr_\a NAME. The SysFS
- file will be word-readable plus owner-writable.
- \param NAME name of the attribute to create.
-*/
-
+/** Convenience macro for defining read-write SysFS attributes.
+ *
+ * This results in creating a static variable called attr_\a NAME. The SysFS
+ * file will be word-readable plus owner-writable.
+ *
+ * \param NAME name of the attribute to create.
+ */
#define EC_SYSFS_READ_WRITE_ATTR(NAME) \
static struct attribute attr_##NAME = { \
.name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO | S_IWUSR \
@@ -171,27 +179,22 @@
/*****************************************************************************/
-/**
- Code - Message pair.
- Some EtherCAT datagrams support reading a status code to display a certain
- message. This type allows to map a code to a message string.
-*/
-
-typedef struct
-{
- uint32_t code; /**< code */
- const char *message; /**< message belonging to \a code */
+/** Code - Message pair.
+ *
+ * Some EtherCAT datagrams support reading a status code to display a certain
+ * message. This type allows to map a code to a message string.
+ */
+typedef struct {
+ uint32_t code; /**< Code. */
+ const char *message; /**< Message belonging to \a code. */
}
ec_code_msg_t;
/*****************************************************************************/
-/**
- * Master request state.
- */
-
-typedef enum
-{
+/** Master request state.
+ */
+typedef enum {
EC_REQUEST_QUEUED,
EC_REQUEST_IN_PROGRESS,
EC_REQUEST_COMPLETE,
@@ -201,6 +204,7 @@
/*****************************************************************************/
+typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
typedef struct ec_sdo ec_sdo_t; /**< \see ec_sdo */
/*****************************************************************************/
--- a/master/master.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/master.c Tue Feb 19 08:22:20 2008 +0000
@@ -46,16 +46,18 @@
#include "../include/ecrt.h"
#include "globals.h"
-#include "master.h"
#include "slave.h"
+#include "slave_config.h"
#include "device.h"
#include "datagram.h"
#ifdef EC_EOE
#include "ethernet.h"
#endif
-
-/*****************************************************************************/
-
+#include "master.h"
+
+/*****************************************************************************/
+
+void ec_master_destroy_slave_configs(ec_master_t *);
void ec_master_destroy_domains(ec_master_t *);
static int ec_master_idle_thread(ec_master_t *);
static int ec_master_operation_thread(ec_master_t *);
@@ -122,6 +124,8 @@
INIT_LIST_HEAD(&master->slaves);
master->slave_count = 0;
+ INIT_LIST_HEAD(&master->configs);
+
master->scan_state = EC_REQUEST_IN_PROGRESS;
master->allow_scan = 1;
init_MUTEX(&master->scan_sem);
@@ -136,12 +140,14 @@
master->datagram_index = 0;
INIT_LIST_HEAD(&master->domains);
+
master->debug_level = 0;
-
master->stats.timeouts = 0;
master->stats.corrupted = 0;
master->stats.unmatched = 0;
master->stats.output_jiffies = 0;
+ master->pdo_slaves_offline = 0; // assume all PDO slaves online
+ master->frames_timed_out = 0;
for (i = 0; i < HZ; i++) {
master->idle_cycle_times[i] = 0;
@@ -236,6 +242,7 @@
#ifdef EC_EOE
ec_master_clear_eoe_handlers(master);
#endif
+ ec_master_destroy_slave_configs(master);
ec_master_destroy_slaves(master);
ec_master_destroy_domains(master);
ec_fsm_master_clear(&master->fsm);
@@ -251,10 +258,8 @@
/*****************************************************************************/
#ifdef EC_EOE
-/**
- * Clear and free all EoE handlers.
+/** Clear and free all EoE handlers.
*/
-
void ec_master_clear_eoe_handlers(
ec_master_t *master /**< EtherCAT master */
)
@@ -271,15 +276,27 @@
/*****************************************************************************/
-/**
- Destroy all slaves.
-*/
-
+/** Destroy all slave configurations.
+ */
+void ec_master_destroy_slave_configs(ec_master_t *master)
+{
+ ec_slave_config_t *sc, *next;
+
+ list_for_each_entry_safe(sc, next, &master->configs, list) {
+ list_del(&sc->list);
+ ec_slave_config_destroy(sc);
+ }
+}
+
+/*****************************************************************************/
+
+/** Destroy all slaves.
+ */
void ec_master_destroy_slaves(ec_master_t *master)
{
- ec_slave_t *slave, *next_slave;
-
- list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
+ ec_slave_t *slave, *next;
+
+ list_for_each_entry_safe(slave, next, &master->slaves, list) {
list_del(&slave->list);
ec_slave_destroy(slave);
}
@@ -295,9 +312,9 @@
void ec_master_destroy_domains(ec_master_t *master)
{
- ec_domain_t *domain, *next_d;
-
- list_for_each_entry_safe(domain, next_d, &master->domains, list) {
+ ec_domain_t *domain, *next;
+
+ list_for_each_entry_safe(domain, next, &master->domains, list) {
list_del(&domain->list);
ec_domain_destroy(domain);
}
@@ -467,8 +484,6 @@
EC_DBG("Switching to operation mode.\n");
master->mode = EC_MASTER_MODE_OPERATION;
- master->pdo_slaves_offline = 0; // assume all PDO slaves online
- master->frames_timed_out = 0;
master->ext_request_cb = NULL;
master->ext_release_cb = NULL;
master->ext_cb_data = NULL;
@@ -505,9 +520,11 @@
master->release_cb = ec_master_release_cb;
master->cb_data = master;
+ ec_master_destroy_slave_configs(master);
+ ec_master_destroy_domains(master);
+
// set states for all slaves
list_for_each_entry(slave, &master->slaves, list) {
- ec_slave_reset(slave);
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
}
#ifdef EC_EOE
@@ -518,8 +535,6 @@
}
#endif
- ec_master_destroy_domains(master);
-
if (ec_master_thread_start(master, ec_master_idle_thread))
EC_WARN("Failed to restart master thread!\n");
#ifdef EC_EOE
@@ -1241,101 +1256,51 @@
/*****************************************************************************/
-/**
- * Translates an ASCII coded bus-address to a slave pointer.
- * These are the valid addressing schemes:
- * - \a "X" = the Xth slave on the bus (ring position),
- * - \a "#X" = the slave with alias X,
- * - \a "#X:Y" = the Yth slave after the slave with alias X.
- * X and Y are zero-based indices and may be provided in hexadecimal or octal
- * notation (with appropriate prefix).
- * \return pointer to the slave on success, else NULL
+/** Detaches the slave configurations from the slaves.
*/
-
-ec_slave_t *ec_master_parse_slave_address(
- const ec_master_t *master, /**< EtherCAT master */
- const char *address /**< address string */
+void ec_master_detach_slave_configs(
+ ec_master_t *master /**< EtherCAT master. */
)
{
- unsigned long first, second;
- char *remainder, *remainder2;
- const char *original;
- unsigned int alias_requested = 0, alias_not_found = 1;
- ec_slave_t *alias_slave = NULL, *slave;
-
- original = address;
-
- if (!address[0])
- goto out_invalid;
-
- if (address[0] == '#') {
- alias_requested = 1;
- address++;
- }
-
- first = simple_strtoul(address, &remainder, 0);
- if (remainder == address)
- goto out_invalid;
-
- if (alias_requested) {
- list_for_each_entry(alias_slave, &master->slaves, list) {
- if (alias_slave->sii_alias == first) {
- alias_not_found = 0;
- break;
- }
- }
- if (alias_not_found) {
- EC_ERR("Alias not found!\n");
- goto out_invalid;
- }
- }
-
- if (!remainder[0]) {
- if (alias_requested) { // alias addressing
- return alias_slave;
- }
- else { // position addressing
- list_for_each_entry(slave, &master->slaves, list) {
- if (slave->ring_position == first) return slave;
- }
- EC_ERR("Slave index out of range!\n");
- goto out_invalid;
- }
- }
- else if (alias_requested && remainder[0] == ':') { // field addressing
- struct list_head *list;
- remainder++;
- second = simple_strtoul(remainder, &remainder2, 0);
-
- if (remainder2 == remainder || remainder2[0])
- goto out_invalid;
-
- list = &alias_slave->list;
- while (second--) {
- list = list->next;
- if (list == &master->slaves) { // last slave exceeded
- EC_ERR("Slave index out of range!\n");
- goto out_invalid;
- }
- }
- return list_entry(list, ec_slave_t, list);
- }
-
-out_invalid:
- EC_ERR("Invalid slave address string \"%s\"!\n", original);
- return NULL;
+ ec_slave_config_t *sc;
+
+ if (!master->configs_attached)
+ return;
+
+ list_for_each_entry(sc, &master->configs, list) {
+ ec_slave_config_detach(sc);
+ }
+
+ master->configs_attached = 0;
+}
+
+/*****************************************************************************/
+
+/** Attaches the slave configurations to the slaves.
+ */
+int ec_master_attach_slave_configs(
+ ec_master_t *master /**< EtherCAT master. */
+ )
+{
+ ec_slave_config_t *sc;
+ unsigned int errors = 0;
+
+ if (master->configs_attached)
+ return 0;
+
+ list_for_each_entry(sc, &master->configs, list) {
+ if (ec_slave_config_attach(sc))
+ errors = 1;
+ }
+
+ master->configs_attached = !errors;
+ return errors ? -1 : 0;
}
/******************************************************************************
* 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;
@@ -1364,25 +1329,16 @@
/*****************************************************************************/
-/**
- 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 */)
+int ecrt_master_activate(ec_master_t *master)
{
uint32_t domain_offset;
ec_domain_t *domain;
- // allocate all domains
+ // finish 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);
+ if (ec_domain_finish(domain, domain_offset)) {
+ EC_ERR("Failed to finish domain %X!\n", (u32) domain);
return -1;
}
domain_offset += domain->data_size;
@@ -1435,12 +1391,7 @@
/*****************************************************************************/
-/**
- Asynchronous sending of datagrams.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
+void ecrt_master_send(ec_master_t *master)
{
ec_datagram_t *datagram, *n;
@@ -1468,12 +1419,7 @@
/*****************************************************************************/
-/**
- Asynchronous receiving of datagrams.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
+void ecrt_master_receive(ec_master_t *master)
{
ec_datagram_t *datagram, *next;
cycles_t cycles_timeout;
@@ -1510,80 +1456,65 @@
/*****************************************************************************/
-/**
- * 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;
-}
-
-/*****************************************************************************/
-
-/**
- * Obtains a slave pointer by its ring position.
- * 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_by_pos(
- const ec_master_t *master, /**< EtherCAT master */
- uint16_t ring_position, /**< ring position */
- uint32_t vendor_id, /**< vendor ID */
- uint32_t product_code /**< product code */
- )
-{
- ec_slave_t *slave;
+ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
+ uint16_t alias, uint16_t position, uint32_t vendor_id,
+ uint32_t product_code)
+{
+ ec_slave_config_t *sc;
unsigned int found = 0;
- list_for_each_entry(slave, &master->slaves, list) {
- if (slave->ring_position == ring_position) {
+ list_for_each_entry(sc, &master->configs, list) {
+ if (sc->alias == alias && sc->position == position) {
found = 1;
break;
}
}
- if (!found) {
- EC_ERR("Slave index out of range!\n");
- return NULL;
- }
-
- return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
-}
-
-/*****************************************************************************/
-
-/**
- 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.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */
- int (*request_cb)(void *), /**< request lock CB */
- void (*release_cb)(void *), /**< release lock CB */
- void *cb_data /**< data parameter */
- )
+ if (found) {
+ if (master->debug_level) {
+ EC_INFO("Using existing slave configuration for %u:%u\n",
+ alias, position);
+ }
+ if (sc->vendor_id != vendor_id || sc->product_code != product_code) {
+ EC_ERR("Slave type mismatch. Slave was configured as"
+ " 0x%08X/0x%08X before. Now configuring with"
+ " 0x%08X/0x%08X.\n", sc->vendor_id, sc->product_code,
+ vendor_id, product_code);
+ return NULL;
+ }
+ } else {
+ if (master->debug_level) {
+ EC_INFO("Creating slave configuration for %u:%u,"
+ " 0x%08X/0x%08X.\n", alias, position, vendor_id,
+ product_code);
+ }
+
+ if (!(sc = (ec_slave_config_t *) kmalloc(sizeof(ec_slave_config_t),
+ GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for slave configuration.\n");
+ return NULL;
+ }
+
+ if (ec_slave_config_init(sc, master, alias, position, vendor_id,
+ product_code)) {
+ EC_ERR("Failed to init slave configuration.\n");
+ return NULL;
+ }
+
+ // try to find the addressed slave
+ ec_slave_config_attach(sc);
+ ec_slave_config_load_default_mapping(sc);
+
+ list_add_tail(&sc->list, &master->configs);
+ }
+
+ return sc;
+}
+
+/*****************************************************************************/
+
+void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
+ void (*release_cb)(void *), void *cb_data)
{
master->ext_request_cb = request_cb;
master->ext_release_cb = release_cb;
@@ -1592,19 +1523,13 @@
/*****************************************************************************/
-/**
- * Reads the current master status.
- */
-
-void ecrt_master_get_status(const ec_master_t *master, /**< EtherCAT master */
- ec_master_status_t *status /**< target status object */
- )
-{
- status->bus_status =
+void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
+{
+ state->bus_state =
(master->pdo_slaves_offline || master->frames_timed_out)
? EC_BUS_FAILURE : EC_BUS_OK;
- status->bus_tainted = master->fsm.tainted;
- status->slaves_responding = master->fsm.slaves_responding;
+ state->bus_tainted = master->fsm.tainted;
+ state->slaves_responding = master->fsm.slaves_responding;
}
/*****************************************************************************/
@@ -1616,9 +1541,8 @@
EXPORT_SYMBOL(ecrt_master_send);
EXPORT_SYMBOL(ecrt_master_receive);
EXPORT_SYMBOL(ecrt_master_callbacks);
-EXPORT_SYMBOL(ecrt_master_get_slave);
-EXPORT_SYMBOL(ecrt_master_get_slave_by_pos);
-EXPORT_SYMBOL(ecrt_master_get_status);
+EXPORT_SYMBOL(ecrt_master_slave_config);
+EXPORT_SYMBOL(ecrt_master_state);
/** \endcond */
--- a/master/master.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/master.h Tue Feb 19 08:22:20 2008 +0000
@@ -53,12 +53,9 @@
/*****************************************************************************/
-/**
- EtherCAT master mode.
-*/
-
-typedef enum
-{
+/** EtherCAT master mode.
+ */
+typedef enum {
EC_MASTER_MODE_ORPHANED,
EC_MASTER_MODE_IDLE,
EC_MASTER_MODE_OPERATION
@@ -67,12 +64,9 @@
/*****************************************************************************/
-/**
- Cyclic statistics.
-*/
-
-typedef struct
-{
+/** Cyclic statistics.
+ */
+typedef struct {
unsigned int timeouts; /**< datagram timeouts */
unsigned int corrupted; /**< corrupted frames */
unsigned int unmatched; /**< unmatched datagrams (received, but not
@@ -83,11 +77,10 @@
/*****************************************************************************/
-/**
- EtherCAT master.
- Manages slaves, domains and IO.
-*/
-
+/** EtherCAT master.
+ *
+ * Manages slaves, domains and IO.
+ */
struct ec_master
{
struct kobject kobj; /**< kobject */
@@ -110,6 +103,9 @@
struct list_head slaves; /**< list of slaves on the bus */
unsigned int slave_count; /**< number of slaves on the bus */
+
+ struct list_head configs; /**< Bus configuration list. */
+ unsigned int configs_attached; /**< Slave configurations were attached. */
ec_request_state_t scan_state; /**< current scanning state */
unsigned int allow_scan; /**< non-zero, if slave scanning is allowed */
@@ -196,6 +192,7 @@
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
// misc.
+int ec_master_attach_slave_configs(ec_master_t *);
void ec_master_output_stats(ec_master_t *);
#ifdef EC_EOE
void ec_master_clear_eoe_handlers(ec_master_t *);
--- a/master/module.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/module.c Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
*
*****************************************************************************/
-/**
- \file
- EtherCAT master driver module.
-*/
+/** \file
+ * EtherCAT master driver module.
+ */
/*****************************************************************************/
@@ -49,7 +48,7 @@
/*****************************************************************************/
-#define MAX_MASTERS 5 /**< maximum number of masters */
+#define MAX_MASTERS 5 /**< Maximum number of masters. */
/*****************************************************************************/
@@ -541,28 +540,7 @@
* Realtime interface
*****************************************************************************/
-/**
- * Returns the version magic of the realtime interface.
- * \return ECRT version magic.
- * \ingroup RealtimeInterface
- */
-
-unsigned int ecrt_version_magic(void)
-{
- return ECRT_VERSION_MAGIC;
-}
-
-/*****************************************************************************/
-
-/**
- Reserves an EtherCAT master for realtime operation.
- \return pointer to reserved master, or NULL on error
- \ingroup RealtimeInterface
-*/
-
-ec_master_t *ecrt_request_master(unsigned int master_index
- /**< master index */
- )
+ec_master_t *ecrt_request_master(unsigned int master_index)
{
ec_master_t *master;
@@ -622,12 +600,7 @@
/*****************************************************************************/
-/**
- Releases a reserved EtherCAT master.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
+void ecrt_release_master(ec_master_t *master)
{
EC_INFO("Releasing master %u...\n", master->index);
@@ -646,6 +619,13 @@
/*****************************************************************************/
+unsigned int ecrt_version_magic(void)
+{
+ return ECRT_VERSION_MAGIC;
+}
+
+/*****************************************************************************/
+
/** \cond */
module_init(ec_init_module);
--- a/master/pdo.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/pdo.c Tue Feb 19 08:22:20 2008 +0000
@@ -44,66 +44,196 @@
/*****************************************************************************/
-/**
- * PDO constructor.
- */
-
-void ec_pdo_init(ec_pdo_t *pdo /**< EtherCAT PDO */)
-{
+void ec_pdo_clear_entries(ec_pdo_t *);
+
+/*****************************************************************************/
+
+/** PDO constructor.
+ */
+void ec_pdo_init(
+ ec_pdo_t *pdo /**< EtherCAT PDO */
+ )
+{
+ pdo->sync_index = -1; // not assigned
pdo->name = NULL;
INIT_LIST_HEAD(&pdo->entries);
}
/*****************************************************************************/
-/**
- * PDO destructor.
- */
-
+/** Pdo copy constructor.
+ */
+int ec_pdo_init_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
+{
+ pdo->dir = other_pdo->dir;
+ pdo->index = other_pdo->index;
+ pdo->sync_index = other_pdo->sync_index;
+ pdo->name = NULL;
+ INIT_LIST_HEAD(&pdo->entries);
+
+ if (ec_pdo_set_name(pdo, other_pdo->name))
+ goto out_return;
+
+ if (ec_pdo_copy_entries(pdo, other_pdo))
+ goto out_clear;
+
+ return 0;
+
+out_clear:
+ ec_pdo_clear(pdo);
+out_return:
+ return -1;
+}
+
+/*****************************************************************************/
+
+/** PDO destructor.
+ */
void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT PDO */)
{
+ if (pdo->name)
+ kfree(pdo->name);
+
+ ec_pdo_clear_entries(pdo);
+}
+
+/*****************************************************************************/
+
+/** Clear Pdo entry list.
+ */
+void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT PDO */)
+{
ec_pdo_entry_t *entry, *next;
// free all PDO entries
list_for_each_entry_safe(entry, next, &pdo->entries, list) {
list_del(&entry->list);
+ ec_pdo_entry_clear(entry);
kfree(entry);
}
}
/*****************************************************************************/
-/**
- * Makes a deep copy of a PDO.
- */
-
-int ec_pdo_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
-{
- ec_pdo_entry_t *entry, *other_entry, *next;
-
- // make flat copy
- *pdo = *other_pdo;
-
- INIT_LIST_HEAD(&pdo->entries);
- list_for_each_entry(other_entry, &other_pdo->entries, list) {
+/** Set Pdo name.
+ */
+int ec_pdo_set_name(
+ ec_pdo_t *pdo, /**< Pdo. */
+ const char *name /**< New name. */
+ )
+{
+ unsigned int len;
+
+ if (pdo->name)
+ kfree(pdo->name);
+
+ if (name && (len = strlen(name))) {
+ if (!(pdo->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
+ EC_ERR("Failed to allocate PDO name.\n");
+ return -1;
+ }
+ memcpy(pdo->name, name, len + 1);
+ } else {
+ pdo->name = NULL;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Copy Pdo entries from another Pdo.
+ */
+int ec_pdo_copy_entries(ec_pdo_t *pdo, const ec_pdo_t *other)
+{
+ ec_pdo_entry_t *entry, *other_entry;
+
+ ec_pdo_clear_entries(pdo);
+
+ list_for_each_entry(other_entry, &other->entries, list) {
if (!(entry = (ec_pdo_entry_t *)
kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for PDO entry copy.\n");
- goto out_free;
- }
-
- *entry = *other_entry; // flat copy is sufficient
+ return -1;
+ }
+
+ if (ec_pdo_entry_init_copy(entry, other_entry)) {
+ kfree(entry);
+ return -1;
+ }
+
list_add_tail(&entry->list, &pdo->entries);
}
return 0;
-
-out_free:
- list_for_each_entry_safe(entry, next, &pdo->entries, list) {
- list_del(&entry->list);
- kfree(entry);
- }
- return -1;
-}
-
-/*****************************************************************************/
+}
+
+/*****************************************************************************/
+
+/** Pdo entry constructor.
+ */
+void ec_pdo_entry_init(
+ ec_pdo_entry_t *entry /**< Pdo entry. */
+ )
+{
+ entry->name = NULL;
+}
+
+/*****************************************************************************/
+
+/** Pdo entry copy constructor.
+ */
+int ec_pdo_entry_init_copy(
+ ec_pdo_entry_t *entry, /**< Pdo entry. */
+ const ec_pdo_entry_t *other /**< Pdo entry to copy from. */
+ )
+{
+ entry->index = other->index;
+ entry->subindex = other->subindex;
+ entry->name = NULL;
+ entry->bit_length = other->bit_length;
+
+ if (ec_pdo_entry_set_name(entry, other->name))
+ return -1;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Pdo entry destructor.
+ */
+void ec_pdo_entry_clear(ec_pdo_entry_t *entry /**< Pdo entry. */)
+{
+ if (entry->name)
+ kfree(entry->name);
+}
+
+/*****************************************************************************/
+
+/** Set Pdo entry name.
+ */
+int ec_pdo_entry_set_name(
+ ec_pdo_entry_t *entry, /**< Pdo entry. */
+ const char *name /**< New name. */
+ )
+{
+ unsigned int len;
+
+ if (entry->name)
+ kfree(entry->name);
+
+ if (name && (len = strlen(name))) {
+ if (!(entry->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
+ EC_ERR("Failed to allocate PDO entry name.\n");
+ return -1;
+ }
+ memcpy(entry->name, name, len + 1);
+ } else {
+ entry->name = NULL;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
--- a/master/pdo.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/pdo.h Tue Feb 19 08:22:20 2008 +0000
@@ -43,59 +43,47 @@
#include <linux/list.h>
+#include "../include/ecrt.h"
+
#include "globals.h"
/*****************************************************************************/
-/**
- * PDO type.
+/** PDO description.
*/
-
-typedef enum
-{
- EC_RX_PDO, /**< Reveive PDO */
- EC_TX_PDO /**< Transmit PDO */
-}
-ec_pdo_type_t;
+typedef struct {
+ struct list_head list; /**< List item. */
+ ec_direction_t dir; /**< PDO direction. */
+ uint16_t index; /**< PDO index. */
+ int8_t sync_index; /**< Assigned sync manager. */
+ char *name; /**< PDO name. */
+ struct list_head entries; /**< List of PDO entries. */
+} ec_pdo_t;
/*****************************************************************************/
-/**
- * PDO description.
+/** PDO entry description.
*/
-
-typedef struct
-{
- struct list_head list; /**< list item */
- ec_pdo_type_t type; /**< PDO type */
- uint16_t index; /**< PDO index */
- int8_t sync_index; /**< assigned sync manager */
- char *name; /**< PDO name */
- struct list_head entries; /**< entry list */
-}
-ec_pdo_t;
-
-/*****************************************************************************/
-
-/**
- * PDO entry description.
- */
-
-typedef struct
-{
+typedef struct {
struct list_head list; /**< list item */
uint16_t index; /**< PDO entry index */
uint8_t subindex; /**< PDO entry subindex */
char *name; /**< entry name */
uint8_t bit_length; /**< entry length in bit */
-}
-ec_pdo_entry_t;
+} ec_pdo_entry_t;
/*****************************************************************************/
void ec_pdo_init(ec_pdo_t *);
+int ec_pdo_init_copy(ec_pdo_t *, const ec_pdo_t *);
void ec_pdo_clear(ec_pdo_t *);
-int ec_pdo_copy(ec_pdo_t *, const ec_pdo_t *);
+int ec_pdo_set_name(ec_pdo_t *, const char *);
+int ec_pdo_copy_entries(ec_pdo_t *, const ec_pdo_t *);
+
+void ec_pdo_entry_init(ec_pdo_entry_t *);
+int ec_pdo_entry_init_copy(ec_pdo_entry_t *, const ec_pdo_entry_t *);
+void ec_pdo_entry_clear(ec_pdo_entry_t *);
+int ec_pdo_entry_set_name(ec_pdo_entry_t *, const char *);
/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/pdo_mapping.c Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,319 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 Pdo mapping methods.
+*/
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "pdo.h"
+#include "slave_config.h"
+#include "master.h"
+
+#include "pdo_mapping.h"
+
+/*****************************************************************************/
+
+/** Pdo mapping constructor.
+ */
+void ec_pdo_mapping_init(
+ ec_pdo_mapping_t *pm /**< Pdo mapping. */
+ )
+{
+ INIT_LIST_HEAD(&pm->pdos);
+ pm->default_mapping = 1;
+}
+
+/*****************************************************************************/
+
+/** Pdo mapping destructor.
+ */
+void ec_pdo_mapping_clear(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
+{
+ ec_pdo_mapping_clear_pdos(pm);
+}
+
+/*****************************************************************************/
+
+/** Clears the list of mapped Pdos.
+ */
+void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
+{
+ ec_pdo_t *pdo, *next;
+
+ list_for_each_entry_safe(pdo, next, &pm->pdos, list) {
+ list_del_init(&pdo->list);
+ ec_pdo_clear(pdo);
+ kfree(pdo);
+ }
+}
+
+/*****************************************************************************/
+
+/** Calculates the total size of the mapped PDO entries.
+ *
+ * \retval Data size in byte.
+ */
+uint16_t ec_pdo_mapping_total_size(
+ const ec_pdo_mapping_t *pm /**< Pdo mapping. */
+ )
+{
+ unsigned int bit_size;
+ const ec_pdo_t *pdo;
+ const ec_pdo_entry_t *pdo_entry;
+ uint16_t byte_size;
+
+ bit_size = 0;
+ list_for_each_entry(pdo, &pm->pdos, list) {
+ list_for_each_entry(pdo_entry, &pdo->entries, list) {
+ bit_size += pdo_entry->bit_length;
+ }
+ }
+
+ if (bit_size % 8) // round up to full bytes
+ byte_size = bit_size / 8 + 1;
+ else
+ byte_size = bit_size / 8;
+
+ return byte_size;
+}
+
+/*****************************************************************************/
+
+/** Adds a Pdo to the mapping.
+ *
+ * \return 0 on success, else < 0
+ */
+int ec_pdo_mapping_add_pdo(
+ ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+ const ec_pdo_t *pdo /**< PDO to add. */
+ )
+{
+ ec_pdo_t *mapped_pdo;
+
+ // PDO already mapped?
+ list_for_each_entry(mapped_pdo, &pm->pdos, list) {
+ if (mapped_pdo->index != pdo->index) continue;
+ EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
+ return -1;
+ }
+
+ if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for PDO mapping.\n");
+ return -1;
+ }
+
+ if (ec_pdo_init_copy(mapped_pdo, pdo)) {
+ kfree(mapped_pdo);
+ return -1;
+ }
+
+ list_add_tail(&mapped_pdo->list, &pm->pdos);
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Add a Pdo to the mapping.
+ *
+ * The first call of this method will clear the default mapping.
+ *
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int ec_pdo_mapping_add_pdo_info(
+ ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+ const ec_pdo_info_t *pdo_info, /**< Pdo information. */
+ const ec_slave_config_t *config /**< Slave configuration, to load
+ default entries. */
+ )
+{
+ unsigned int i;
+ ec_pdo_t *pdo;
+ ec_pdo_entry_t *entry;
+ const ec_pdo_entry_info_t *entry_info;
+
+ if (pm->default_mapping) {
+ pm->default_mapping = 0;
+ ec_pdo_mapping_clear_pdos(pm);
+ }
+
+ if (!(pdo = (ec_pdo_t *) kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for Pdo.\n");
+ goto out_return;
+ }
+
+ ec_pdo_init(pdo);
+ pdo->dir = pdo_info->dir;
+ pdo->index = pdo_info->index;
+
+ if (config->master->debug_level)
+ EC_INFO("Adding Pdo 0x%04X to mapping.\n", pdo->index);
+
+ if (pdo_info->n_entries) { // Pdo configuration provided
+ if (config->master->debug_level)
+ EC_INFO(" Pdo configuration provided.\n");
+
+ for (i = 0; i < pdo_info->n_entries; i++) {
+ entry_info = &pdo_info->entries[i];
+
+ if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for PDO entry.\n");
+ goto out_free;
+ }
+
+ ec_pdo_entry_init(entry);
+ entry->index = entry_info->index;
+ entry->subindex = entry_info->subindex;
+ entry->bit_length = entry_info->bit_length;
+ list_add_tail(&entry->list, &pdo->entries);
+ }
+ } else { // use default Pdo configuration
+ if (config->master->debug_level)
+ EC_INFO(" Using default Pdo configuration.\n");
+
+ if (config->slave) {
+ ec_sync_t *sync;
+ ec_pdo_t *default_pdo;
+
+ if ((sync = ec_slave_get_pdo_sync(config->slave, pdo->dir))) {
+ list_for_each_entry(default_pdo, &sync->mapping.pdos, list) {
+ if (default_pdo->index != pdo->index)
+ continue;
+ if (config->master->debug_level)
+ EC_INFO(" Found Pdo name \"%s\".\n",
+ default_pdo->name);
+ // try to take Pdo name from mapped one
+ if (ec_pdo_set_name(pdo, default_pdo->name))
+ goto out_free;
+ // copy entries (= default Pdo configuration)
+ if (ec_pdo_copy_entries(pdo, default_pdo))
+ goto out_free;
+ if (config->master->debug_level) {
+ const ec_pdo_entry_t *entry;
+ list_for_each_entry(entry, &pdo->entries, list) {
+ EC_INFO(" Entry 0x%04X:%u.\n",
+ entry->index, entry->subindex);
+ }
+ }
+ }
+ } else {
+ EC_WARN("Slave %u does not provide a default Pdo"
+ " configuration!\n", config->slave->ring_position);
+ }
+ } else {
+ EC_WARN("Failed to load default Pdo configuration for %u:%u:"
+ " Slave not found.\n", config->alias, config->position);
+ }
+ }
+
+ list_add_tail(&pdo->list, &pm->pdos);
+ return 0;
+
+out_free:
+ ec_pdo_clear(pdo);
+ kfree(pdo);
+out_return:
+ return -1;
+}
+
+/*****************************************************************************/
+
+/** Makes a deep copy of another Pdo mapping.
+ *
+ * \return 0 on success, else < 0
+ */
+int ec_pdo_mapping_copy(
+ ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+ const ec_pdo_mapping_t *other /**< PDO mapping to copy from. */
+ )
+{
+ ec_pdo_t *other_pdo;
+
+ ec_pdo_mapping_clear_pdos(pm);
+
+ // PDO already mapped?
+ list_for_each_entry(other_pdo, &other->pdos, list) {
+ if (ec_pdo_mapping_add_pdo(pm, other_pdo))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Compares two Pdo mappings.
+ *
+ * Only the mapping is compared, not the Pdo entries (i. e. the Pdo
+ * configuration).
+ *
+ * \retval 1 The given Pdo mappings are equal.
+ * \retval 0 The given Pdo mappings differ.
+ */
+int ec_pdo_mapping_equal(
+ const ec_pdo_mapping_t *pm1, /**< First mapping. */
+ const ec_pdo_mapping_t *pm2 /**< Second mapping. */
+ )
+{
+ const struct list_head *h1, *h2, *l1, *l2;
+ const ec_pdo_t *p1, *p2;
+
+ h1 = l1 = &pm1->pdos;
+ h2 = l2 = &pm2->pdos;
+
+ while (1) {
+ l1 = l1->next;
+ l2 = l2->next;
+
+ if ((l1 == h1) ^ (l2 == h2)) // unequal lengths
+ return 0;
+ if (l1 == h1 && l2 == h2) // both finished
+ break;
+
+ p1 = list_entry(l1, ec_pdo_t, list);
+ p2 = list_entry(l2, ec_pdo_t, list);
+
+ if (p1->index != p2->index)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/pdo_mapping.h Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 Pdo mapping structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef _EC_PDO_MAPPING_H_
+#define _EC_PDO_MAPPING_H_
+
+#include <linux/list.h>
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** EtherCAT PDO mapping.
+ */
+typedef struct {
+ struct list_head pdos; /**< List of Pdos. */
+ unsigned int default_mapping; /**< This is the default mapping. */
+} ec_pdo_mapping_t;
+
+/*****************************************************************************/
+
+void ec_pdo_mapping_init(ec_pdo_mapping_t *);
+void ec_pdo_mapping_clear(ec_pdo_mapping_t *);
+
+void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *);
+
+int ec_pdo_mapping_add_pdo(ec_pdo_mapping_t *, const ec_pdo_t *);
+int ec_pdo_mapping_add_pdo_info(ec_pdo_mapping_t *, const ec_pdo_info_t *,
+ const ec_slave_config_t *);
+
+int ec_pdo_mapping_copy(ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
+
+uint16_t ec_pdo_mapping_total_size(const ec_pdo_mapping_t *);
+int ec_pdo_mapping_equal(const ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/slave.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/slave.c Tue Feb 19 08:22:20 2008 +0000
@@ -42,9 +42,11 @@
#include <linux/delay.h>
#include "globals.h"
-#include "slave.h"
#include "datagram.h"
#include "master.h"
+#include "slave_config.h"
+
+#include "slave.h"
/*****************************************************************************/
@@ -113,13 +115,12 @@
slave->master = master;
+ slave->config = NULL;
slave->requested_state = EC_SLAVE_STATE_PREOP;
slave->current_state = EC_SLAVE_STATE_UNKNOWN;
+ slave->online_state = EC_SLAVE_ONLINE;
slave->self_configured = 0;
slave->error_flag = 0;
- slave->online_state = EC_SLAVE_ONLINE;
- slave->fmmu_count = 0;
- slave->pdos_registered = 0;
slave->base_type = 0;
slave->base_revision = 0;
@@ -151,7 +152,6 @@
slave->sii_sync_count = 0;
INIT_LIST_HEAD(&slave->sii_pdos);
INIT_LIST_HEAD(&slave->sdo_dictionary);
- INIT_LIST_HEAD(&slave->sdo_confs);
slave->sdo_dictionary_fetched = 0;
slave->pdo_mapping_fetched = 0;
@@ -213,6 +213,9 @@
{
ec_sdo_t *sdo, *next_sdo;
+ if (slave->config)
+ ec_slave_config_detach(slave->config);
+
// free all SDOs
list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
list_del(&sdo->list);
@@ -240,7 +243,6 @@
{
ec_slave_t *slave;
ec_pdo_t *pdo, *next_pdo;
- ec_sdo_data_t *sdodata, *next_sdodata;
unsigned int i;
slave = container_of(kobj, ec_slave_t, kobj);
@@ -267,13 +269,6 @@
kfree(pdo);
}
- // free all SDO configurations
- list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
- list_del(&sdodata->list);
- kfree(sdodata->data);
- kfree(sdodata);
- }
-
if (slave->eeprom_data) kfree(slave->eeprom_data);
kfree(slave);
@@ -292,33 +287,6 @@
/*****************************************************************************/
/**
- Reset slave from operation mode.
-*/
-
-void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */)
-{
- ec_sdo_data_t *sdodata, *next_sdodata;
- unsigned int i;
-
- slave->fmmu_count = 0;
- slave->pdos_registered = 0;
-
- // free all SDO configurations
- list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
- list_del(&sdodata->list);
- kfree(sdodata->data);
- kfree(sdodata);
- }
-
- // remove estimated sync manager sizes
- for (i = 0; i < slave->sii_sync_count; i++) {
- slave->sii_syncs[i].est_length = 0;
- }
-}
-
-/*****************************************************************************/
-
-/**
* Sets the application state of a slave.
*/
@@ -351,16 +319,12 @@
{
if (new_state == EC_SLAVE_OFFLINE &&
slave->online_state == EC_SLAVE_ONLINE) {
- if (slave->pdos_registered)
- slave->master->pdo_slaves_offline++;
if (slave->master->debug_level)
EC_DBG("Slave %u: offline.\n", slave->ring_position);
}
else if (new_state == EC_SLAVE_ONLINE &&
slave->online_state == EC_SLAVE_OFFLINE) {
slave->error_flag = 0; // clear error flag
- if (slave->pdos_registered)
- slave->master->pdo_slaves_offline--;
if (slave->master->debug_level) {
char cur_state[EC_STATE_STRING_SIZE];
ec_state_string(slave->current_state, cur_state);
@@ -534,7 +498,7 @@
ec_slave_t *slave, /**< EtherCAT slave */
const uint8_t *data, /**< category data */
size_t data_size, /**< number of bytes */
- ec_pdo_type_t pdo_type /**< PDO type */
+ ec_direction_t dir /**< PDO direction. */
)
{
ec_pdo_t *pdo;
@@ -548,11 +512,16 @@
}
ec_pdo_init(pdo);
- pdo->type = pdo_type;
+ pdo->dir = dir;
pdo->index = EC_READ_U16(data);
entry_count = EC_READ_U8(data + 2);
pdo->sync_index = EC_READ_U8(data + 3);
- pdo->name = ec_slave_sii_string(slave, EC_READ_U8(data + 5));
+ if (ec_pdo_set_name(pdo,
+ ec_slave_sii_string(slave, EC_READ_U8(data + 5)))) {
+ ec_pdo_clear(pdo);
+ kfree(pdo);
+ return -1;
+ }
list_add_tail(&pdo->list, &slave->sii_pdos);
data_size -= 8;
@@ -564,9 +533,15 @@
return -1;
}
+ ec_pdo_entry_init(entry);
entry->index = EC_READ_U16(data);
entry->subindex = EC_READ_U8(data + 2);
- entry->name = ec_slave_sii_string(slave, EC_READ_U8(data + 3));
+ if (ec_pdo_entry_set_name(entry,
+ ec_slave_sii_string(slave, EC_READ_U8(data + 3)))) {
+ ec_pdo_entry_clear(entry);
+ kfree(entry);
+ return -1;
+ }
entry->bit_length = EC_READ_U8(data + 5);
list_add_tail(&entry->list, &pdo->entries);
@@ -577,7 +552,6 @@
// if sync manager index is positive, the PDO is mapped by default
if (pdo->sync_index >= 0) {
ec_sync_t *sync;
- ec_pdo_t *mapped_pdo;
if (pdo->sync_index >= slave->sii_sync_count) {
EC_ERR("Invalid SM index %i for PDO 0x%04X in slave %u.",
@@ -586,18 +560,9 @@
}
sync = &slave->sii_syncs[pdo->sync_index];
- if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
- EC_ERR("Failed to allocate PDO memory.\n");
+ if (ec_pdo_mapping_add_pdo(&sync->mapping, pdo))
return -1;
- }
-
- if (ec_pdo_copy(mapped_pdo, pdo)) {
- EC_ERR("Failed to copy PDO.\n");
- kfree(mapped_pdo);
- return -1;
- }
-
- list_add_tail(&mapped_pdo->list, &sync->pdos);
+
sync->mapping_source = EC_SYNC_MAPPING_SII;
}
}
@@ -632,61 +597,8 @@
/*****************************************************************************/
-/**
- * Prepares an FMMU configuration.
- * Configuration data for the FMMU is saved in the slave structure and is
- * written to the slave in ecrt_master_activate().
- * The FMMU configuration is done in a way, that the complete data range
- * of the corresponding sync manager is covered. Seperate FMMUs are configured
- * for each domain.
- * If the FMMU configuration is already prepared, the function returns with
- * success.
- * \return 0 in case of success, else < 0
+/** Outputs all information about a certain slave.
*/
-
-int ec_slave_prepare_fmmu(
- ec_slave_t *slave, /**< EtherCAT slave */
- const ec_domain_t *domain, /**< domain */
- const ec_sync_t *sync /**< sync manager */
- )
-{
- unsigned int i;
- ec_fmmu_t *fmmu;
-
- // FMMU configuration already prepared?
- for (i = 0; i < slave->fmmu_count; i++) {
- fmmu = &slave->fmmus[i];
- if (fmmu->domain == domain && fmmu->sync == sync)
- return 0;
- }
-
- // reserve new FMMU...
-
- if (slave->fmmu_count >= slave->base_fmmu_count) {
- EC_ERR("Slave %u FMMU limit reached!\n", slave->ring_position);
- return -1;
- }
-
- fmmu = &slave->fmmus[slave->fmmu_count];
-
- ec_fmmu_init(fmmu, slave, slave->fmmu_count++);
- fmmu->domain = domain;
- fmmu->sync = sync;
- fmmu->logical_start_address = 0;
-
- slave->pdos_registered = 1;
-
- ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Outputs all information about a certain slave.
-*/
-
ssize_t ec_slave_info(const ec_slave_t *slave, /**< EtherCAT slave */
char *buffer /**< Output buffer */
)
@@ -695,8 +607,6 @@
ec_pdo_t *pdo;
ec_pdo_entry_t *pdo_entry;
int first, i;
- ec_sdo_data_t *sdodata;
- char str[20];
char *large_buffer, *buf;
unsigned int size;
@@ -713,9 +623,7 @@
buf += sprintf(buf, " (");
buf += ec_state_string(slave->requested_state, buf);
buf += sprintf(buf, ")\n");
- buf += sprintf(buf, "Flags: %s, %s\n\n",
- slave->online_state == EC_SLAVE_ONLINE ? "online" : "OFFLINE",
- slave->error_flag ? "ERROR" : "ok");
+ buf += sprintf(buf, "Flags: %s\n\n", slave->error_flag ? "ERROR" : "ok");
buf += sprintf(buf, "Data link status:\n");
for (i = 0; i < 4; i++) {
@@ -821,10 +729,10 @@
buf += sprintf(buf,
" SM%u: addr 0x%04X, size %u, control 0x%02X, %s\n",
sync->index, sync->physical_start_address,
- ec_sync_size(sync), sync->control_register,
+ sync->length, sync->control_register,
sync->enable ? "enable" : "disable");
- if (list_empty(&sync->pdos)) {
+ if (list_empty(&sync->mapping.pdos)) {
buf += sprintf(buf, " No PDOs mapped.\n");
} else if (sync->mapping_source != EC_SYNC_MAPPING_NONE) {
buf += sprintf(buf,
@@ -833,9 +741,9 @@
? "SII" : "CoE");
}
- list_for_each_entry(pdo, &sync->pdos, list) {
+ list_for_each_entry(pdo, &sync->mapping.pdos, list) {
buf += sprintf(buf, " %s 0x%04X \"%s\"\n",
- pdo->type == EC_RX_PDO ? "RxPdo" : "TxPdo",
+ pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
pdo->index, pdo->name ? pdo->name : "???");
list_for_each_entry(pdo_entry, &pdo->entries, list) {
@@ -856,7 +764,7 @@
list_for_each_entry(pdo, &slave->sii_pdos, list) {
buf += sprintf(buf, " %s 0x%04X \"%s\"",
- pdo->type == EC_RX_PDO ? "RxPdo" : "TxPdo",
+ pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
pdo->index, pdo->name ? pdo->name : "???");
if (pdo->sync_index >= 0)
buf += sprintf(buf, ", default mapping: SM%u.\n",
@@ -874,23 +782,6 @@
buf += sprintf(buf, "\n");
}
- // type-cast to avoid warnings on some compilers
- if (!list_empty((struct list_head *) &slave->sdo_confs)) {
- buf += sprintf(buf, "SDO configurations:\n");
-
- list_for_each_entry(sdodata, &slave->sdo_confs, list) {
- switch (sdodata->size) {
- case 1: sprintf(str, "%u", EC_READ_U8(sdodata->data)); break;
- case 2: sprintf(str, "%u", EC_READ_U16(sdodata->data)); break;
- case 4: sprintf(str, "%u", EC_READ_U32(sdodata->data)); break;
- default: sprintf(str, "(invalid size)"); break;
- }
- buf += sprintf(buf, " 0x%04X:%-3i -> %s\n",
- sdodata->index, sdodata->subindex, str);
- }
- buf += sprintf(buf, "\n");
- }
-
size = buf - large_buffer;
if (size >= PAGE_SIZE) {
const char trunc[] = "\n---TRUNCATED---\n";
@@ -1251,47 +1142,6 @@
\return 0 in case of success, else < 0
*/
-int ec_slave_conf_sdo(ec_slave_t *slave, /**< EtherCAT slave */
- uint16_t sdo_index, /**< SDO index */
- uint8_t sdo_subindex, /**< SDO subindex */
- const uint8_t *data, /**< SDO data */
- size_t size /**< SDO size in bytes */
- )
-{
- ec_sdo_data_t *sdodata;
-
- if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
- EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
- return -1;
- }
-
- if (!(sdodata = (ec_sdo_data_t *)
- kmalloc(sizeof(ec_sdo_data_t), GFP_KERNEL))) {
- EC_ERR("Failed to allocate memory for SDO configuration object!\n");
- return -1;
- }
-
- if (!(sdodata->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
- EC_ERR("Failed to allocate memory for SDO configuration data!\n");
- kfree(sdodata);
- return -1;
- }
-
- sdodata->index = sdo_index;
- sdodata->subindex = sdo_subindex;
- memcpy(sdodata->data, data, size);
- sdodata->size = size;
-
- list_add_tail(&sdodata->list, &slave->sdo_confs);
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- \return 0 in case of success, else < 0
-*/
-
int ec_slave_validate(const ec_slave_t *slave, /**< EtherCAT slave */
uint32_t vendor_id, /**< vendor ID */
uint32_t product_code /**< product code */
@@ -1357,184 +1207,4 @@
return NULL;
}
-/******************************************************************************
- * Realtime interface
- *****************************************************************************/
-
-/**
- \return 0 in case of success, else < 0
- \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo8(ec_slave_t *slave, /**< EtherCAT slave */
- uint16_t sdo_index, /**< SDO index */
- uint8_t sdo_subindex, /**< SDO subindex */
- uint8_t value /**< new SDO value */
- )
-{
- uint8_t data[1];
- EC_WRITE_U8(data, value);
- return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 1);
-}
-
-/*****************************************************************************/
-
-/**
- \return 0 in case of success, else < 0
- \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo16(ec_slave_t *slave, /**< EtherCAT slave */
- uint16_t sdo_index, /**< SDO index */
- uint8_t sdo_subindex, /**< SDO subindex */
- uint16_t value /**< new SDO value */
- )
-{
- uint8_t data[2];
- EC_WRITE_U16(data, value);
- return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 2);
-}
-
-/*****************************************************************************/
-
-/**
- \return 0 in case of success, else < 0
- \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo32(ec_slave_t *slave, /**< EtherCAT slave */
- uint16_t sdo_index, /**< SDO index */
- uint8_t sdo_subindex, /**< SDO subindex */
- uint32_t value /**< new SDO value */
- )
-{
- uint8_t data[4];
- EC_WRITE_U32(data, value);
- return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 4);
-}
-
-/*****************************************************************************/
-
-/**
- * Clear slave's PDO mapping.
- */
-
-void ecrt_slave_pdo_mapping_clear(
- ec_slave_t *slave, /**< EtherCAT slave */
- ec_direction_t dir /**< output/input */
- )
-{
- ec_sync_t *sync;
-
- if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
- EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
- return;
- }
-
- if (!(sync = ec_slave_get_pdo_sync(slave, dir)))
- return;
-
- ec_sync_clear_pdos(sync);
- sync->alt_mapping = 1;
-}
-
-/*****************************************************************************/
-
-/**
- * Add a PDO to the list of known mapped PDOs.
- */
-
-int ecrt_slave_pdo_mapping_add(
- ec_slave_t *slave, /**< EtherCAT slave */
- ec_direction_t dir, /**< input/output */
- uint16_t pdo_index /**< Index of mapped PDO */)
-{
- ec_pdo_t *pdo;
- ec_sync_t *sync;
- unsigned int not_found = 1;
-
- if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
- EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
- return -1;
- }
-
- // does the slave provide the PDO? FIXME
- list_for_each_entry(pdo, &slave->sii_pdos, list) {
- if (pdo->index == pdo_index) {
- not_found = 0;
- break;
- }
- }
-
- if (not_found) {
- EC_ERR("Slave %u does not provide PDO 0x%04X!\n",
- slave->ring_position, pdo_index);
- return -1;
- }
-
- // check direction
- if ((pdo->type == EC_TX_PDO && dir == EC_DIR_OUTPUT) ||
- (pdo->type == EC_RX_PDO && dir == EC_DIR_INPUT)) {
- EC_ERR("Invalid direction for PDO 0x%04X.\n", pdo_index);
- return -1;
- }
-
-
- if (!(sync = ec_slave_get_pdo_sync(slave, dir))) {
- EC_ERR("Failed to obtain sync manager for PDO mapping of slave %u!\n",
- slave->ring_position);
- return -1;
- }
-
- if (ec_sync_add_pdo(sync, pdo))
- return -1;
-
- sync->alt_mapping = 1;
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * Convenience function for ecrt_slave_pdo_mapping_clear() and
- * ecrt_slave_pdo_mapping_add().
- */
-
-int ecrt_slave_pdo_mapping(ec_slave_t *slave, /**< EtherCAT slave */
- ec_direction_t dir, /**< input/output */
- unsigned int num_args, /**< Number of following arguments */
- ... /**< PDO indices to map */
- )
-{
- va_list ap;
-
- ecrt_slave_pdo_mapping_clear(slave, dir);
-
- va_start(ap, num_args);
-
- for (; num_args; num_args--) {
- if (ecrt_slave_pdo_mapping_add(
- slave, dir, (uint16_t) va_arg(ap, int))) {
- return -1;
- }
- }
-
- va_end(ap);
- return 0;
-}
-
-
-/*****************************************************************************/
-
-/** \cond */
-
-EXPORT_SYMBOL(ecrt_slave_conf_sdo8);
-EXPORT_SYMBOL(ecrt_slave_conf_sdo16);
-EXPORT_SYMBOL(ecrt_slave_conf_sdo32);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping_clear);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping_add);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping);
-
-/** \endcond */
-
-/*****************************************************************************/
+/*****************************************************************************/
--- a/master/slave.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/slave.h Tue Feb 19 08:22:20 2008 +0000
@@ -50,21 +50,12 @@
#include "datagram.h"
#include "pdo.h"
#include "sync.h"
-#include "fmmu.h"
/*****************************************************************************/
-/** maximum number of FMMUs per slave */
-#define EC_MAX_FMMUS 16
-
-/*****************************************************************************/
-
-/**
- * State of an EtherCAT slave.
+/** State of an EtherCAT slave.
*/
-
-typedef enum
-{
+typedef enum {
EC_SLAVE_STATE_UNKNOWN = 0x00,
/**< unknown state */
EC_SLAVE_STATE_INIT = 0x01,
@@ -77,29 +68,22 @@
/**< OP (mailbox communication and input/output update) */
EC_SLAVE_STATE_ACK_ERR = 0x10
/**< Acknowledge/Error bit (no actual state) */
-}
-ec_slave_state_t;
+} ec_slave_state_t;
/*****************************************************************************/
-/**
- * EtherCAT slave online state.
+/** EtherCAT slave online state.
*/
-
typedef enum {
EC_SLAVE_OFFLINE,
EC_SLAVE_ONLINE
-}
-ec_slave_online_state_t;
+} ec_slave_online_state_t;
/*****************************************************************************/
-/**
- * Supported mailbox protocols.
+/** Supported mailbox protocols.
*/
-
-enum
-{
+enum {
EC_MBOX_AOE = 0x01, /**< ADS-over-EtherCAT */
EC_MBOX_EOE = 0x02, /**< Ethernet-over-EtherCAT */
EC_MBOX_COE = 0x04, /**< CANopen-over-EtherCAT */
@@ -110,27 +94,26 @@
/*****************************************************************************/
-/**
- * EtherCAT slave.
+/** EtherCAT slave.
*/
-
struct ec_slave
{
struct list_head list; /**< list item */
struct kobject kobj; /**< kobject */
ec_master_t *master; /**< master owning the slave */
- ec_slave_state_t requested_state; /**< requested application state */
- ec_slave_state_t current_state; /**< current application state */
- ec_slave_online_state_t online_state; /**< online state */
- unsigned int self_configured; /**< slave was configured by this master */
- unsigned int error_flag; /**< stop processing after an error */
- unsigned int pdos_registered; /**< non-zero, if PDOs were registered */
-
// addresses
uint16_t ring_position; /**< ring position */
uint16_t station_address; /**< configured station address */
+ // configuration
+ ec_slave_config_t *config; /**< Current configuration. */
+ ec_slave_state_t requested_state; /**< Requested application state. */
+ ec_slave_state_t current_state; /**< Current application state. */
+ ec_slave_online_state_t online_state; /**< online state */
+ unsigned int self_configured; /**< Slave was configured by this master. */
+ unsigned int error_flag; /**< Stop processing after an error. */
+
// base data
uint8_t base_type; /**< slave type */
uint8_t base_revision; /**< revision */
@@ -169,12 +152,8 @@
char *sii_name; /**< slave name acc. to EEPROM */
int16_t sii_current_on_ebus; /**< power consumption */
- ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
- uint8_t fmmu_count; /**< number of FMMUs used */
-
struct kobject sdo_kobj; /**< kobject for SDOs */
struct list_head sdo_dictionary; /**< SDO dictionary list */
- struct list_head sdo_confs; /**< list of SDO configurations */
uint8_t sdo_dictionary_fetched; /**< dictionary has been fetched */
unsigned long jiffies_preop; /**< time, the slave went to PREOP */
@@ -187,11 +166,6 @@
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
void ec_slave_destroy(ec_slave_t *);
-void ec_slave_reset(ec_slave_t *);
-
-int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
- const ec_sync_t *);
-
void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
void ec_slave_set_state(ec_slave_t *, ec_slave_state_t);
void ec_slave_set_online_state(ec_slave_t *, ec_slave_online_state_t);
@@ -201,7 +175,7 @@
int ec_slave_fetch_sii_general(ec_slave_t *, const uint8_t *, size_t);
int ec_slave_fetch_sii_syncs(ec_slave_t *, const uint8_t *, size_t);
int ec_slave_fetch_sii_pdos(ec_slave_t *, const uint8_t *, size_t,
- ec_pdo_type_t);
+ ec_direction_t);
// misc.
ec_sync_t *ec_slave_get_pdo_sync(ec_slave_t *, ec_direction_t);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave_config.c Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,546 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 slave configuration methods.
+*/
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "master.h"
+
+#include "slave_config.h"
+
+/*****************************************************************************/
+
+void ec_slave_config_clear(struct kobject *);
+ssize_t ec_show_slave_config_attribute(struct kobject *, struct attribute *,
+ char *);
+
+/*****************************************************************************/
+
+/** \cond */
+
+EC_SYSFS_READ_ATTR(info);
+
+static struct attribute *def_attrs[] = {
+ &attr_info,
+ NULL,
+};
+
+static struct sysfs_ops sysfs_ops = {
+ .show = ec_show_slave_config_attribute
+};
+
+static struct kobj_type ktype_ec_slave_config = {
+ .release = ec_slave_config_clear,
+ .sysfs_ops = &sysfs_ops,
+ .default_attrs = def_attrs
+};
+
+/** \endcond */
+
+/*****************************************************************************/
+
+/** Slave configuration constructor.
+ *
+ * See ecrt_master_slave_config() for the usage of the \a alias and \a
+ * position parameters.
+ *
+ * \retval 0 Success.
+ * \retval <0 Failure.
+ */
+int ec_slave_config_init(ec_slave_config_t *sc, /**< Slave configuration. */
+ 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. */
+ )
+{
+ ec_direction_t dir;
+
+ sc->master = master;
+ sc->alias = alias;
+ sc->position = position;
+ sc->vendor_id = vendor_id;
+ sc->product_code = product_code;
+ sc->slave = NULL;
+
+ for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++)
+ ec_pdo_mapping_init(&sc->mapping[dir]);
+
+ INIT_LIST_HEAD(&sc->sdo_configs);
+
+ sc->used_fmmus = 0;
+
+ // init kobject and add it to the hierarchy
+ memset(&sc->kobj, 0x00, sizeof(struct kobject));
+ kobject_init(&sc->kobj);
+ sc->kobj.ktype = &ktype_ec_slave_config;
+ sc->kobj.parent = &master->kobj;
+ if (kobject_set_name(&sc->kobj, "config-%u-%u", sc->alias, sc->position)) {
+ EC_ERR("Failed to set kobject name for slave config %u:%u.\n",
+ sc->alias, sc->position);
+ goto out_put;
+ }
+ if (kobject_add(&sc->kobj)) {
+ EC_ERR("Failed to add kobject for slave config %u:%u.\n",
+ sc->alias, sc->position);
+ goto out_put;
+ }
+
+ return 0;
+
+ out_put:
+ kobject_put(&sc->kobj);
+ return -1;
+}
+
+/*****************************************************************************/
+
+/** Slave configuration destructor.
+ *
+ * Clears and frees a slave configuration object.
+ */
+void ec_slave_config_destroy(
+ ec_slave_config_t *sc /**< Slave configuration. */
+ )
+{
+ ec_slave_config_detach(sc);
+
+ // destroy self
+ kobject_del(&sc->kobj);
+ kobject_put(&sc->kobj);
+}
+
+/*****************************************************************************/
+
+/** Clear and free the slave configuration.
+ *
+ * This method is called by the kobject, once there are no more references to
+ * it.
+ */
+void ec_slave_config_clear(struct kobject *kobj /**< kobject of the config. */)
+{
+ ec_slave_config_t *sc;
+ ec_direction_t dir;
+ ec_sdo_data_t *sdodata, *next_sdodata;
+
+ sc = container_of(kobj, ec_slave_config_t, kobj);
+
+ // Free Pdo mappings
+ for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++)
+ ec_pdo_mapping_clear(&sc->mapping[dir]);
+
+ // free all SDO configurations
+ list_for_each_entry_safe(sdodata, next_sdodata, &sc->sdo_configs, list) {
+ list_del(&sdodata->list);
+ kfree(sdodata->data);
+ kfree(sdodata);
+ }
+
+ /** \todo */
+
+ kfree(sc);
+}
+
+/*****************************************************************************/
+
+/** Prepares an FMMU configuration.
+ *
+ * Configuration data for the FMMU is saved in the slave config structure and
+ * is written to the slave during the configuration. The FMMU configuration
+ * is done in a way, that the complete data range of the corresponding sync
+ * manager is covered. Seperate FMMUs are configured for each domain. If the
+ * FMMU configuration is already prepared, the function returns with success.
+ *
+ * \retval >=0 Logical offset address.
+ * \retval -1 FMMU limit reached.
+ */
+int ec_slave_config_prepare_fmmu(
+ ec_slave_config_t *sc, /**< Slave configuration. */
+ ec_domain_t *domain, /**< Domain. */
+ ec_direction_t dir /**< PDO direction. */
+ )
+{
+ unsigned int i;
+ ec_fmmu_config_t *fmmu;
+
+ // FMMU configuration already prepared?
+ for (i = 0; i < sc->used_fmmus; i++) {
+ fmmu = &sc->fmmu_configs[i];
+ if (fmmu->domain == domain && fmmu->dir == dir)
+ return fmmu->logical_start_address;
+ }
+
+ if (sc->used_fmmus == EC_MAX_FMMUS) {
+ EC_ERR("FMMU limit reached for slave configuration %u:%u!\n",
+ sc->alias, sc->position);
+ return -1;
+ }
+
+ fmmu = &sc->fmmu_configs[sc->used_fmmus++];
+ ec_fmmu_config_init(fmmu, sc, domain, dir);
+ return fmmu->logical_start_address;
+}
+
+/*****************************************************************************/
+
+/** Registers a Pdo entry.
+ *
+ * Searches the mapping and the Pdo configurations for the given Pdo entry. If
+ * found, the curresponding sync manager/FMMU is added to the domain and the
+ * offset of the Pdo entry's data in the domain process data is returned.
+ *
+ * \retval >=0 Offset of the Pdo entry's process data.
+ * \retval -1 Pdo entry not found.
+ * \retval -2 Failed to register Pdo entry.
+ */
+int ec_slave_config_reg_pdo_entry(
+ ec_slave_config_t *sc, /**< Slave configuration. */
+ ec_domain_t *domain, /**< Domain. */
+ uint16_t index, /**< Index of Pdo entry to register. */
+ uint8_t subindex /**< Subindex of Pdo entry to register. */
+ )
+{
+ ec_direction_t dir;
+ ec_pdo_mapping_t *map;
+ unsigned int bit_offset, byte_offset;
+ ec_pdo_t *pdo;
+ ec_pdo_entry_t *entry;
+ int ret;
+
+ for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+ map = &sc->mapping[dir];
+ bit_offset = 0;
+ list_for_each_entry(pdo, &map->pdos, list) {
+ list_for_each_entry(entry, &pdo->entries, list) {
+ if (entry->index != index || entry->subindex != subindex) {
+ bit_offset += entry->bit_length;
+ } else {
+ goto found;
+ }
+ }
+ }
+ }
+
+ EC_ERR("PDO entry 0x%04X:%u is not mapped in slave config %u:%u.\n",
+ index, subindex, sc->alias, sc->position);
+ return -1;
+
+found:
+ byte_offset = bit_offset / 8;
+ if ((ret = ec_slave_config_prepare_fmmu(sc, domain, dir)) < 0)
+ return -2;
+ return ret + byte_offset;
+}
+
+/*****************************************************************************/
+
+/** Outputs all information about a certain slave configuration.
+*/
+ssize_t ec_slave_config_info(
+ const ec_slave_config_t *sc, /**< Slave configuration. */
+ char *buffer /**< Output buffer */
+ )
+{
+ char *buf = buffer;
+ ec_direction_t dir;
+ const ec_pdo_mapping_t *map;
+ const ec_pdo_t *pdo;
+ const ec_pdo_entry_t *entry;
+ char str[20];
+ ec_sdo_data_t *sdodata;
+
+ buf += sprintf(buf, "Alias: 0x%04X (%u)\n", sc->alias, sc->alias);
+ buf += sprintf(buf, "Position: %u\n", sc->position);
+
+ for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+ map = &sc->mapping[dir];
+
+ if (!list_empty(&map->pdos)) {
+ buf += sprintf(buf, "%s mapping:\n",
+ dir == EC_DIR_OUTPUT ? "Output" : "Input");
+
+ list_for_each_entry(pdo, &map->pdos, list) {
+ buf += sprintf(buf, " %s 0x%04X \"%s\"\n",
+ pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
+ pdo->index, pdo->name ? pdo->name : "???");
+
+ list_for_each_entry(entry, &pdo->entries, list) {
+ buf += sprintf(buf, " 0x%04X:%X \"%s\", %u bit\n",
+ entry->index, entry->subindex,
+ entry->name ? entry->name : "???",
+ entry->bit_length);
+ }
+ }
+ }
+ }
+
+ // type-cast to avoid warnings on some compilers
+ if (!list_empty((struct list_head *) &sc->sdo_configs)) {
+ buf += sprintf(buf, "\nSDO configurations:\n");
+
+ list_for_each_entry(sdodata, &sc->sdo_configs, list) {
+ switch (sdodata->size) {
+ case 1: sprintf(str, "%u", EC_READ_U8(sdodata->data)); break;
+ case 2: sprintf(str, "%u", EC_READ_U16(sdodata->data)); break;
+ case 4: sprintf(str, "%u", EC_READ_U32(sdodata->data)); break;
+ default: sprintf(str, "(invalid size)"); break;
+ }
+ buf += sprintf(buf, " 0x%04X:%-3i -> %s\n",
+ sdodata->index, sdodata->subindex, str);
+ }
+ buf += sprintf(buf, "\n");
+ }
+
+ return buf - buffer;
+}
+
+/*****************************************************************************/
+
+/** Formats attribute data for SysFS read access.
+ *
+ * \return number of bytes to read
+ */
+ssize_t ec_show_slave_config_attribute(
+ struct kobject *kobj, /**< Slave configuration's kobject */
+ struct attribute *attr, /**< Requested attribute. */
+ char *buffer /**< Memory to store data. */
+ )
+{
+ ec_slave_config_t *sc = container_of(kobj, ec_slave_config_t, kobj);
+
+ if (attr == &attr_info) {
+ return ec_slave_config_info(sc, buffer);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Adds an SDO configuration.
+ */
+int ec_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
+ uint8_t subindex, const uint8_t *data, size_t size)
+{
+ ec_slave_t *slave = sc->slave;
+ ec_sdo_data_t *sdodata;
+
+ if (slave && !(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
+ EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
+ return -1;
+ }
+
+ if (!(sdodata = (ec_sdo_data_t *)
+ kmalloc(sizeof(ec_sdo_data_t), GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for SDO configuration object!\n");
+ return -1;
+ }
+
+ if (!(sdodata->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
+ EC_ERR("Failed to allocate memory for SDO configuration data!\n");
+ kfree(sdodata);
+ return -1;
+ }
+
+ sdodata->index = index;
+ sdodata->subindex = subindex;
+ memcpy(sdodata->data, data, size);
+ sdodata->size = size;
+
+ list_add_tail(&sdodata->list, &sc->sdo_configs);
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Attaches the configuration to the addressed slave object.
+ *
+ * \retval 0 Success.
+ * \retval -1 Slave not found.
+ * \retval -2 Slave already configured.
+ * \retval -3 Invalid slave type found at the given position.
+ */
+int ec_slave_config_attach(
+ ec_slave_config_t *sc /**< Slave configuration. */
+ )
+{
+ ec_slave_t *slave;
+ unsigned int alias_found = 0, relative_position = 0;
+
+ if (sc->slave)
+ return 0; // already attached
+
+ list_for_each_entry(slave, &sc->master->slaves, list) {
+ if (!alias_found) {
+ if (sc->alias && slave->sii_alias != sc->alias)
+ continue;
+ alias_found = 1;
+ relative_position = 0;
+ }
+ if (relative_position == sc->position)
+ goto found;
+ relative_position++;
+ }
+
+ EC_ERR("Failed to find slave for configuration %u:%u.\n",
+ sc->alias, sc->position);
+ return -1;
+
+found:
+ if (slave->config) {
+ EC_ERR("Failed to attach slave configuration %u:%u. Slave %u"
+ " already has a configuration!\n", sc->alias,
+ sc->position, slave->ring_position);
+ return -2;
+ }
+ if (slave->sii_vendor_id != sc->vendor_id
+ || slave->sii_product_code != sc->product_code) {
+ EC_ERR("Slave %u has an invalid type (0x%08X/0x%08X) for"
+ " configuration %u:%u (0x%08X/0x%08X).\n",
+ slave->ring_position, slave->sii_vendor_id,
+ slave->sii_product_code, sc->alias, sc->position,
+ sc->vendor_id, sc->product_code);
+ return -3;
+ }
+
+ // attach slave
+ slave->config = sc;
+ sc->slave = slave;
+
+ ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** Detaches the configuration from a slave object.
+ */
+void ec_slave_config_detach(
+ ec_slave_config_t *sc /**< Slave configuration. */
+ )
+{
+ if (sc->slave) {
+ sc->slave->config = NULL;
+ sc->slave = NULL;
+ }
+}
+
+/*****************************************************************************/
+
+/** Loads the default mapping from the slave object.
+ */
+void ec_slave_config_load_default_mapping(ec_slave_config_t *sc)
+{
+ ec_direction_t dir;
+ ec_pdo_mapping_t *map;
+ ec_sync_t *sync;
+
+ if (!sc->slave)
+ return;
+
+ for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+ map = &sc->mapping[dir];
+ if (!(sync = ec_slave_get_pdo_sync(sc->slave, dir)))
+ continue;
+ ec_pdo_mapping_copy(map, &sync->mapping);
+ }
+}
+
+/******************************************************************************
+ * Realtime interface
+ *****************************************************************************/
+
+int ecrt_slave_config_mapping(ec_slave_config_t *sc, unsigned int n_entries,
+ const ec_pdo_info_t pdo_infos[])
+{
+ unsigned int i;
+
+ for (i = 0; i < n_entries; i++)
+ if (ec_pdo_mapping_add_pdo_info(&sc->mapping[pdo_infos[i].dir],
+ &pdo_infos[i], sc))
+ return -1;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo8(ec_slave_config_t *slave, uint16_t index,
+ uint8_t subindex, uint8_t value)
+{
+ uint8_t data[1];
+ EC_WRITE_U8(data, value);
+ return ec_slave_config_sdo(slave, index, subindex, data, 1);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo16(ec_slave_config_t *slave, uint16_t index,
+ uint8_t subindex, uint16_t value)
+{
+ uint8_t data[2];
+ EC_WRITE_U16(data, value);
+ return ec_slave_config_sdo(slave, index, subindex, data, 2);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo32(ec_slave_config_t *slave, uint16_t index,
+ uint8_t subindex, uint32_t value)
+{
+ uint8_t data[4];
+ EC_WRITE_U32(data, value);
+ return ec_slave_config_sdo(slave, index, subindex, data, 4);
+}
+
+/*****************************************************************************/
+
+/** \cond */
+
+EXPORT_SYMBOL(ecrt_slave_config_mapping);
+EXPORT_SYMBOL(ecrt_slave_config_sdo8);
+EXPORT_SYMBOL(ecrt_slave_config_sdo16);
+EXPORT_SYMBOL(ecrt_slave_config_sdo32);
+
+/** \endcond */
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave_config.h Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * 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 slave configuration structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef _EC_SLAVE_CONFIG_H_
+#define _EC_SLAVE_CONFIG_H_
+
+#include <linux/list.h>
+#include <linux/kobject.h>
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+#include "slave.h"
+#include "fmmu_config.h"
+#include "pdo_mapping.h"
+
+/*****************************************************************************/
+
+/** EtherCAT slave configuration.
+ */
+struct ec_slave_config {
+ struct list_head list; /**< List item. */
+ struct kobject kobj; /**< kobject. */
+ ec_master_t *master; /**< Master owning the slave configuration. */
+
+ uint16_t alias; /**< Slave alias. */
+ uint16_t position; /**< Index after alias. If alias is zero, this is the
+ ring position. */
+ uint32_t vendor_id; /**< Slave vendor ID. */
+ uint32_t product_code; /**< Slave product code. */
+
+ ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
+ offline. */
+
+ ec_pdo_mapping_t mapping[2]; /**< Output and input PDO mapping. */
+
+ struct list_head sdo_configs; /**< SDO configurations. */
+
+ ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
+ uint8_t used_fmmus; /**< Number of FMMUs used. */
+};
+
+/*****************************************************************************/
+
+int ec_slave_config_init(ec_slave_config_t *, ec_master_t *, uint16_t,
+ uint16_t, uint32_t, uint32_t);
+void ec_slave_config_destroy(ec_slave_config_t *);
+
+int ec_slave_config_reg_pdo_entry(ec_slave_config_t *, ec_domain_t *,
+ uint16_t, uint8_t);
+
+int ec_slave_config_attach(ec_slave_config_t *);
+void ec_slave_config_detach(ec_slave_config_t *);
+
+void ec_slave_config_load_default_mapping(ec_slave_config_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/sync.c Thu Feb 14 09:18:55 2008 +0000
+++ b/master/sync.c Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
*
*****************************************************************************/
-/**
- \file
- EtherCAT sync manager methods.
-*/
+/** \file
+ * EtherCAT sync manager methods.
+ */
/*****************************************************************************/
@@ -46,93 +45,52 @@
/*****************************************************************************/
-/**
- * Constructor.
+/** Constructor.
*/
-
void ec_sync_init(
- ec_sync_t *sync, /**< EtherCAT sync manager */
- ec_slave_t *slave, /**< EtherCAT slave */
- unsigned int index /**< sync manager index */
+ ec_sync_t *sync, /**< EtherCAT sync manager. */
+ ec_slave_t *slave, /**< EtherCAT slave. */
+ unsigned int index /**< Sync manager index. */
)
{
sync->slave = slave;
sync->index = index;
- sync->est_length = 0;
- INIT_LIST_HEAD(&sync->pdos);
- sync->alt_mapping = 0;
+ ec_pdo_mapping_init(&sync->mapping);
sync->mapping_source = EC_SYNC_MAPPING_NONE;
}
/*****************************************************************************/
-/**
- * Destructor.
+/** Destructor.
*/
-
void ec_sync_clear(
- ec_sync_t *sync /**< EtherCAT sync manager */
+ ec_sync_t *sync /**< EtherCAT sync manager. */
)
{
- ec_sync_clear_pdos(sync);
+ ec_pdo_mapping_clear(&sync->mapping);
}
/*****************************************************************************/
-/**
- * Calculates the size of a sync manager by evaluating PDO sizes.
- * \return sync manager size
+/** Initializes a sync manager configuration page with EEPROM data.
+ *
+ * The referenced memory (\a data) must be at least \a EC_SYNC_SIZE bytes.
*/
-
-uint16_t ec_sync_size(
- const ec_sync_t *sync /**< sync manager */
+void ec_sync_config(
+ const ec_sync_t *sync, /**< Sync manager. */
+ uint16_t data_size, /**< Data size. */
+ uint8_t *data /**> Configuration memory. */
)
{
- const ec_pdo_t *pdo;
- const ec_pdo_entry_t *pdo_entry;
- unsigned int bit_size, byte_size;
-
- if (sync->length) return sync->length;
- if (sync->est_length) return sync->est_length;
-
- bit_size = 0;
- list_for_each_entry(pdo, &sync->pdos, list) {
- list_for_each_entry(pdo_entry, &pdo->entries, list) {
- bit_size += pdo_entry->bit_length;
- }
- }
-
- if (bit_size % 8) // round up to full bytes
- byte_size = bit_size / 8 + 1;
- else
- byte_size = bit_size / 8;
-
- return byte_size;
-}
-
-/*****************************************************************************/
-
-/**
- Initializes a sync manager configuration page with EEPROM data.
- The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes.
-*/
-
-void ec_sync_config(
- const ec_sync_t *sync, /**< sync manager */
- uint8_t *data /**> configuration memory */
- )
-{
- size_t sync_size = ec_sync_size(sync);
-
if (sync->slave->master->debug_level) {
EC_DBG("SM%i: Addr 0x%04X, Size %3i, Ctrl 0x%02X, En %i\n",
sync->index, sync->physical_start_address,
- sync_size, sync->control_register, sync->enable);
+ data_size, sync->control_register, sync->enable);
}
EC_WRITE_U16(data, sync->physical_start_address);
- EC_WRITE_U16(data + 2, sync_size);
+ EC_WRITE_U16(data + 2, data_size);
EC_WRITE_U8 (data + 4, sync->control_register);
EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
EC_WRITE_U16(data + 6, sync->enable ? 0x0001 : 0x0000); // enable
@@ -140,72 +98,26 @@
/*****************************************************************************/
-/**
- * Adds a PDO to the list of known mapped PDOs.
+/** Adds a PDO to the list of known mapped PDOs.
+ *
* \return 0 on success, else < 0
*/
-
int ec_sync_add_pdo(
- ec_sync_t *sync, /**< EtherCAT sync manager */
- const ec_pdo_t *pdo /**< PDO to map */
+ ec_sync_t *sync, /**< EtherCAT sync manager. */
+ const ec_pdo_t *pdo /**< PDO to map. */
)
{
- ec_pdo_t *mapped_pdo;
-
- // PDO already mapped?
- list_for_each_entry(mapped_pdo, &sync->pdos, list) {
- if (mapped_pdo->index != pdo->index) continue;
- EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
- return -1;
- }
-
- if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
- EC_ERR("Failed to allocate memory for PDO mapping.\n");
- return -1;
- }
-
- ec_pdo_init(mapped_pdo);
- if (ec_pdo_copy(mapped_pdo, pdo)) {
- ec_pdo_clear(mapped_pdo);
- kfree(mapped_pdo);
- return -1;
- }
-
- // set appropriate sync manager index
- mapped_pdo->sync_index = sync->index;
-
- list_add_tail(&mapped_pdo->list, &sync->pdos);
- return 0;
+ return ec_pdo_mapping_add_pdo(&sync->mapping, pdo);
}
/*****************************************************************************/
-/**
- * Clears the list of known mapped PDOs.
+/** Get direction covered by sync manager.
+ *
+ * \return Direction covered by the given sync manager.
*/
-
-void ec_sync_clear_pdos(
- ec_sync_t *sync /**< EtherCAT sync manager */
- )
-{
- ec_pdo_t *pdo, *next;
-
- // free all mapped PDOs
- list_for_each_entry_safe(pdo, next, &sync->pdos, list) {
- list_del(&pdo->list);
- ec_pdo_clear(pdo);
- kfree(pdo);
- }
-}
-
-/*****************************************************************************/
-
-/**
- * \return Type of PDOs covered by the given sync manager.
- */
-
-ec_pdo_type_t ec_sync_get_pdo_type(
- const ec_sync_t *sync /**< EtherCAT sync manager */
+ec_direction_t ec_sync_direction(
+ const ec_sync_t *sync /**< EtherCAT sync manager. */
)
{
int index = sync->index;
@@ -215,11 +127,11 @@
}
if (index < 0 || index > 1) {
- EC_WARN("ec_sync_get_pdo_type(): invalid sync manager index.\n");
- return EC_RX_PDO;
+ EC_WARN("ec_sync_get_direction(): invalid sync manager index.\n");
+ return EC_DIR_OUTPUT;
}
- return (ec_pdo_type_t) index;
+ return (ec_direction_t) index;
}
/*****************************************************************************/
--- a/master/sync.h Thu Feb 14 09:18:55 2008 +0000
+++ b/master/sync.h Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
*
*****************************************************************************/
-/**
- \file
- EtherCAT sync manager.
-*/
+/** \file
+ * EtherCAT sync manager.
+ */
/*****************************************************************************/
@@ -44,60 +43,46 @@
#include <linux/list.h>
#include "../include/ecrt.h"
+
#include "globals.h"
+#include "pdo_mapping.h"
/*****************************************************************************/
-/** size of a sync manager configuration page */
-#define EC_SYNC_SIZE 8
+/** EtherCAT sync manager PDO mapping information source.
+ */
+typedef enum {
+ EC_SYNC_MAPPING_NONE, /**< No PDO mapping information. */
+ EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII. */
+ EC_SYNC_MAPPING_COE, /**< PDO mapping information from CoE dictionary. */
+ EC_SYNC_MAPPING_CUSTOM, /**< PDO mapping configured externally. */
+} ec_sync_mapping_source_t;
/*****************************************************************************/
-/**
- * EtherCAT sync manager PDO mapping information source.
+/** Sync manager.
*/
-
-typedef enum {
- EC_SYNC_MAPPING_NONE, /**< No PDO mapping information */
- EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII */
- EC_SYNC_MAPPING_COE /**< PDO mapping information from CoE dictionary */
-}
-ec_sync_mapping_source_t;
-
-/*****************************************************************************/
-
-/**
- * Sync manager.
- */
-
-typedef struct
-{
- ec_slave_t *slave; /**< slave, the sync manager belongs to */
- unsigned int index; /**< sync manager index */
- uint16_t physical_start_address; /**< physical start address */
- uint16_t length; /**< data length in bytes */
- uint8_t control_register; /**< control register value */
- uint8_t enable; /**< enable bit */
-
- uint16_t est_length; /**< used to calculate the length via PDO ranges */
- struct list_head pdos; /**< list of mapped PDOs */
- unsigned int alt_mapping; /**< alternative mapping configured */
- ec_sync_mapping_source_t mapping_source; /**< pdo mapping source */
-}
-ec_sync_t;
+typedef struct {
+ ec_slave_t *slave; /**< Slave, the sync manager belongs to. */
+ unsigned int index; /**< Sync manager index. */
+ uint16_t physical_start_address; /**< Physical start address. */
+ uint16_t length; /**< Data length in bytes. */
+ uint8_t control_register; /**< Control register value. */
+ uint8_t enable; /**< Enable bit. */
+ ec_pdo_mapping_t mapping; /**< Current Pdo mapping. */
+ ec_sync_mapping_source_t mapping_source; /**< Pdo mapping source. */
+} ec_sync_t;
/*****************************************************************************/
void ec_sync_init(ec_sync_t *, ec_slave_t *, unsigned int);
void ec_sync_clear(ec_sync_t *);
-uint16_t ec_sync_size(const ec_sync_t *);
-void ec_sync_config(const ec_sync_t *, uint8_t *);
+void ec_sync_config(const ec_sync_t *, uint16_t, uint8_t *);
int ec_sync_add_pdo(ec_sync_t *, const ec_pdo_t *);
-void ec_sync_clear_pdos(ec_sync_t *);
-ec_pdo_type_t ec_sync_get_pdo_type(const ec_sync_t *);
+ec_direction_t ec_sync_direction(const ec_sync_t *);
/*****************************************************************************/