Bus configuration via 'ethercat config'.
authorFlorian Pose <fp@igh-essen.com>
Wed, 11 Jun 2008 15:29:47 +0000
changeset 990 4f223f3df05a
parent 989 816663ca9370
child 991 2548ca639b1f
Bus configuration via 'ethercat config'.
TODO
master/cdev.c
master/ioctl.h
master/master.c
master/master.h
master/slave_config.c
master/slave_config.h
tools/Master.cpp
tools/Master.h
tools/main.cpp
--- a/TODO	Wed Jun 11 13:01:21 2008 +0000
+++ b/TODO	Wed Jun 11 15:29:47 2008 +0000
@@ -8,8 +8,6 @@
 
 Version 1.4.0:
 
-* Replace all Sysfs files via the new ethercat tool.
-    - Config info (alias, position, type, Pdos, Sdos)
 * Slaves as array.
 * Remove the end state of the master state machine.
 * Supply new ec_master_state_t.
@@ -25,6 +23,8 @@
 * Attach Pdo names from SII or Coe dictioary to Pdos read via CoE.
 * Make scanning and configuration run parallel (each).
 * List of commands that require a slave.
+* Remove configs_attached flag.
+* Remove EC_IOCTL_DOMAIN_COUNT.
 
 Future issues:
 
--- a/master/cdev.c	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/cdev.c	Wed Jun 11 15:29:47 2008 +0000
@@ -148,6 +148,7 @@
                 ec_ioctl_master_t data;
 
                 data.slave_count = master->slave_count;
+                data.config_count = ec_master_config_count(master);
                 data.mode = (uint8_t) master->mode;
                 
                 memcpy(data.devices[0].address, master->main_mac, ETH_ALEN); 
@@ -210,8 +211,8 @@
 
                 if (slave->sii.name) {
                     strncpy(data.name, slave->sii.name,
-                            EC_IOCTL_SLAVE_NAME_SIZE);
-                    data.name[EC_IOCTL_SLAVE_NAME_SIZE - 1] = 0;
+                            EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
                 } else {
                     data.name[0] = 0;
                 }
@@ -306,8 +307,8 @@
                 data.entry_count = ec_pdo_entry_count(pdo);
 
                 if (pdo->name) {
-                    strncpy(data.name, pdo->name, EC_IOCTL_PDO_NAME_SIZE);
-                    data.name[EC_IOCTL_PDO_NAME_SIZE - 1] = 0;
+                    strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
                 } else {
                     data.name[0] = 0;
                 }
@@ -369,9 +370,8 @@
                 data.subindex = entry->subindex;
                 data.bit_length = entry->bit_length;
                 if (entry->name) {
-                    strncpy(data.name, entry->name,
-                            EC_IOCTL_PDO_ENTRY_NAME_SIZE);
-                    data.name[EC_IOCTL_PDO_ENTRY_NAME_SIZE - 1] = 0;
+                    strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
                 } else {
                     data.name[0] = 0;
                 }
@@ -546,8 +546,8 @@
                 data.max_subindex = sdo->max_subindex;
 
                 if (sdo->name) {
-                    strncpy(data.name, sdo->name, EC_IOCTL_SDO_NAME_SIZE);
-                    data.name[EC_IOCTL_SDO_NAME_SIZE - 1] = 0;
+                    strncpy(data.name, sdo->name, EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
                 } else {
                     data.name[0] = 0;
                 }
@@ -610,8 +610,8 @@
 
                 if (entry->description) {
                     strncpy(data.description, entry->description,
-                            EC_IOCTL_SDO_ENTRY_DESCRIPTION_SIZE);
-                    data.description[EC_IOCTL_SDO_ENTRY_DESCRIPTION_SIZE - 1]
+                            EC_IOCTL_STRING_SIZE);
+                    data.description[EC_IOCTL_STRING_SIZE - 1]
                         = 0;
                 } else {
                     data.description[0] = 0;
@@ -853,6 +853,186 @@
                 break;
             }
 
