From 86788b42bc8070b368d742786b6b8f8b5ecfd0e1 Mon Sep 17 00:00:00 2001
From: Florian Pose <fp@igh-essen.com>
Date: Wed, 11 Jun 2008 15:29:47 +0000
Subject: [PATCH] Bus configuration via 'ethercat config'.

---
 TODO                  |   4 +-
 master/cdev.c         | 202 +++++++++++++++++++++++++++++++++++++++---
 master/ioctl.h        | 123 ++++++++++++++++++-------
 master/master.c       |  34 +++++++
 master/master.h       |   3 +
 master/slave_config.c |  40 +++++++++
 master/slave_config.h |   4 +
 tools/Master.cpp      | 166 +++++++++++++++++++++++++++++++++-
 tools/Master.h        |   8 +-
 tools/main.cpp        |   3 +
 10 files changed, 537 insertions(+), 50 deletions(-)

diff --git a/TODO b/TODO
index ccbb6020..ac87449b 100644
--- a/TODO
+++ b/TODO
@@ -8,8 +8,6 @@ $Id$
 
 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 @@ Version 1.4.0:
 * 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:
 
diff --git a/master/cdev.c b/master/cdev.c
index dbdbe1da..699145de 100644
--- a/master/cdev.c
+++ b/master/cdev.c
@@ -148,6 +148,7 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
                 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 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;
     }
diff --git a/master/ioctl.h b/master/ioctl.h
index bc1b1b77..63c0ca3e 100644
--- a/master/ioctl.h
+++ b/master/ioctl.h
@@ -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 @@ typedef struct {
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SLAVE_NAME_SIZE 77
-
 typedef struct {
     // input
     uint16_t position;
@@ -113,7 +118,7 @@ typedef struct {
     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 @@ typedef struct {
 
 /*****************************************************************************/
 
-#define EC_IOCTL_PDO_NAME_SIZE 114
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -146,13 +149,11 @@ typedef struct {
     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 @@ typedef struct {
     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 @@ typedef struct {
     // inputs
 	uint32_t domain_index;
     uint32_t data_size;
-    unsigned char *target;
+    uint8_t *target;
 } ec_ioctl_data_t;
 
 /*****************************************************************************/
@@ -215,8 +216,6 @@ typedef struct {
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SDO_NAME_SIZE 121
-
 typedef struct {
     // inputs
     uint16_t slave_position;
@@ -225,13 +224,11 @@ typedef struct {
     // 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 @@ typedef struct {
     // 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 {
 
 /*****************************************************************************/
 
+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
diff --git a/master/master.c b/master/master.c
index 6d8edcca..8dd0c566 100644
--- a/master/master.c
+++ b/master/master.c
@@ -1101,6 +1101,40 @@ ec_slave_t *ec_master_find_slave(
 
 /*****************************************************************************/
 
+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. */
 		)
diff --git a/master/master.h b/master/master.h
index 8be5d3f9..9b4a2548 100644
--- a/master/master.h
+++ b/master/master.h
@@ -197,6 +197,9 @@ void ec_master_clear_eoe_handlers(ec_master_t *);
 #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);
 
diff --git a/master/slave_config.c b/master/slave_config.c
index 94b4f18b..78d67c59 100644
--- a/master/slave_config.c
+++ b/master/slave_config.c
@@ -462,6 +462,46 @@ void ec_slave_config_load_default_mapping(
     }
 }
 
+/*****************************************************************************/
+
+/**
+ */
+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
  *****************************************************************************/
diff --git a/master/slave_config.h b/master/slave_config.h
index d9f36632..a9c71ea4 100644
--- a/master/slave_config.h
+++ b/master/slave_config.h
@@ -91,6 +91,10 @@ void ec_slave_config_load_default_assignment(ec_slave_config_t *);
 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
diff --git a/tools/Master.cpp b/tools/Master.cpp
index f0d1005f..95556f01 100644
--- a/tools/Master.cpp
+++ b/tools/Master.cpp
@@ -171,6 +171,94 @@ void Master::writeAlias(
     }
 }
 
+/*****************************************************************************/
+
+/**
+ * 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 @@ void Master::listSlavePdos(
 
                 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 @@ void Master::showSlave(uint16_t slavePosition)
             << "    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::getMaster(ec_ioctl_master_t *data)
 
 /****************************************************************************/
 
+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;
diff --git a/tools/Master.h b/tools/Master.h
index b8818bb3..c7618545 100644
--- a/tools/Master.h
+++ b/tools/Master.h
@@ -42,6 +42,7 @@ class Master
         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 @@ class Master
         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,
diff --git a/tools/main.cpp b/tools/main.cpp
index 14c02b8e..b9f5685c 100644
--- a/tools/main.cpp
+++ b/tools/main.cpp
@@ -34,6 +34,7 @@ void printUsage()
         << "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 @@ int main(int argc, char **argv)
 
         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") {
-- 
GitLab