+        case EC_IOCTL_CONFIG:
+            {
+                ec_ioctl_config_t data;
+                const ec_slave_config_t *sc;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(sc = ec_master_get_config_const(
+                                master, data.config_index))) {
+                    EC_ERR("Slave config %u does not exist!\n",
+                            data.config_index);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.alias = sc->alias;
+                data.position = sc->position;
+                data.vendor_id = sc->vendor_id;
+                data.product_code = sc->product_code;
+                data.pdo_count[EC_DIR_OUTPUT] =
+                    ec_pdo_list_count(&sc->pdos[EC_DIR_OUTPUT]);
+                data.pdo_count[EC_DIR_INPUT] =
+                    ec_pdo_list_count(&sc->pdos[EC_DIR_INPUT]);
+                data.sdo_count = ec_slave_config_sdo_count(sc);
+                data.attached = sc->slave != NULL;
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
+        case EC_IOCTL_CONFIG_PDO:
+            {
+                ec_ioctl_config_pdo_t data;
+                const ec_slave_config_t *sc;
+                const ec_pdo_t *pdo;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(sc = ec_master_get_config_const(
+                                master, data.config_index))) {
+                    EC_ERR("Slave config %u does not exist!\n",
+                            data.config_index);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (data.direction > EC_DIR_INPUT) {
+                    EC_ERR("Invalid direction %u!\n", data.direction);
+                    retval = -EINVAL;
+                    break;
+                }
+                
+                if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
+                                &sc->pdos[data.direction], data.pdo_pos))) {
+                    EC_ERR("Invalid Pdo position!\n");
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.index = pdo->index;
+                data.entry_count = ec_pdo_entry_count(pdo);
+
+                if (pdo->name) {
+                    strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
+                } else {
+                    data.name[0] = 0;
+                }
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
+        case EC_IOCTL_CONFIG_PDO_ENTRY:
+            {
+                ec_ioctl_config_pdo_entry_t data;
+                const ec_slave_config_t *sc;
+                const ec_pdo_t *pdo;
+                const ec_pdo_entry_t *entry;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(sc = ec_master_get_config_const(
+                                master, data.config_index))) {
+                    EC_ERR("Slave config %u does not exist!\n",
+                            data.config_index);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (data.direction > EC_DIR_INPUT) {
+                    EC_ERR("Invalid direction %u!\n", data.direction);
+                    retval = -EINVAL;
+                    break;
+                }
+                
+                if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
+                                &sc->pdos[data.direction], data.pdo_pos))) {
+                    EC_ERR("Invalid Pdo position!\n");
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (!(entry = ec_pdo_find_entry_by_pos_const(
+                                pdo, data.entry_pos))) {
+                    EC_ERR("Entry not found!\n");
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.index = entry->index;
+                data.subindex = entry->subindex;
+                data.bit_length = entry->bit_length;
+                if (entry->name) {
+                    strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE);
+                    data.name[EC_IOCTL_STRING_SIZE - 1] = 0;
+                } else {
+                    data.name[0] = 0;
+                }
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
+        case EC_IOCTL_CONFIG_SDO:
+            {
+                ec_ioctl_config_sdo_t data;
+                const ec_slave_config_t *sc;
+                const ec_sdo_request_t *req;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(sc = ec_master_get_config_const(
+                                master, data.config_index))) {
+                    EC_ERR("Slave config %u does not exist!\n",
+                            data.config_index);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (!(req = ec_slave_config_get_sdo_by_pos_const(
+                                sc, data.sdo_pos))) {
+                    EC_ERR("Invalid Sdo position!\n");
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.index = req->index;
+                data.subindex = req->subindex;
+                data.size = req->data_size;
+                memcpy(&data.data, req->data, min((u32) data.size, (u32) 4));
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
         default:
             retval = -ENOTTY;
     }
--- a/master/ioctl.h	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/ioctl.h	Wed Jun 11 15:29:47 2008 +0000
@@ -54,28 +54,35 @@
 #define EC_IOW(nr,type)   _IOW(EC_IOCTL_TYPE,nr,type)
 #define EC_IOWR(nr,type) _IOWR(EC_IOCTL_TYPE,nr,type)
 
-#define EC_IOCTL_MASTER        EC_IOR(0x00, ec_ioctl_master_t)
-#define EC_IOCTL_SLAVE        EC_IOWR(0x01, ec_ioctl_slave_t)
-#define EC_IOCTL_SYNC         EC_IOWR(0x02, ec_ioctl_sync_t)
-#define EC_IOCTL_PDO          EC_IOWR(0x03, ec_ioctl_pdo_t)
-#define EC_IOCTL_PDO_ENTRY    EC_IOWR(0x04, ec_ioctl_pdo_entry_t)
-#define EC_IOCTL_DOMAIN_COUNT   EC_IO(0x05)
-#define EC_IOCTL_DOMAIN       EC_IOWR(0x06, ec_ioctl_domain_t)
-#define EC_IOCTL_DOMAIN_FMMU  EC_IOWR(0x07, ec_ioctl_domain_fmmu_t)
-#define EC_IOCTL_DATA         EC_IOWR(0x08, ec_ioctl_data_t)
-#define EC_IOCTL_SET_DEBUG      EC_IO(0x09)
-#define EC_IOCTL_SLAVE_STATE   EC_IOW(0x0a, ec_ioctl_slave_state_t)
-#define EC_IOCTL_SDO          EC_IOWR(0x0b, ec_ioctl_sdo_t)
-#define EC_IOCTL_SDO_ENTRY    EC_IOWR(0x0c, ec_ioctl_sdo_entry_t)
-#define EC_IOCTL_SDO_UPLOAD   EC_IOWR(0x0d, ec_ioctl_sdo_upload_t)
-#define EC_IOCTL_SDO_DOWNLOAD  EC_IOW(0x0e, ec_ioctl_sdo_download_t)
-#define EC_IOCTL_SII_READ     EC_IOWR(0x0f, ec_ioctl_sii_t)
-#define EC_IOCTL_SII_WRITE     EC_IOW(0x10, ec_ioctl_sii_t)
+#define EC_IOCTL_MASTER            EC_IOR(0x00, ec_ioctl_master_t)
+#define EC_IOCTL_SLAVE            EC_IOWR(0x01, ec_ioctl_slave_t)
+#define EC_IOCTL_SYNC             EC_IOWR(0x02, ec_ioctl_sync_t)
+#define EC_IOCTL_PDO              EC_IOWR(0x03, ec_ioctl_pdo_t)
+#define EC_IOCTL_PDO_ENTRY        EC_IOWR(0x04, ec_ioctl_pdo_entry_t)
+#define EC_IOCTL_DOMAIN_COUNT       EC_IO(0x05)
+#define EC_IOCTL_DOMAIN           EC_IOWR(0x06, ec_ioctl_domain_t)
+#define EC_IOCTL_DOMAIN_FMMU      EC_IOWR(0x07, ec_ioctl_domain_fmmu_t)
+#define EC_IOCTL_DATA             EC_IOWR(0x08, ec_ioctl_data_t)
+#define EC_IOCTL_SET_DEBUG          EC_IO(0x09)
+#define EC_IOCTL_SLAVE_STATE       EC_IOW(0x0a, ec_ioctl_slave_state_t)
+#define EC_IOCTL_SDO              EC_IOWR(0x0b, ec_ioctl_sdo_t)
+#define EC_IOCTL_SDO_ENTRY        EC_IOWR(0x0c, ec_ioctl_sdo_entry_t)
+#define EC_IOCTL_SDO_UPLOAD       EC_IOWR(0x0d, ec_ioctl_sdo_upload_t)
+#define EC_IOCTL_SDO_DOWNLOAD      EC_IOW(0x0e, ec_ioctl_sdo_download_t)
+#define EC_IOCTL_SII_READ         EC_IOWR(0x0f, ec_ioctl_sii_t)
+#define EC_IOCTL_SII_WRITE         EC_IOW(0x10, ec_ioctl_sii_t)
+#define EC_IOCTL_CONFIG           EC_IOWR(0x11, ec_ioctl_config_t)
+#define EC_IOCTL_CONFIG_PDO       EC_IOWR(0x12, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x12, ec_ioctl_config_pdo_entry_t)
+#define EC_IOCTL_CONFIG_SDO       EC_IOWR(0x13, ec_ioctl_config_sdo_t)
+
+#define EC_IOCTL_STRING_SIZE 64
 
 /*****************************************************************************/
 
 typedef struct {
     uint32_t slave_count;
+    uint32_t config_count;
     uint8_t mode;
     struct {
         uint8_t address[6];
@@ -87,8 +94,6 @@
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SLAVE_NAME_SIZE 77
-
 typedef struct {
     // input
     uint16_t position;
@@ -113,7 +118,7 @@
     uint8_t sync_count;
     uint16_t sdo_count;
     uint32_t sii_nwords;
-    char name[EC_IOCTL_SLAVE_NAME_SIZE];
+    char name[EC_IOCTL_STRING_SIZE];
 } ec_ioctl_slave_t;
 
 /*****************************************************************************/
@@ -134,8 +139,6 @@
 
 /*****************************************************************************/
 
-#define EC_IOCTL_PDO_NAME_SIZE 114
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -146,13 +149,11 @@
     uint8_t dir;
     uint16_t index;
     uint8_t entry_count;
-    char name[EC_IOCTL_PDO_NAME_SIZE];
+    int8_t name[EC_IOCTL_STRING_SIZE];
 } ec_ioctl_pdo_t;
 
 /*****************************************************************************/
 
-#define EC_IOCTL_PDO_ENTRY_NAME_SIZE 110
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -164,7 +165,7 @@
     uint16_t index;
     uint8_t subindex;
     uint8_t bit_length;
-    char name[EC_IOCTL_PDO_NAME_SIZE];
+    int8_t name[EC_IOCTL_STRING_SIZE];
 } ec_ioctl_pdo_entry_t;
 
 /*****************************************************************************/
@@ -202,7 +203,7 @@
     // inputs
 	uint32_t domain_index;
     uint32_t data_size;
-    unsigned char *target;
+    uint8_t *target;
 } ec_ioctl_data_t;
 
 /*****************************************************************************/
@@ -215,8 +216,6 @@
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SDO_NAME_SIZE 121
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -225,13 +224,11 @@
     // outputs
     uint16_t sdo_index;
     uint8_t max_subindex;
-    char name[EC_IOCTL_SDO_NAME_SIZE];
+    int8_t name[EC_IOCTL_STRING_SIZE];
 } ec_ioctl_sdo_t;
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SDO_ENTRY_DESCRIPTION_SIZE 120
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -241,7 +238,7 @@
     // outputs
     uint16_t data_type;
     uint16_t bit_length;
-    char description[EC_IOCTL_SDO_ENTRY_DESCRIPTION_SIZE];
+    int8_t description[EC_IOCTL_STRING_SIZE];
 } ec_ioctl_sdo_entry_t;
 
 /*****************************************************************************/
@@ -281,4 +278,64 @@
 
 /*****************************************************************************/
 
+typedef struct {
+    // inputs
+    uint32_t config_index;
+
+    // outputs
+    uint16_t alias;
+    uint16_t position;
+    uint32_t vendor_id;
+    uint32_t product_code;
+    uint32_t pdo_count[2];
+    uint32_t sdo_count;
+    uint8_t attached;
+} ec_ioctl_config_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
+    uint32_t direction;
+    uint32_t pdo_pos;
+
+    // outputs
+    uint16_t index;
+    uint8_t entry_count;
+    int8_t name[EC_IOCTL_STRING_SIZE];
+} ec_ioctl_config_pdo_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
+    uint32_t direction;
+    uint32_t pdo_pos;
+    uint32_t entry_pos;
+
+    // outputs
+    uint16_t index;
+    uint8_t subindex;
+    uint8_t bit_length;
+    int8_t name[EC_IOCTL_STRING_SIZE];
+} ec_ioctl_config_pdo_entry_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
+    uint32_t sdo_pos;
+
+    // outputs
+    uint16_t index;
+    uint8_t subindex;
+    uint32_t size;
+    uint8_t data[4];
+} ec_ioctl_config_sdo_t;
+
+/*****************************************************************************/
+
 #endif
--- a/master/master.c	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/master.c	Wed Jun 11 15:29:47 2008 +0000
@@ -1101,6 +1101,40 @@
 
 /*****************************************************************************/
 
+unsigned int ec_master_config_count(
+		const ec_master_t *master /**< EtherCAT master. */
+		)
+{
+	const ec_slave_config_t *sc;
+	unsigned int count = 0;
+
+	list_for_each_entry(sc, &master->configs, list) {
+		count++;
+	}
+
+	return count;
+}
+
+/*****************************************************************************/
+
+const ec_slave_config_t *ec_master_get_config_const(
+		const ec_master_t *master, /**< EtherCAT master. */
+		unsigned int index /**< List position. */
+		)
+{
+	const ec_slave_config_t *sc;
+
+	list_for_each_entry(sc, &master->configs, list) {
+		if (index--)
+			continue;
+		return sc;
+	}
+
+	return NULL;
+}
+
+/*****************************************************************************/
+
 unsigned int ec_master_domain_count(
 		const ec_master_t *master /**< EtherCAT master. */
 		)
--- a/master/master.h	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/master.h	Wed Jun 11 15:29:47 2008 +0000
@@ -197,6 +197,9 @@
 #endif
 void ec_master_destroy_slaves(ec_master_t *);
 
+unsigned int ec_master_config_count(const ec_master_t *);
+const ec_slave_config_t *ec_master_get_config_const(
+        const ec_master_t *, unsigned int);
 unsigned int ec_master_domain_count(const ec_master_t *);
 ec_domain_t *ec_master_find_domain(ec_master_t *, unsigned int);
 
--- a/master/slave_config.c	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/slave_config.c	Wed Jun 11 15:29:47 2008 +0000
@@ -462,6 +462,46 @@
     }
 }
 
+/*****************************************************************************/
+
+/**
+ */
+unsigned int ec_slave_config_sdo_count(
+        const ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+	const ec_sdo_request_t *req;
+	unsigned int count = 0;
+
+	list_for_each_entry(req, &sc->sdo_configs, list) {
+		count++;
+	}
+
+	return count;
+}
+
+/*****************************************************************************/
+
+/** Finds an Sdo configuration via its position in the list.
+ *
+ * Const version.
+ */
+const ec_sdo_request_t *ec_slave_config_get_sdo_by_pos_const(
+        const ec_slave_config_t *sc, /**< Slave configuration. */
+        unsigned int pos /**< Position in the list. */
+        )
+{
+    const ec_sdo_request_t *req;
+
+    list_for_each_entry(req, &sc->sdo_configs, list) {
+        if (pos--)
+            continue;
+        return req;
+    }
+
+    return NULL;
+}
+
 /******************************************************************************
  *  Realtime interface
  *****************************************************************************/
--- a/master/slave_config.h	Wed Jun 11 13:01:21 2008 +0000
+++ b/master/slave_config.h	Wed Jun 11 15:29:47 2008 +0000
@@ -91,6 +91,10 @@
 void ec_slave_config_load_default_mapping(const ec_slave_config_t *,
         ec_pdo_t *);
 
+unsigned int ec_slave_config_sdo_count(const ec_slave_config_t *);
+const ec_sdo_request_t *ec_slave_config_get_sdo_by_pos_const(
+        const ec_slave_config_t *, unsigned int);
+
 /*****************************************************************************/
 
 #endif
--- a/tools/Master.cpp	Wed Jun 11 13:01:21 2008 +0000
+++ b/tools/Master.cpp	Wed Jun 11 15:29:47 2008 +0000
@@ -171,6 +171,94 @@
     }
 }
 
+/*****************************************************************************/
+
+/**
+ * Lists the bus configuration.
+ */
+void Master::showConfig()
+{
+    ec_ioctl_master_t master;
+    unsigned int i, j, k, l;
+    ec_ioctl_config_t config;
+    ec_ioctl_config_pdo_t pdo;
+    ec_ioctl_config_pdo_entry_t entry;
+    ec_ioctl_config_sdo_t sdo;
+
+    open(Read);
+    getMaster(&master);
+
+    for (i = 0; i < master.config_count; i++) {
+        getConfig(&config, i);
+
+        cout << "Alias: 0x"
+            << hex << setfill('0') << setw(4) << config.alias << endl
+            << "Position: " << dec << config.position << endl
+            << "Vendor Id: 0x"
+            << hex << setw(8) << config.vendor_id << endl
+            << "Product code: 0x"
+            << hex << setw(8) << config.product_code << endl
+            << "Attached: " << (config.attached ? "yes" : "no") << endl;
+
+        for (j = 0; j < 2; j++) {
+            if (config.pdo_count[j]) {
+                cout << (j ? "Input" : "Output")
+                    << " Pdo assignment / mapping " << endl;
+                for (k = 0; k < config.pdo_count[j]; k++) {
+                    getConfigPdo(&pdo, i, j, k);
+
+                    cout << "  Pdo 0x"
+                        << hex << setfill('0') << setw(4) << pdo.index
+                        << " \"" << pdo.name << "\"" << endl;
+
+                    for (l = 0; l < pdo.entry_count; l++) {
+                        getConfigPdoEntry(&entry, i, j, k, l);
+
+                        cout << "    Pdo entry 0x"
+                            << hex << setfill('0') << setw(4) << entry.index
+                            << ":" << setw(2) << (unsigned int) entry.subindex
+                            << ", " << dec << (unsigned int) entry.bit_length
+                            << " bit, \"" << entry.name << "\"" << endl;
+                    }
+                }
+            }
+        }
+
+        if (config.sdo_count) {
+            cout << "Sdo configuration:" << endl;
+            for (j = 0; j < config.sdo_count; j++) {
+                getConfigSdo(&sdo, i, j);
+
+                cout << "  0x"
+                    << hex << setfill('0') << setw(4) << sdo.index
+                    << ":" << setw(2) << (unsigned int) sdo.subindex
+                    << ", " << sdo.size << " byte: " << hex;
+
+                switch (sdo.size) {
+                    case 1:
+                        cout << "0x" << setw(2)
+                            << (unsigned int) *(uint8_t *) &sdo.data;
+                        break;
+                    case 2:
+                        cout << "0x" << setw(4)
+                            << le16tocpu(*(uint16_t *) &sdo.data);
+                        break;
+                    case 4:
+                        cout << "0x" << setw(8)
+                            << le32tocpu(*(uint32_t *) &sdo.data);
+                        break;
+                    default:
+                        cout << "???";
+                }
+
+                cout << endl;
+            }
+        }
+
+        cout << endl;
+    }
+}
+
 /****************************************************************************/
 
 void Master::outputData(int domainIndex)
@@ -1156,8 +1244,7 @@
 
                 cout << "    Pdo entry 0x"
                     << hex << setfill('0') << setw(4) << entry.index
-                    << ":" << hex << setfill('0') << setw(2)
-                    << (unsigned int) entry.subindex
+                    << ":" << setw(2) << (unsigned int) entry.subindex
                     << ", " << dec << (unsigned int) entry.bit_length
                     << " bit, \"" << entry.name << "\"" << endl;
             }
@@ -1306,7 +1393,7 @@
             << "    Enable notLRW: "
             << (slave.general_flags.enable_not_lrw ? "yes" : "no") << endl
             << "  Current consumption: "
-            << dec << slave.current_on_ebus << " mA" << endl << sizeof(slave);
+            << dec << slave.current_on_ebus << " mA" << endl;
     }
     cout << endl;
 }
@@ -1447,6 +1534,79 @@
 
 /****************************************************************************/
 
+void Master::getConfig(ec_ioctl_config_t *data, unsigned int index)
+{
+    data->config_index = index;
+
+    if (ioctl(fd, EC_IOCTL_CONFIG, data) < 0) {
+        stringstream err;
+        err << "Failed to get slave configuration: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getConfigPdo(
+        ec_ioctl_config_pdo_t *data,
+        unsigned int index,
+        unsigned int dir,
+        unsigned int pdo_pos
+        )
+{
+    data->config_index = index;
+    data->direction = dir;
+    data->pdo_pos = pdo_pos;
+
+    if (ioctl(fd, EC_IOCTL_CONFIG_PDO, data) < 0) {
+        stringstream err;
+        err << "Failed to get slave config Pdo: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getConfigPdoEntry(
+        ec_ioctl_config_pdo_entry_t *data,
+        unsigned int index,
+        unsigned int dir,
+        unsigned int pdo_pos,
+        unsigned int entry_pos
+        )
+{
+    data->config_index = index;
+    data->direction = dir;
+    data->pdo_pos = pdo_pos;
+    data->entry_pos = entry_pos;
+
+    if (ioctl(fd, EC_IOCTL_CONFIG_PDO_ENTRY, data) < 0) {
+        stringstream err;
+        err << "Failed to get slave config Pdo entry: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getConfigSdo(
+        ec_ioctl_config_sdo_t *data,
+        unsigned int index,
+        unsigned int sdo_pos
+        )
+{
+    data->config_index = index;
+    data->sdo_pos = sdo_pos;
+
+    if (ioctl(fd, EC_IOCTL_CONFIG_SDO, data) < 0) {
+        stringstream err;
+        err << "Failed to get slave config Sdo: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
 void Master::getDomain(ec_ioctl_domain_t *data, unsigned int index)
 {
     data->index = index;
--- a/tools/Master.h	Wed Jun 11 13:01:21 2008 +0000
+++ b/tools/Master.h	Wed Jun 11 15:29:47 2008 +0000
@@ -42,6 +42,7 @@
         void setIndex(unsigned int);
 
         void writeAlias(int, bool, const vector<string> &);
+        void showConfig();
         void outputData(int);
         void setDebug(const vector<string> &);
         void showDomains(int);
@@ -72,7 +73,12 @@
         unsigned int domainCount();
         unsigned int slaveCount();
         void getMaster(ec_ioctl_master_t *);
-        void slaveSyncs(uint16_t);
+        void getConfig(ec_ioctl_config_t *, unsigned int);
+        void getConfigPdo(ec_ioctl_config_pdo_t *, unsigned int,
+                unsigned int, unsigned int);
+        void getConfigPdoEntry(ec_ioctl_config_pdo_entry_t *, unsigned int,
+                unsigned int, unsigned int, unsigned int);
+        void getConfigSdo(ec_ioctl_config_sdo_t *, unsigned int, unsigned int);
         void getDomain(ec_ioctl_domain_t *, unsigned int);
         void getFmmu(ec_ioctl_domain_fmmu_t *, unsigned int, unsigned int);
         void getData(ec_ioctl_data_t *, unsigned int, unsigned int,
--- a/tools/main.cpp	Wed Jun 11 13:01:21 2008 +0000
+++ b/tools/main.cpp	Wed Jun 11 15:29:47 2008 +0000
@@ -34,6 +34,7 @@
         << "Usage: ethercat <COMMAND> [OPTIONS]" << endl
 		<< "Commands:" << endl
         << "  alias              Write alias address(es)." << endl
+        << "  config             Show slave configurations." << endl
         << "  data               Output binary domain process data." << endl
         << "  debug              Set the master debug level." << endl
         << "  domain             Show domain information." << endl
@@ -178,6 +179,8 @@
 
         if (command == "alias") {
             master.writeAlias(slavePosition, force, commandArgs);
+        } else if (command == "config") {
+            master.showConfig();
         } else if (command == "data") {
             master.outputData(domainIndex);
         } else if (command == "debug") {