Multi-master support for command-line tool. The --master option supports
authorFlorian Pose <fp@igh-essen.com>
Wed, 24 Feb 2010 16:27:11 +0100
changeset 1826 ec6223c3b7ec
parent 1825 65781b048a47
child 1827 489be2180f71
Multi-master support for command-line tool. The --master option supports
ranges like '1-3,6,7-9'. The ioctl() interface version is checked.
NEWS
TODO
lib/common.c
master/cdev.c
master/globals.h
master/ioctl.h
master/module.c
tool/Command.cpp
tool/Command.h
tool/CommandAlias.cpp
tool/CommandAlias.h
tool/CommandCStruct.cpp
tool/CommandCStruct.h
tool/CommandConfig.cpp
tool/CommandConfig.h
tool/CommandData.cpp
tool/CommandData.h
tool/CommandDebug.cpp
tool/CommandDebug.h
tool/CommandDomains.cpp
tool/CommandDomains.h
tool/CommandDownload.cpp
tool/CommandDownload.h
tool/CommandEoe.cpp
tool/CommandEoe.h
tool/CommandFoeRead.cpp
tool/CommandFoeRead.h
tool/CommandFoeWrite.cpp
tool/CommandFoeWrite.h
tool/CommandGraph.cpp
tool/CommandGraph.h
tool/CommandMaster.cpp
tool/CommandMaster.h
tool/CommandPdos.cpp
tool/CommandPdos.h
tool/CommandRegRead.cpp
tool/CommandRegRead.h
tool/CommandRegWrite.cpp
tool/CommandRegWrite.h
tool/CommandSdos.cpp
tool/CommandSdos.h
tool/CommandSiiRead.cpp
tool/CommandSiiRead.h
tool/CommandSiiWrite.cpp
tool/CommandSiiWrite.h
tool/CommandSlaves.cpp
tool/CommandSlaves.h
tool/CommandStates.cpp
tool/CommandStates.h
tool/CommandUpload.cpp
tool/CommandUpload.h
tool/CommandVersion.cpp
tool/CommandVersion.h
tool/CommandXml.cpp
tool/CommandXml.h
tool/Makefile.am
tool/MasterDevice.cpp
tool/MasterDevice.h
tool/NumberListParser.cpp
tool/NumberListParser.h
tool/main.cpp
--- a/NEWS	Tue Feb 23 17:40:46 2010 +0100
+++ b/NEWS	Wed Feb 24 16:27:11 2010 +0100
@@ -65,6 +65,8 @@
 * Significantly improved EoE bandwidth by running EoE processing in a kthread.
 * Switched version control from Subversion to Mercurial.
 * Implemented CompleteAccess for SDO downloads.
+* ethercat tool is now able to handle multiple masters. The --masters option
+  supports ranges like '0,3,8-10'.
 
 Changes in 1.4.0:
 
--- a/TODO	Tue Feb 23 17:40:46 2010 +0100
+++ b/TODO	Wed Feb 24 16:27:11 2010 +0100
@@ -38,7 +38,6 @@
 * Remove default buffer size in SDO upload.
 * Improve application-triggered SDO transfers by moving the state machine into
   the SDO handlers.
-* Check for ioctl() interface version.
 * Remove allow_scanning flag.
 * Override sync manager size?
 * Show Record / Array / List type of SDOs.
@@ -71,6 +70,7 @@
     - Data type abbreviations.
     - Add a -n (numeric) switch.
 	- Check for unwanted options.
+    - Implement ranges for slaves, domains, etc.
 * Simplify master fsm by introducing a common request state to handle external
   requests (replace write_sii, sdo_request, etc).
 
--- a/lib/common.c	Tue Feb 23 17:40:46 2010 +0100
+++ b/lib/common.c	Wed Feb 24 16:27:11 2010 +0100
@@ -71,7 +71,8 @@
 ec_master_t *ecrt_open_master(unsigned int master_index)
 {
     char path[MAX_PATH_LEN];
-    ec_master_t *master;
+    ec_master_t *master = NULL;
+    ec_ioctl_module_t module_data;
 
     master = malloc(sizeof(ec_master_t));
     if (!master) {
@@ -87,11 +88,30 @@
     master->fd = open(path, O_RDWR);
     if (master->fd == -1) {
         fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
-        free(master);
-        return 0;
+        goto out_free;
+    }
+
+    if (ioctl(master->fd, EC_IOCTL_MODULE, &module_data) < 0) {
+        fprintf(stderr, "Failed to get module information from %s: %s\n",
+                path, strerror(errno));
+        goto out_close;
+    }
+
+    if (module_data.ioctl_version_magic != EC_IOCTL_VERSION_MAGIC) {
+        fprintf(stderr, "ioctl() version magic is differing:"
+                " %s: %u, libethercat: %u.\n",
+                path, module_data.ioctl_version_magic,
+                EC_IOCTL_VERSION_MAGIC);
+        goto out_close;
     }
 
     return master;
+
+out_close:
+    close(master->fd);
+out_free:
+    free(master);
+    return 0;
 }
 
 /*****************************************************************************/
--- a/master/cdev.c	Tue Feb 23 17:40:46 2010 +0100
+++ b/master/cdev.c	Wed Feb 24 16:27:11 2010 +0100
@@ -157,6 +157,25 @@
 
 /*****************************************************************************/
 
+/** Get module information.
+ */
+int ec_cdev_ioctl_module(
+        unsigned long arg /**< Userspace address to store the results. */
+        )
+{
+    ec_ioctl_module_t data;
+
+    data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC;
+    data.master_count = ec_master_count();
+
+    if (copy_to_user((void __user *) arg, &data, sizeof(data)))
+        return -EFAULT;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 /** Get master information.
  */
 int ec_cdev_ioctl_master(
@@ -3281,6 +3300,8 @@
 #endif
 
     switch (cmd) {
+        case EC_IOCTL_MODULE:
+            return ec_cdev_ioctl_module(arg);
         case EC_IOCTL_MASTER:
             return ec_cdev_ioctl_master(master, arg);
         case EC_IOCTL_SLAVE:
--- a/master/globals.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/master/globals.h	Wed Feb 24 16:27:11 2010 +0100
@@ -263,6 +263,7 @@
 
 /*****************************************************************************/
 
+unsigned int ec_master_count(void);
 void ec_print_data(const uint8_t *, size_t);
 void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
 size_t ec_state_string(uint8_t, char *, uint8_t);
--- a/master/ioctl.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/master/ioctl.h	Wed Feb 24 16:27:11 2010 +0100
@@ -52,78 +52,85 @@
 #define EC_IOW(nr, type)   _IOW(EC_IOCTL_TYPE, nr, type)
 #define EC_IOWR(nr, type) _IOWR(EC_IOCTL_TYPE, nr, type)
 
+/** EtherCAT master ioctl() version magic.
+ *
+ * Increment this when changing the ioctl interface!
+ */
+#define EC_IOCTL_VERSION_MAGIC 1
+
 // Command-line tool
-#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_SLAVE_SYNC           EC_IOWR(0x02, ec_ioctl_slave_sync_t)
-#define EC_IOCTL_SLAVE_SYNC_PDO       EC_IOWR(0x03, ec_ioctl_slave_sync_pdo_t)
-#define EC_IOCTL_SLAVE_SYNC_PDO_ENTRY EC_IOWR(0x04, ec_ioctl_slave_sync_pdo_entry_t)
-#define EC_IOCTL_DOMAIN               EC_IOWR(0x05, ec_ioctl_domain_t)
-#define EC_IOCTL_DOMAIN_FMMU          EC_IOWR(0x06, ec_ioctl_domain_fmmu_t)
-#define EC_IOCTL_DOMAIN_DATA          EC_IOWR(0x07, ec_ioctl_domain_data_t)
-#define EC_IOCTL_MASTER_DEBUG           EC_IO(0x08)
-#define EC_IOCTL_SLAVE_STATE           EC_IOW(0x09, ec_ioctl_slave_state_t)
-#define EC_IOCTL_SLAVE_SDO            EC_IOWR(0x0a, ec_ioctl_slave_sdo_t)
-#define EC_IOCTL_SLAVE_SDO_ENTRY      EC_IOWR(0x0b, ec_ioctl_slave_sdo_entry_t)
-#define EC_IOCTL_SLAVE_SDO_UPLOAD     EC_IOWR(0x0c, ec_ioctl_slave_sdo_upload_t)
-#define EC_IOCTL_SLAVE_SDO_DOWNLOAD   EC_IOWR(0x0d, ec_ioctl_slave_sdo_download_t)
-#define EC_IOCTL_SLAVE_SII_READ       EC_IOWR(0x0e, ec_ioctl_slave_sii_t)
-#define EC_IOCTL_SLAVE_SII_WRITE       EC_IOW(0x0f, ec_ioctl_slave_sii_t)
-#define EC_IOCTL_SLAVE_REG_READ       EC_IOWR(0x10, ec_ioctl_slave_reg_t)
-#define EC_IOCTL_SLAVE_REG_WRITE       EC_IOW(0x11, ec_ioctl_slave_reg_t)
-#define EC_IOCTL_SLAVE_FOE_READ       EC_IOWR(0x12, ec_ioctl_slave_foe_t)
-#define EC_IOCTL_SLAVE_FOE_WRITE       EC_IOW(0x13, ec_ioctl_slave_foe_t)
-#define EC_IOCTL_CONFIG               EC_IOWR(0x14, ec_ioctl_config_t)
-#define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x15, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x16, ec_ioctl_config_pdo_entry_t)
-#define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x17, ec_ioctl_config_sdo_t)
+#define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
+#define EC_IOCTL_MASTER                EC_IOR(0x01, ec_ioctl_master_t)
+#define EC_IOCTL_SLAVE                EC_IOWR(0x02, ec_ioctl_slave_t)
+#define EC_IOCTL_SLAVE_SYNC           EC_IOWR(0x03, ec_ioctl_slave_sync_t)
+#define EC_IOCTL_SLAVE_SYNC_PDO       EC_IOWR(0x04, ec_ioctl_slave_sync_pdo_t)
+#define EC_IOCTL_SLAVE_SYNC_PDO_ENTRY EC_IOWR(0x05, ec_ioctl_slave_sync_pdo_entry_t)
+#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_DOMAIN_DATA          EC_IOWR(0x08, ec_ioctl_domain_data_t)
+#define EC_IOCTL_MASTER_DEBUG           EC_IO(0x09)
+#define EC_IOCTL_SLAVE_STATE           EC_IOW(0x0a, ec_ioctl_slave_state_t)
+#define EC_IOCTL_SLAVE_SDO            EC_IOWR(0x0b, ec_ioctl_slave_sdo_t)
+#define EC_IOCTL_SLAVE_SDO_ENTRY      EC_IOWR(0x0c, ec_ioctl_slave_sdo_entry_t)
+#define EC_IOCTL_SLAVE_SDO_UPLOAD     EC_IOWR(0x0d, ec_ioctl_slave_sdo_upload_t)
+#define EC_IOCTL_SLAVE_SDO_DOWNLOAD   EC_IOWR(0x0e, ec_ioctl_slave_sdo_download_t)
+#define EC_IOCTL_SLAVE_SII_READ       EC_IOWR(0x0f, ec_ioctl_slave_sii_t)
+#define EC_IOCTL_SLAVE_SII_WRITE       EC_IOW(0x10, ec_ioctl_slave_sii_t)
+#define EC_IOCTL_SLAVE_REG_READ       EC_IOWR(0x11, ec_ioctl_slave_reg_t)
+#define EC_IOCTL_SLAVE_REG_WRITE       EC_IOW(0x12, ec_ioctl_slave_reg_t)
+#define EC_IOCTL_SLAVE_FOE_READ       EC_IOWR(0x13, ec_ioctl_slave_foe_t)
+#define EC_IOCTL_SLAVE_FOE_WRITE       EC_IOW(0x14, ec_ioctl_slave_foe_t)
+#define EC_IOCTL_CONFIG               EC_IOWR(0x15, ec_ioctl_config_t)
+#define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x16, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x17, ec_ioctl_config_pdo_entry_t)
+#define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x18, ec_ioctl_config_sdo_t)
 #ifdef EC_EOE
-#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x18, ec_ioctl_eoe_handler_t)
+#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x19, ec_ioctl_eoe_handler_t)
 #endif
 
 // Application interface
-#define EC_IOCTL_REQUEST                EC_IO(0x19)
-#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1a)
-#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x1b, ec_ioctl_config_t)
-#define EC_IOCTL_ACTIVATE              EC_IOR(0x1c, size_t)
-#define EC_IOCTL_DEACTIVATE             EC_IO(0x1d)
-#define EC_IOCTL_SEND                   EC_IO(0x1e)
-#define EC_IOCTL_RECEIVE                EC_IO(0x1f)
-#define EC_IOCTL_MASTER_STATE          EC_IOR(0x20, ec_master_state_t)
-#define EC_IOCTL_APP_TIME              EC_IOW(0x21, ec_ioctl_app_time_t)
-#define EC_IOCTL_SYNC_REF               EC_IO(0x22)
-#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x23)
-#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x24)
-#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x25, uint32_t)
-#define EC_IOCTL_SC_SYNC               EC_IOW(0x26, ec_ioctl_config_t)
-#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x27, ec_ioctl_config_t)
-#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x28, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x29, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x2a, ec_ioctl_add_pdo_entry_t)
-#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x2b, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x2c, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_DC                 EC_IOW(0x2d, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO                EC_IOW(0x2e, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x2f, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x20, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x31, ec_ioctl_sc_state_t)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x32)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x33)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x34)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x35, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x36, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x37, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x38, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x39, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x3b, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x3c, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x3d, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x3e, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x3f, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x40, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x41, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL    EC_IOW(0x42, size_t)
+#define EC_IOCTL_REQUEST                EC_IO(0x1a)
+#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1b)
+#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x1c, ec_ioctl_config_t)
+#define EC_IOCTL_ACTIVATE              EC_IOR(0x1d, size_t)
+#define EC_IOCTL_DEACTIVATE             EC_IO(0x1e)
+#define EC_IOCTL_SEND                   EC_IO(0x1f)
+#define EC_IOCTL_RECEIVE                EC_IO(0x20)
+#define EC_IOCTL_MASTER_STATE          EC_IOR(0x21, ec_master_state_t)
+#define EC_IOCTL_APP_TIME              EC_IOW(0x22, ec_ioctl_app_time_t)
+#define EC_IOCTL_SYNC_REF               EC_IO(0x23)
+#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x24)
+#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x25)
+#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x26, uint32_t)
+#define EC_IOCTL_SC_SYNC               EC_IOW(0x27, ec_ioctl_config_t)
+#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x28, ec_ioctl_config_t)
+#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x29, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x2a, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x2b, ec_ioctl_add_pdo_entry_t)
+#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x2c, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x2d, ec_ioctl_reg_pdo_entry_t)
+#define EC_IOCTL_SC_DC                 EC_IOW(0x2e, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO                EC_IOW(0x2f, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x20, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x31, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x32, ec_ioctl_sc_state_t)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x33)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x34)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x35)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x36, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x37, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x38, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x39, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x3b, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x3c, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x3d, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x3e, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x3f, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x40, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x41, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x42, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x43, size_t)
 
 /*****************************************************************************/
 
@@ -132,6 +139,13 @@
 /*****************************************************************************/
 
 typedef struct {
+    uint32_t ioctl_version_magic;
+    uint32_t master_count;
+} ec_ioctl_module_t;
+
+/*****************************************************************************/
+
+typedef struct {
     uint32_t slave_count;
     uint32_t config_count;
     uint32_t domain_count;
--- a/master/module.c	Tue Feb 23 17:40:46 2010 +0100
+++ b/master/module.c	Wed Feb 24 16:27:11 2010 +0100
@@ -195,6 +195,15 @@
     EC_INFO("Master module cleaned up.\n");
 }
 
+/*****************************************************************************/
+
+/** Get the number of masters.
+ */
+unsigned int ec_master_count(void)
+{
+    return master_count;
+}
+
 /*****************************************************************************
  * MAC address functions
  ****************************************************************************/
--- a/tool/Command.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/Command.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -28,6 +28,7 @@
  ****************************************************************************/
 
 #include "Command.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -46,6 +47,13 @@
 
 /*****************************************************************************/
 
+void Command::setMasterIndices(const MasterIndexList &indices)
+{
+    masterIndices = indices;
+};
+
+/*****************************************************************************/
+
 void Command::setVerbosity(Verbosity v)
 {
     verbosity = v;
--- a/tool/Command.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/Command.h	Wed Feb 24 16:27:11 2010 +0100
@@ -33,9 +33,12 @@
 #include <stdexcept>
 #include <vector>
 #include <list>
+#include <sstream>
 using namespace std;
 
-#include "MasterDevice.h"
+#include "../master/ioctl.h"
+
+class MasterDevice;
 
 /****************************************************************************/
 
@@ -76,6 +79,9 @@
         const string &getName() const;
         const string &getBriefDescription() const;
 
+        typedef list<unsigned int> MasterIndexList;
+        void setMasterIndices(const MasterIndexList &);
+        const MasterIndexList &getMasterIndices() const;
         enum Verbosity {
             Quiet,
             Normal,
@@ -102,7 +108,7 @@
         virtual string helpString() const = 0;
 
         typedef vector<string> StringVector;
-        virtual void execute(MasterDevice &, const StringVector &) = 0;
+        virtual void execute(const StringVector &) = 0;
 
         static string numericInfo();
 
@@ -125,6 +131,7 @@
     private:
         string name;
         string briefDesc;
+        MasterIndexList masterIndices;
         Verbosity verbosity;
         int alias;
         int position;
@@ -152,6 +159,13 @@
 
 /****************************************************************************/
 
+inline const Command::MasterIndexList &Command::getMasterIndices() const
+{
+    return masterIndices;
+}
+
+/****************************************************************************/
+
 inline Command::Verbosity Command::getVerbosity() const
 {
     return verbosity;
--- a/tool/CommandAlias.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandAlias.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 
 #include "CommandAlias.h"
 #include "sii_crc.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -75,7 +76,7 @@
 
 /** Writes the Secondary slave address (alias) to the slave's SII.
  */
-void CommandAlias::execute(MasterDevice &m, const StringVector &args)
+void CommandAlias::execute(const StringVector &args)
 {
     uint16_t alias;
     stringstream err, strAlias;
@@ -98,6 +99,11 @@
     }
     alias = number;
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::ReadWrite);
     slaves = selectedSlaves(m);
     
--- a/tool/CommandAlias.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandAlias.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandAlias();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void writeSlaveAlias(MasterDevice &, const ec_ioctl_slave_t &,
--- a/tool/CommandCStruct.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandCStruct.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -33,6 +33,7 @@
 using namespace std;
 
 #include "CommandCStruct.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -67,7 +68,7 @@
 
 /****************************************************************************/
 
-void CommandCStruct::execute(MasterDevice &m, const StringVector &args)
+void CommandCStruct::execute(const StringVector &args)
 {
     SlaveList slaves;
     SlaveList::const_iterator si;
@@ -78,11 +79,16 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    slaves = selectedSlaves(m);
-
-    for (si = slaves.begin(); si != slaves.end(); si++) {
-        generateSlaveCStruct(m, *si);
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        slaves = selectedSlaves(m);
+
+        for (si = slaves.begin(); si != slaves.end(); si++) {
+            generateSlaveCStruct(m, *si);
+        }
     }
 }
 
--- a/tool/CommandCStruct.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandCStruct.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandCStruct();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void generateSlaveCStruct(MasterDevice &, const ec_ioctl_slave_t &);
--- a/tool/CommandConfig.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandConfig.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 using namespace std;
 
 #include "CommandConfig.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -101,9 +102,10 @@
 
 /** Lists the bus configuration.
  */
-void CommandConfig::execute(MasterDevice &m, const StringVector &args)
+void CommandConfig::execute(const StringVector &args)
 {
     ConfigList configs;
+    bool doIndent;
 
     if (args.size()) {
         stringstream err;
@@ -111,13 +113,23 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    configs = selectedConfigs(m);
-
-    if (getVerbosity() == Verbose) {
-        showDetailedConfigs(m, configs);
-    } else {
-        listConfigs(m, configs);
+    doIndent = getMasterIndices().size() > 1;
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        configs = selectedConfigs(m);
+
+        if (doIndent) {
+            cout << "Master" << dec << *mi << endl;
+        }
+
+        if (getVerbosity() == Verbose) {
+            showDetailedConfigs(m, configs, doIndent);
+        } else {
+            listConfigs(m, configs, doIndent);
+        }
     }
 }
 
@@ -127,7 +139,8 @@
  */
 void CommandConfig::showDetailedConfigs(
         MasterDevice &m,
-        const ConfigList &configList
+        const ConfigList &configList,
+        bool doIndent
         )
 {
     ConfigList::const_iterator configIter;
@@ -136,19 +149,21 @@
     ec_ioctl_config_pdo_t pdo;
     ec_ioctl_config_pdo_entry_t entry;
     ec_ioctl_config_sdo_t sdo;
+    string indent(doIndent ? "  " : "");
 
     for (configIter = configList.begin();
             configIter != configList.end();
             configIter++) {
 
-        cout << "Alias: "
-            << dec << configIter->alias << endl
-            << "Position: " << configIter->position << endl
+        cout << indent
+            << "Alias: "
+            << dec << configIter->alias << endl << indent
+            << "Position: " << configIter->position << endl << indent
             << "Vendor Id: 0x"
             << hex << setfill('0')
-            << setw(8) << configIter->vendor_id << endl
+            << setw(8) << configIter->vendor_id << endl << indent
             << "Product code: 0x"
-            << setw(8) << configIter->product_code << endl
+            << setw(8) << configIter->product_code << endl << indent
             << "Attached slave: ";
         
         if (configIter->slave_position != -1) {
@@ -159,13 +174,13 @@
             cout << "none" << endl;
         }
 
-        cout << "Watchdog divider: ";
+        cout << indent << "Watchdog divider: ";
         if (configIter->watchdog_divider) {
             cout << dec << configIter->watchdog_divider;
         } else {
             cout << "(Default)";
         }
-        cout << endl
+        cout << endl << indent
             << "Watchdog intervals: ";
         if (configIter->watchdog_intervals) {
             cout << dec << configIter->watchdog_intervals;
@@ -176,7 +191,7 @@
 
         for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
             if (configIter->syncs[j].pdo_count) {
-                cout << "SM" << dec << j << ", Dir: "
+                cout << indent << "SM" << dec << j << ", Dir: "
                     << (configIter->syncs[j].dir == EC_DIR_INPUT
                             ? "Input" : "Output") << ", Watchdog: ";
                 switch (configIter->syncs[j].watchdog_mode) {
@@ -190,14 +205,15 @@
                 for (k = 0; k < configIter->syncs[j].pdo_count; k++) {
                     m.getConfigPdo(&pdo, configIter->config_index, j, k);
 
-                    cout << "  PDO 0x" << hex << setfill('0')
+                    cout << indent << "  PDO 0x" << hex << setfill('0')
                         << setw(4) << pdo.index << endl;
 
                     for (l = 0; l < pdo.entry_count; l++) {
                         m.getConfigPdoEntry(&entry,
                                 configIter->config_index, j, k, l);
 
-                        cout << "    PDO entry 0x" << hex << setfill('0')
+                        cout << indent << "    PDO entry 0x"
+                            << hex << setfill('0')
                             << setw(4) << entry.index << ":"
                             << setw(2) << (unsigned int) entry.subindex
                             << ", " << dec << setfill(' ')
@@ -208,23 +224,23 @@
             }
         }
 
-        cout << "SDO configuration:" << endl;
+        cout << indent << "SDO configuration:" << endl;
         if (configIter->sdo_count) {
             for (j = 0; j < configIter->sdo_count; j++) {
                 m.getConfigSdo(&sdo, configIter->config_index, j);
 
-                cout << "  0x"
+                cout << indent << "  0x"
                     << hex << setfill('0')
                     << setw(4) << sdo.index << ":"
                     << setw(2) << (unsigned int) sdo.subindex
                     << ", " << dec << sdo.size << " byte" << endl;
 
-                cout << "    " << hex;
+                cout << indent << "    " << hex;
                 for (i = 0; i < min((uint32_t) sdo.size,
                             (uint32_t) EC_MAX_SDO_DATA_SIZE); i++) {
                     cout << setw(2) << (unsigned int) sdo.data[i];
                     if ((i + 1) % 16 == 0 && i < sdo.size - 1) {
-                        cout << endl << "    ";
+                        cout << endl << indent << "    ";
                     } else {
                         cout << " ";
                     }
@@ -232,23 +248,23 @@
 
                 cout << endl;
                 if (sdo.size > EC_MAX_SDO_DATA_SIZE) {
-                    cout << "    ..." << endl;
+                    cout << indent << "    ..." << endl;
                 }
             }
         } else {
-            cout << "  None." << endl;
+            cout << indent << "  None." << endl;
         }
 
         if (configIter->dc_assign_activate) {
             int i;
 
-            cout << "DC configuration:" << endl
-                << "  AssignActivate: 0x" << hex << setfill('0')
+            cout << indent << "DC configuration:" << endl
+                << indent << "  AssignActivate: 0x" << hex << setfill('0')
                 << setw(4) << configIter->dc_assign_activate << endl;
 
-            cout << "         Cycle [ns]   Shift [ns]" << endl;
+            cout << indent << "         Cycle [ns]   Shift [ns]" << endl;
             for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) {
-                cout << "  SYNC" << dec << i << "  "
+                cout << indent << "  SYNC" << dec << i << "  "
                     << setfill(' ') << right
                     << setw(11) << configIter->dc_sync[i].cycle_time
                     << "  "
@@ -266,7 +282,8 @@
  */
 void CommandConfig::listConfigs(
         MasterDevice &m,
-        const ConfigList &configList
+        const ConfigList &configList,
+        bool doIndent
         )
 {
     ConfigList::const_iterator configIter;
@@ -278,6 +295,7 @@
     unsigned int maxAliasWidth = 0, maxPosWidth = 0,
                  maxSlavePosWidth = 0, maxStateWidth = 0;
     ec_ioctl_slave_t slave;
+    string indent(doIndent ? "  " : "");
 
     for (configIter = configList.begin();
             configIter != configList.end();
@@ -337,7 +355,7 @@
     }
 
     for (iter = list.begin(); iter != list.end(); iter++) {
-        cout << setfill(' ') << right
+        cout << indent << setfill(' ') << right
             << setw(maxAliasWidth) << iter->alias
             << ":" << left
             << setw(maxPosWidth) << iter->pos
--- a/tool/CommandConfig.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandConfig.h	Wed Feb 24 16:27:11 2010 +0100
@@ -44,7 +44,7 @@
         CommandConfig();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         struct Info {
@@ -55,8 +55,8 @@
             string state;
         };
 
-        void showDetailedConfigs(MasterDevice &, const ConfigList &);
-        void listConfigs(MasterDevice &m, const ConfigList &);
+        void showDetailedConfigs(MasterDevice &, const ConfigList &, bool);
+        void listConfigs(MasterDevice &m, const ConfigList &, bool);
 };
 
 /****************************************************************************/
--- a/tool/CommandData.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandData.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -31,6 +31,7 @@
 using namespace std;
 
 #include "CommandData.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -63,7 +64,7 @@
 
 /****************************************************************************/
 
-void CommandData::execute(MasterDevice &m, const StringVector &args)
+void CommandData::execute(const StringVector &args)
 {
     DomainList domains;
     DomainList::const_iterator di;
@@ -74,6 +75,12 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        stringstream err;
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     domains = selectedDomains(m);
 
--- a/tool/CommandData.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandData.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandData();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void outputDomainData(MasterDevice &, const ec_ioctl_domain_t &);
--- a/tool/CommandDebug.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDebug.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandDebug.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -65,7 +66,7 @@
 
 /****************************************************************************/
 
-void CommandDebug::execute(MasterDevice &m, const StringVector &args)
+void CommandDebug::execute(const StringVector &args)
 {
     stringstream str;
     int debugLevel;
@@ -86,8 +87,13 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::ReadWrite);
-    m.setDebug(debugLevel);
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::ReadWrite);
+        m.setDebug(debugLevel);
+    }
 }
 
 /*****************************************************************************/
--- a/tool/CommandDebug.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDebug.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandDebug();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandDomains.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDomains.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandDomains.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -89,10 +90,11 @@
 
 /****************************************************************************/
 
-void CommandDomains::execute(MasterDevice &m, const StringVector &args)
+void CommandDomains::execute(const StringVector &args)
 {
     DomainList domains;
     DomainList::const_iterator di;
+    bool doIndent;
 
     if (args.size()) {
         stringstream err;
@@ -100,11 +102,21 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    domains = selectedDomains(m);
+    doIndent = getMasterIndices().size() > 1;
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        domains = selectedDomains(m);
 
-    for (di = domains.begin(); di != domains.end(); di++) {
-        showDomain(m, *di);
+        if (doIndent) {
+            cout << "Master" << dec << *mi << endl;
+        }
+
+        for (di = domains.begin(); di != domains.end(); di++) {
+            showDomain(m, *di, doIndent);
+        }
     }
 }
 
@@ -112,7 +124,8 @@
 
 void CommandDomains::showDomain(
         MasterDevice &m,
-        const ec_ioctl_domain_t &domain
+        const ec_ioctl_domain_t &domain,
+        bool doIndent
         )
 {
     unsigned char *processData;
@@ -120,8 +133,9 @@
     unsigned int i, j;
     ec_ioctl_domain_fmmu_t fmmu;
     unsigned int dataOffset;
+    string indent(doIndent ? "  " : "");
 
-    cout << "Domain" << dec << domain.index << ":"
+    cout << indent << "Domain" << dec << domain.index << ":"
         << " LogBaseAddr 0x"
         << hex << setfill('0')
         << setw(8) << domain.logical_base_address
@@ -146,7 +160,7 @@
     for (i = 0; i < domain.fmmu_count; i++) {
         m.getFmmu(&fmmu, domain.index, i);
 
-        cout << "  SlaveConfig "
+        cout << indent << "  SlaveConfig "
             << dec << fmmu.slave_config_alias
             << ":" << fmmu.slave_config_position
             << ", SM" << (unsigned int) fmmu.sync_index << " ("
@@ -165,10 +179,10 @@
             throwCommandException(err);
         }
 
-        cout << "    " << hex << setfill('0');
+        cout << indent << "    " << hex << setfill('0');
         for (j = 0; j < fmmu.data_size; j++) {
             if (j && !(j % BreakAfterBytes))
-                cout << endl << "    ";
+                cout << endl << indent << "    ";
             cout << "0x" << setw(2)
                 << (unsigned int) *(processData + dataOffset + j) << " ";
         }
--- a/tool/CommandDomains.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDomains.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,10 +41,10 @@
         CommandDomains();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
-        void showDomain(MasterDevice &, const ec_ioctl_domain_t &);
+        void showDomain(MasterDevice &, const ec_ioctl_domain_t &, bool);
 };
 
 /****************************************************************************/
--- a/tool/CommandDownload.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDownload.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandDownload.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -83,7 +84,7 @@
 
 /****************************************************************************/
 
-void CommandDownload::execute(MasterDevice &m, const StringVector &args)
+void CommandDownload::execute(const StringVector &args)
 {
     stringstream strIndex, strSubIndex, strValue, err;
     ec_ioctl_slave_sdo_download_t data;
@@ -115,6 +116,11 @@
     }
     data.sdo_entry_subindex = number;
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::ReadWrite);
     slaves = selectedSlaves(m);
     if (slaves.size() != 1) {
--- a/tool/CommandDownload.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandDownload.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandDownload();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         enum {DefaultBufferSize = 1024};
--- a/tool/CommandEoe.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandEoe.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 using namespace std;
 
 #include "CommandEoe.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -60,11 +61,13 @@
 
 /****************************************************************************/
 
-void CommandEoe::execute(MasterDevice &m, const StringVector &args)
+void CommandEoe::execute(const StringVector &args)
 {
     ec_ioctl_master_t master;
     unsigned int i;
     ec_ioctl_eoe_handler_t eoe;
+    bool doIndent;
+    string indent;
     
     if (args.size()) {
         stringstream err;
@@ -72,31 +75,42 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    m.getMaster(&master);
+    doIndent = getMasterIndices().size();
+    indent = doIndent ? "  " : "";
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        m.getMaster(&master);
 
-    cout << "Interface  Slave  State  "
-        << "RxBytes  RxRate  "
-        << "TxBytes  TxRate  TxQueue"
-        << endl;
+        if (doIndent) {
+            cout << "Master" << dec << *mi << endl;
+        }
 
-    for (i = 0; i < master.eoe_handler_count; i++) {
-        stringstream queue;
+        cout << indent << "Interface  Slave  State  "
+            << "RxBytes  RxRate  "
+            << "TxBytes  TxRate  TxQueue"
+            << endl;
 
-        m.getEoeHandler(&eoe, i);
+        for (i = 0; i < master.eoe_handler_count; i++) {
+            stringstream queue;
 
-        queue << eoe.tx_queued_frames << "/" << eoe.tx_queue_size;
+            m.getEoeHandler(&eoe, i);
 
-        cout 
-            << setw(9) << eoe.name << "  "
-            << setw(5) << dec << eoe.slave_position << "  "
-            << setw(5) << (eoe.open ? "up" : "down") << "  "
-            << setw(7) << eoe.rx_bytes << "  "
-            << setw(6) << eoe.rx_rate << "  "
-            << setw(7) << eoe.tx_bytes << "  "
-            << setw(6) << eoe.tx_rate << "  "
-            << setw(7) << queue.str()
-            << endl;
+            queue << eoe.tx_queued_frames << "/" << eoe.tx_queue_size;
+
+            cout << indent
+                << setw(9) << eoe.name << "  "
+                << setw(5) << dec << eoe.slave_position << "  "
+                << setw(5) << (eoe.open ? "up" : "down") << "  "
+                << setw(7) << eoe.rx_bytes << "  "
+                << setw(6) << eoe.rx_rate << "  "
+                << setw(7) << eoe.tx_bytes << "  "
+                << setw(6) << eoe.tx_rate << "  "
+                << setw(7) << queue.str()
+                << endl;
+        }
     }
 }
 
--- a/tool/CommandEoe.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandEoe.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandEoe();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandFoeRead.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandFoeRead.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -35,6 +35,7 @@
 
 #include "CommandFoeRead.h"
 #include "foe.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -73,7 +74,7 @@
 
 /****************************************************************************/
 
-void CommandFoeRead::execute(MasterDevice &m, const StringVector &args)
+void CommandFoeRead::execute(const StringVector &args)
 {
     SlaveList slaves;
     ec_ioctl_slave_t *slave;
@@ -86,6 +87,11 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     slaves = selectedSlaves(m);
 
--- a/tool/CommandFoeRead.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandFoeRead.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandFoeRead();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandFoeWrite.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandFoeWrite.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -37,6 +37,7 @@
 
 #include "CommandFoeWrite.h"
 #include "foe.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -79,7 +80,7 @@
 
 /****************************************************************************/
 
-void CommandFoeWrite::execute(MasterDevice &m, const StringVector &args)
+void CommandFoeWrite::execute(const StringVector &args)
 {
     stringstream err;
     ec_ioctl_slave_foe_t data;
@@ -92,6 +93,12 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
+
     if (args[0] == "-") {
         loadFoeData(&data, cin);
         if (getOutputFile().empty()) {
--- a/tool/CommandFoeWrite.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandFoeWrite.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandFoeWrite();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void loadFoeData(ec_ioctl_slave_foe_t *, const istream &);
--- a/tool/CommandGraph.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandGraph.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandGraph.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -64,7 +65,7 @@
 
 /****************************************************************************/
 
-void CommandGraph::execute(MasterDevice &m, const StringVector &args)
+void CommandGraph::execute(const StringVector &args)
 {
     ec_ioctl_master_t master;
     unsigned int i;
@@ -89,6 +90,12 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        stringstream err;
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     m.getMaster(&master);
 
--- a/tool/CommandGraph.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandGraph.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandGraph();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandMaster.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandMaster.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandMaster.h"
+#include "MasterDevice.h"
 
 #define MAX_TIME_STR_SIZE 50
 
@@ -53,7 +54,9 @@
         << getBriefDescription() << endl
         << endl
         << "Command-specific options:" << endl
-        << "  --master -m <index>  Index of the master to use. Default: 0."
+        << "  --master -m <indices>  Master indices. A comma-separated" << endl
+        << "                         list with ranges is supported." << endl
+        << "                         Example: 1,4,5,7-9. Default: - (all)."
         << endl << endl
         << numericInfo();
 
@@ -62,7 +65,7 @@
 
 /****************************************************************************/
 
-void CommandMaster::execute(MasterDevice &m, const StringVector &args)
+void CommandMaster::execute(const StringVector &args)
 {
     ec_ioctl_master_t data;
     stringstream err;
@@ -76,67 +79,79 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    m.getMaster(&data);
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        m.getMaster(&data);
 
-    cout
-        << "Master" << m.getIndex() << endl
-        << "  Phase: ";
+        cout
+            << "Master" << m.getIndex() << endl
+            << "  Phase: ";
 
-    switch (data.phase) {
-        case 0:  cout << "Waiting for device..."; break;
-        case 1:  cout << "Idle"; break;
-        case 2:  cout << "Operation"; break;
-        default: cout << "???";
+        switch (data.phase) {
+            case 0:  cout << "Waiting for device..."; break;
+            case 1:  cout << "Idle"; break;
+            case 2:  cout << "Operation"; break;
+            default: cout << "???";
+        }
+
+        cout << endl
+            << "  Active: " << (data.active ? "yes" : "no") << endl
+            << "  Slaves: " << data.slave_count << endl
+            << "  Ethernet devices:" << endl;
+
+        for (i = 0; i < 2; i++) {
+            cout << "    " << (i == 0 ? "Main" : "Backup") << ": ";
+            if (data.devices[i].address[0] == 0x00
+                    && data.devices[i].address[1] == 0x00
+                    && data.devices[i].address[2] == 0x00
+                    && data.devices[i].address[3] == 0x00
+                    && data.devices[i].address[4] == 0x00
+                    && data.devices[i].address[5] == 0x00) {
+                cout << "None.";
+            } else {
+                cout << hex << setfill('0')
+                    << setw(2) << (unsigned int) data.devices[i].address[0]
+                    << ":"
+                    << setw(2) << (unsigned int) data.devices[i].address[1]
+                    << ":"
+                    << setw(2) << (unsigned int) data.devices[i].address[2]
+                    << ":"
+                    << setw(2) << (unsigned int) data.devices[i].address[3]
+                    << ":"
+                    << setw(2) << (unsigned int) data.devices[i].address[4]
+                    << ":"
+                    << setw(2) << (unsigned int) data.devices[i].address[5]
+                    << " ("
+                    << (data.devices[i].attached ? "attached" : "waiting...")
+                    << ")" << endl << dec
+                    << "      Link: "
+                    << (data.devices[i].link_state ? "UP" : "DOWN") << endl
+                    << "      Tx count: " << data.devices[i].tx_count << endl
+                    << "      Rx count: " << data.devices[i].rx_count;
+            }
+            cout << endl;
+        }
+
+        cout << "  Distributed clocks:" << endl
+            << "    Reference clock: ";
+        if (data.ref_clock != 0xffff) {
+            cout << "Slave " << dec << data.ref_clock;
+        } else {
+            cout << "None";
+        }
+        cout << endl
+            << "    Application time: " << data.app_time << endl
+            << "                      ";
+
+        epoch = data.app_time / 1000000000 + 946684800ULL;
+        time_str_size = strftime(time_str, MAX_TIME_STR_SIZE,
+                "%Y-%m-%d %H:%M:%S", gmtime(&epoch));
+        cout << string(time_str, time_str_size) << "."
+            << setfill('0') << setw(9) << data.app_time % 1000000000 << endl;
     }
-
-    cout << endl
-        << "  Active: " << (data.active ? "yes" : "no") << endl
-        << "  Slaves: " << data.slave_count << endl
-        << "  Ethernet devices:" << endl;
-
-    for (i = 0; i < 2; i++) {
-        cout << "    " << (i == 0 ? "Main" : "Backup") << ": ";
-        if (data.devices[i].address[0] == 0x00
-                && data.devices[i].address[1] == 0x00
-                && data.devices[i].address[2] == 0x00
-                && data.devices[i].address[3] == 0x00
-                && data.devices[i].address[4] == 0x00
-                && data.devices[i].address[5] == 0x00) {
-            cout << "None.";
-        } else {
-            cout << hex << setfill('0')
-                << setw(2) << (unsigned int) data.devices[i].address[0] << ":"
-                << setw(2) << (unsigned int) data.devices[i].address[1] << ":"
-                << setw(2) << (unsigned int) data.devices[i].address[2] << ":"
-                << setw(2) << (unsigned int) data.devices[i].address[3] << ":"
-                << setw(2) << (unsigned int) data.devices[i].address[4] << ":"
-                << setw(2) << (unsigned int) data.devices[i].address[5] << " ("
-                << (data.devices[i].attached ? "attached" : "waiting...")
-                << ")" << endl << dec
-                << "      Link: " << (data.devices[i].link_state ? "UP" : "DOWN") << endl
-                << "      Tx count: " << data.devices[i].tx_count << endl
-                << "      Rx count: " << data.devices[i].rx_count;
-        }
-        cout << endl;
-    }
-
-    cout << "  Distributed clocks:" << endl
-        << "    Reference clock: ";
-    if (data.ref_clock != 0xffff) {
-        cout << "Slave " << dec << data.ref_clock;
-    } else {
-        cout << "None";
-    }
-    cout << endl
-        << "    Application time: " << data.app_time << endl
-        << "                      ";
-
-    epoch = data.app_time / 1000000000 + 946684800ULL;
-    time_str_size = strftime(time_str, MAX_TIME_STR_SIZE,
-            "%Y-%m-%d %H:%M:%S", gmtime(&epoch));
-    cout << string(time_str, time_str_size) << "."
-        << setfill('0') << setw(9) << data.app_time % 1000000000 << endl;
 }
 
 /*****************************************************************************/
--- a/tool/CommandMaster.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandMaster.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandMaster();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandPdos.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandPdos.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandPdos.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -88,11 +89,11 @@
 
 /****************************************************************************/
 
-void CommandPdos::execute(MasterDevice &m, const StringVector &args)
+void CommandPdos::execute(const StringVector &args)
 {
     SlaveList slaves;
     SlaveList::const_iterator si;
-    bool showHeader;
+    bool showHeader, multiMaster;
     
     if (args.size()) {
         stringstream err;
@@ -100,12 +101,18 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    slaves = selectedSlaves(m);
-    showHeader = slaves.size() > 1;
+    multiMaster = getMasterIndices().size() > 1;
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        slaves = selectedSlaves(m);
+        showHeader = multiMaster || slaves.size() > 1;
 
-    for (si = slaves.begin(); si != slaves.end(); si++) {
-        listSlavePdos(m, *si, showHeader);
+        for (si = slaves.begin(); si != slaves.end(); si++) {
+            listSlavePdos(m, *si, showHeader);
+        }
     }
 }
 
@@ -123,7 +130,8 @@
     unsigned int i, j, k;
     
     if (showHeader)
-        cout << "=== Slave " << slave.position << " ===" << endl;
+        cout << "=== Master " << m.getIndex()
+            << ", Slave " << slave.position << " ===" << endl;
 
     for (i = 0; i < slave.sync_count; i++) {
         m.getSync(&sync, slave.position, i);
--- a/tool/CommandPdos.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandPdos.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandPdos();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void listSlavePdos(MasterDevice &, const ec_ioctl_slave_t &, bool);
--- a/tool/CommandRegRead.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandRegRead.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandRegRead.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -78,7 +79,7 @@
 
 /****************************************************************************/
 
-void CommandRegRead::execute(MasterDevice &m, const StringVector &args)
+void CommandRegRead::execute(const StringVector &args)
 {
     SlaveList slaves;
     ec_ioctl_slave_reg_t data;
@@ -141,6 +142,11 @@
         throwInvalidUsageException(err);
     }
     
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     slaves = selectedSlaves(m);
 
--- a/tool/CommandRegRead.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandRegRead.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandRegRead();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandRegWrite.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandRegWrite.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 
 #include "CommandRegWrite.h"
 #include "sii_crc.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -80,7 +81,7 @@
 
 /****************************************************************************/
 
-void CommandRegWrite::execute(MasterDevice &m, const StringVector &args)
+void CommandRegWrite::execute(const StringVector &args)
 {
     stringstream strOffset, err;
     ec_ioctl_slave_reg_t data;
@@ -100,6 +101,12 @@
         err << "Invalid offset '" << args[0] << "'!";
         throwInvalidUsageException(err);
     }
+  
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
 
     if (getDataType().empty()) {
         if (args[1] == "-") {
--- a/tool/CommandRegWrite.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandRegWrite.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandRegWrite();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     private:
         void loadRegData(ec_ioctl_slave_reg_t *, const istream &);
--- a/tool/CommandSdos.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSdos.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandSdos.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -86,11 +87,11 @@
 
 /****************************************************************************/
 
-void CommandSdos::execute(MasterDevice &m, const StringVector &args)
+void CommandSdos::execute(const StringVector &args)
 {
     SlaveList slaves;
     SlaveList::const_iterator si;
-    bool showHeader;
+    bool showHeader, multiMaster;
 
     if (args.size()) {
         stringstream err;
@@ -98,12 +99,18 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    slaves = selectedSlaves(m);
-    showHeader = slaves.size() > 1;
+    multiMaster = getMasterIndices().size() > 1;
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        slaves = selectedSlaves(m);
+        showHeader = multiMaster || slaves.size() > 1;
 
-    for (si = slaves.begin(); si != slaves.end(); si++) {
-        listSlaveSdos(m, *si, showHeader);
+        for (si = slaves.begin(); si != slaves.end(); si++) {
+            listSlaveSdos(m, *si, showHeader);
+        }
     }
 }
 
@@ -121,7 +128,8 @@
     const DataType *d;
     
     if (showHeader)
-        cout << "=== Slave " << slave.position << " ===" << endl;
+        cout << "=== Master " << m.getIndex()
+            << ", Slave " << slave.position << " ===" << endl;
 
     for (i = 0; i < slave.sdo_count; i++) {
         m.getSdo(&sdo, slave.position, i);
--- a/tool/CommandSdos.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSdos.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandSdos();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void listSlaveSdos(MasterDevice &, const ec_ioctl_slave_t &, bool);
--- a/tool/CommandSiiRead.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSiiRead.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandSiiRead.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -73,7 +74,7 @@
 
 /****************************************************************************/
 
-void CommandSiiRead::execute(MasterDevice &m, const StringVector &args)
+void CommandSiiRead::execute(const StringVector &args)
 {
     SlaveList slaves;
     ec_ioctl_slave_t *slave;
@@ -88,6 +89,11 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     slaves = selectedSlaves(m);
 
--- a/tool/CommandSiiRead.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSiiRead.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandSiiRead();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         struct CategoryName {
--- a/tool/CommandSiiWrite.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSiiWrite.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 
 #include "CommandSiiWrite.h"
 #include "sii_crc.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -75,7 +76,7 @@
 
 /****************************************************************************/
 
-void CommandSiiWrite::execute(MasterDevice &m, const StringVector &args)
+void CommandSiiWrite::execute(const StringVector &args)
 {
     stringstream err;
     ec_ioctl_slave_sii_t data;
@@ -87,6 +88,12 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
+
     if (args[0] == "-") {
         loadSiiData(&data, cin);
     } else {
--- a/tool/CommandSiiWrite.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSiiWrite.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandSiiWrite();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void loadSiiData(ec_ioctl_slave_sii_t *, const istream &);
--- a/tool/CommandSlaves.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSlaves.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -34,6 +34,7 @@
 using namespace std;
 
 #include "CommandSlaves.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -105,9 +106,10 @@
 
 /****************************************************************************/
 
-void CommandSlaves::execute(MasterDevice &m, const StringVector &args)
+void CommandSlaves::execute(const StringVector &args)
 {
     SlaveList slaves;
+    bool doIndent;
     
     if (args.size()) {
         stringstream err;
@@ -115,13 +117,23 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::Read);
-    slaves = selectedSlaves(m);
-
-    if (getVerbosity() == Verbose) {
-        showSlaves(m, slaves);
-    } else {
-        listSlaves(m, slaves);
+    doIndent = getMasterIndices().size() > 1;
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::Read);
+        slaves = selectedSlaves(m);
+
+        if (doIndent) {
+            cout << "Master" << dec << *mi << endl;
+        }
+
+        if (getVerbosity() == Verbose) {
+            showSlaves(m, slaves);
+        } else {
+            listSlaves(m, slaves, doIndent);
+        }
     }
 }
 
@@ -129,7 +141,8 @@
 
 void CommandSlaves::listSlaves(
         MasterDevice &m,
-        const SlaveList &slaves
+        const SlaveList &slaves,
+        bool doIndent
         )
 {
     ec_ioctl_master_t master;
@@ -143,6 +156,7 @@
     stringstream str;
     unsigned int maxPosWidth = 0, maxAliasWidth = 0,
                  maxRelPosWidth = 0, maxStateWidth = 0;
+    string indent(doIndent ? "  " : "");
     
     m.getMaster(&master);
 
@@ -200,7 +214,7 @@
     }
 
     for (iter = infoList.begin(); iter != infoList.end(); iter++) {
-        cout << setfill(' ') << right
+        cout << indent << setfill(' ') << right
             << setw(maxPosWidth) << iter->pos << "  "
             << setw(maxAliasWidth) << iter->alias
             << ":" << left
@@ -222,7 +236,8 @@
     int i;
 
     for (si = slaves.begin(); si != slaves.end(); si++) {
-        cout << "=== Slave " << dec << si->position << " ===" << endl;
+        cout << "=== Master " << dec << m.getIndex()
+            << ", Slave " << dec << si->position << " ===" << endl;
 
         if (si->alias)
             cout << "Alias: " << si->alias << endl;
--- a/tool/CommandSlaves.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandSlaves.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandSlaves();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         struct Info {
@@ -53,7 +53,7 @@
             string name;
         };
 
-        void listSlaves(MasterDevice &, const SlaveList &);
+        void listSlaves(MasterDevice &, const SlaveList &, bool);
         void showSlaves(MasterDevice &, const SlaveList &);
         
         static bool slaveInList( const ec_ioctl_slave_t &, const SlaveList &);
--- a/tool/CommandStates.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandStates.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandStates.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -65,7 +66,7 @@
 
 /****************************************************************************/
 
-void CommandStates::execute(MasterDevice &m, const StringVector &args)
+void CommandStates::execute(const StringVector &args)
 {
     SlaveList slaves;
     SlaveList::const_iterator si;
@@ -97,15 +98,16 @@
         throwInvalidUsageException(err);
     }
 
-    m.open(MasterDevice::ReadWrite);
-    slaves = selectedSlaves(m);
+    MasterIndexList::const_iterator mi;
+    for (mi = getMasterIndices().begin();
+            mi != getMasterIndices().end(); mi++) {
+        MasterDevice m(*mi);
+        m.open(MasterDevice::ReadWrite);
+        slaves = selectedSlaves(m);
 
-    if (!slaves.size() && getVerbosity() != Quiet) {
-        cerr << "Warning: Selection matches no slaves!" << endl;
-    }
-
-    for (si = slaves.begin(); si != slaves.end(); si++) {
-        m.requestState(si->position, state);
+        for (si = slaves.begin(); si != slaves.end(); si++) {
+            m.requestState(si->position, state);
+        }
     }
 }
 
--- a/tool/CommandStates.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandStates.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandStates();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandUpload.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandUpload.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -32,6 +32,7 @@
 using namespace std;
 
 #include "CommandUpload.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -81,7 +82,7 @@
 
 /****************************************************************************/
 
-void CommandUpload::execute(MasterDevice &m, const StringVector &args)
+void CommandUpload::execute(const StringVector &args)
 {
     SlaveList slaves;
     stringstream err, strIndex, strSubIndex;
@@ -113,6 +114,11 @@
     }
     data.sdo_entry_subindex = uval;
 
+    if (getMasterIndices().size() != 1) {
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     slaves = selectedSlaves(m);
     if (slaves.size() != 1) {
--- a/tool/CommandUpload.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandUpload.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandUpload();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         enum {DefaultBufferSize = 64 * 1024};
--- a/tool/CommandVersion.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandVersion.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -54,7 +54,7 @@
 
 /****************************************************************************/
 
-void CommandVersion::execute(MasterDevice &m, const StringVector &args)
+void CommandVersion::execute(const StringVector &args)
 {
     if (args.size()) {
         stringstream err;
--- a/tool/CommandVersion.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandVersion.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandVersion();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 };
 
 /****************************************************************************/
--- a/tool/CommandXml.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandXml.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -33,6 +33,7 @@
 using namespace std;
 
 #include "CommandXml.h"
+#include "MasterDevice.h"
 
 /*****************************************************************************/
 
@@ -68,7 +69,7 @@
 
 /****************************************************************************/
 
-void CommandXml::execute(MasterDevice &m, const StringVector &args)
+void CommandXml::execute(const StringVector &args)
 {
     SlaveList slaves;
     SlaveList::const_iterator si;
@@ -79,6 +80,12 @@
         throwInvalidUsageException(err);
     }
 
+    if (getMasterIndices().size() != 1) {
+        stringstream err;
+        err << getName() << " requires to select a single master!";
+        throwInvalidUsageException(err);
+    }
+    MasterDevice m(getMasterIndices().front());
     m.open(MasterDevice::Read);
     slaves = selectedSlaves(m);
 
--- a/tool/CommandXml.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/CommandXml.h	Wed Feb 24 16:27:11 2010 +0100
@@ -41,7 +41,7 @@
         CommandXml();
 
         string helpString() const;
-        void execute(MasterDevice &, const StringVector &);
+        void execute(const StringVector &);
 
     protected:
         void generateSlaveXml(MasterDevice &, const ec_ioctl_slave_t &,
--- a/tool/Makefile.am	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/Makefile.am	Wed Feb 24 16:27:11 2010 +0100
@@ -38,8 +38,8 @@
 ethercat_SOURCES = \
 	Command.cpp \
 	CommandAlias.cpp \
+	CommandCStruct.cpp \
 	CommandConfig.cpp \
-	CommandCStruct.cpp \
 	CommandData.cpp \
 	CommandDebug.cpp \
 	CommandDomains.cpp \
@@ -62,6 +62,7 @@
 	CommandXml.cpp \
 	FoeCommand.cpp \
 	MasterDevice.cpp \
+	NumberListParser.cpp \
 	SdoCommand.cpp \
 	main.cpp \
 	sii_crc.cpp
@@ -75,8 +76,8 @@
 noinst_HEADERS = \
 	Command.h \
 	CommandAlias.h \
+	CommandCStruct.h \
 	CommandConfig.h \
-	CommandCStruct.h \
 	CommandData.h \
 	CommandDebug.h \
 	CommandDomains.h \
@@ -99,6 +100,7 @@
 	CommandXml.h \
 	FoeCommand.h \
 	MasterDevice.h \
+	NumberListParser.h \
 	SdoCommand.h \
 	sii_crc.h
 
--- a/tool/MasterDevice.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/MasterDevice.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -42,10 +42,11 @@
 
 /****************************************************************************/
 
-MasterDevice::MasterDevice()
-{
-    index = 0;
-    fd = -1;
+MasterDevice::MasterDevice(unsigned int index):
+    index(index),
+    masterCount(0U),
+    fd(-1)
+{
 }
 
 /****************************************************************************/
@@ -69,6 +70,7 @@
     stringstream deviceName;
 
     if (fd == -1) { // not already open
+        ec_ioctl_module_t module_data;
         deviceName << "/dev/EtherCAT" << index;
 
         if ((fd = ::open(deviceName.str().c_str(),
@@ -78,6 +80,16 @@
                 << strerror(errno);
             throw MasterDeviceException(err);
         }
+
+        getModule(&module_data);
+        if (module_data.ioctl_version_magic != EC_IOCTL_VERSION_MAGIC) {
+            stringstream err;
+            err << "ioctl() version magic is differing: "
+                << deviceName << ": " << module_data.ioctl_version_magic
+                << ", ethercat tool: " << EC_IOCTL_VERSION_MAGIC;
+            throw MasterDeviceException(err);
+        }
+        masterCount = module_data.master_count;
     }
 }
 
@@ -93,6 +105,17 @@
 
 /****************************************************************************/
 
+void MasterDevice::getModule(ec_ioctl_module_t *data)
+{
+    if (ioctl(fd, EC_IOCTL_MODULE, data) < 0) {
+        stringstream err;
+        err << "Failed to get module information: " << strerror(errno);
+        throw MasterDeviceException(err);
+    }
+}
+
+/****************************************************************************/
+
 void MasterDevice::getMaster(ec_ioctl_master_t *data)
 {
     if (ioctl(fd, EC_IOCTL_MASTER, data) < 0) {
--- a/tool/MasterDevice.h	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/MasterDevice.h	Wed Feb 24 16:27:11 2010 +0100
@@ -79,7 +79,7 @@
 class MasterDevice
 {
     public:
-        MasterDevice();
+        MasterDevice(unsigned int = 0U);
         ~MasterDevice();
 
         void setIndex(unsigned int);
@@ -89,6 +89,8 @@
         void open(Permissions);
         void close();
 
+        void getModule(ec_ioctl_module_t *);
+
         void getMaster(ec_ioctl_master_t *);
         void getConfig(ec_ioctl_config_t *, unsigned int);
         void getConfigPdo(ec_ioctl_config_pdo_t *, unsigned int, uint8_t,
@@ -121,8 +123,11 @@
         void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t);
 #endif
 
+        unsigned int getMasterCount() const {return masterCount;}
+
     private:
         unsigned int index;
+        unsigned int masterCount;
         int fd;
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/NumberListParser.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -0,0 +1,230 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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 version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  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 license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#include <cstring>
+#include <sstream>
+#include <stdexcept>
+using namespace std;
+
+#include "NumberListParser.h"
+
+/*****************************************************************************/
+
+NumberListParser::NumberListParser():
+    max(0U),
+    hasMax(false)
+{
+}
+
+/*****************************************************************************/
+
+NumberListParser::~NumberListParser()
+{
+}
+
+/*****************************************************************************/
+
+NumberListParser::NumberList NumberListParser::parse(const char *data)
+{
+    NumberList ret;
+    unsigned int i = 0, size = strlen(data), firstNum = 0U, secondNum = 0U;
+    typedef enum {
+        SectionStart,
+        FirstNumber,
+        Range,
+        SecondNumber,
+        Finished
+    } State;
+    State state = SectionStart;
+
+    while (state != Finished) {
+        switch (state) {
+            case SectionStart:
+                if (i >= size) {
+                    state = Finished;
+                } else if (isNumeric(data[i])) {
+                    firstNum = parseNumber(data, &i, size);
+                    state = FirstNumber;
+                } else if (data[i] == '-') {
+                    firstNum = 0U;
+                    i++;
+                    state = Range;
+                } else if (data[i] == ',') {
+                    i++;
+                } else {
+                    stringstream err;
+                    err << "Invalid character " << data[i]
+                        << " at position " << i << "in state "
+                        << state << "." << endl;
+                    throw runtime_error(err.str());
+                }
+                break;
+
+            case FirstNumber:
+                if (i >= size) {
+                    ret.push_back(firstNum);
+                    state = Finished;
+                } else if (data[i] == '-') {
+                    i++;
+                    state = Range;
+                } else if (data[i] == ',') {
+                    i++;
+                    ret.push_back(firstNum);
+                    state = SectionStart;
+                } else {
+                    stringstream err;
+                    err << "Invalid character " << data[i]
+                        << " at position " << i << "in state "
+                        << state << "." << endl;
+                    throw runtime_error(err.str());
+                }
+                break;
+
+            case Range:
+                if (i >= size) {
+                    secondNum = maximum();
+                    NumberList r = range(firstNum, secondNum);
+                    ret.splice(ret.end(), r);
+                    state = Finished;
+                } else if (isNumeric(data[i])) {
+                    secondNum = parseNumber(data, &i, size);
+                    state = SecondNumber;
+                } else if (data[i] == ',') {
+                    i++;
+                    secondNum = maximum();
+                    NumberList r = range(firstNum, secondNum);
+                    ret.splice(ret.end(), r);
+                    state = SectionStart;
+                } else {
+                    stringstream err;
+                    err << "Invalid character " << data[i]
+                        << " at position " << i << "in state "
+                        << state << "." << endl;
+                    throw runtime_error(err.str());
+                }
+                break;
+
+            case SecondNumber:
+                if (i >= size) {
+                    NumberList r = range(firstNum, secondNum);
+                    ret.splice(ret.end(), r);
+                    state = Finished;
+                } else if (data[i] == ',') {
+                    i++;
+                    NumberList r = range(firstNum, secondNum);
+                    ret.splice(ret.end(), r);
+                    state = SectionStart;
+                } else {
+                    stringstream err;
+                    err << "Invalid character " << data[i]
+                        << " at position " << i << "in state "
+                        << state << "." << endl;
+                    throw runtime_error(err.str());
+                }
+                break;
+
+            default:
+                {
+                    stringstream err;
+                    err << "Invalid state " << state << ".";
+                    throw runtime_error(err.str());
+                }
+        }
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+unsigned int NumberListParser::maximum()
+{
+    if (!hasMax) {
+        max = getMax();
+    }
+
+    return max;
+}
+
+/*****************************************************************************/
+
+bool NumberListParser::isNumeric(char c)
+{
+    return c >= '0' && c <= '9';
+}
+
+/*****************************************************************************/
+
+unsigned int NumberListParser::parseNumber(
+        const char *data,
+        unsigned int *i,
+        unsigned int size
+        )
+{
+    unsigned int numSize = 0U, ret;
+
+    while (*i + numSize < size && isNumeric(data[*i + numSize])) {
+        numSize++;
+    }
+
+    if (numSize) {
+        stringstream str;
+        str << string(data + *i, numSize);
+        str >> ret;
+    } else {
+        throw runtime_error("EOF");
+    }
+
+    *i = *i + numSize;
+    return ret;
+}
+
+/****************************************************************************/
+
+NumberListParser::NumberList NumberListParser::range(
+        unsigned int i,
+        unsigned int j
+        )
+{
+    NumberList ret;
+
+    if (i <= j) {
+        for (; i <= j; i++) {
+            ret.push_back(i);
+        }
+    } else {
+        for (; i >= j; i--) {
+            ret.push_back(i);
+        }
+    }
+
+    return ret;
+}
+
+/****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/NumberListParser.h	Wed Feb 24 16:27:11 2010 +0100
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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 version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  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 license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#include <list>
+using namespace std;
+
+/*****************************************************************************/
+
+class NumberListParser
+{
+    public:
+        NumberListParser();
+        ~NumberListParser();
+
+        typedef list<unsigned int> NumberList;
+
+        NumberList parse(const char *);
+
+        virtual unsigned int getMax() = 0;
+
+    private:
+        unsigned int max;
+        bool hasMax;
+
+        unsigned int maximum();
+
+        static bool isNumeric(char);
+        static unsigned int parseNumber(const char *, unsigned int *,
+                unsigned int);
+        static NumberList range(unsigned int, unsigned int);
+};
+
+/****************************************************************************/
--- a/tool/main.cpp	Tue Feb 23 17:40:46 2010 +0100
+++ b/tool/main.cpp	Wed Feb 24 16:27:11 2010 +0100
@@ -61,19 +61,21 @@
 #include "CommandVersion.h"
 #include "CommandXml.h"
 
+#include "NumberListParser.h"
+#include "MasterDevice.h"
+
 /*****************************************************************************/
 
 typedef list<Command *> CommandList;
 CommandList commandList;
 
-MasterDevice masterDev;
-
 string binaryBaseName;
 string commandName;
 Command::StringVector commandArgs;
 
 // option variables
-unsigned int masterIndex = 0;
+list<unsigned int> masterIndices;
+string masterIndexList = "-"; // all masters
 int slavePosition = -1;
 int slaveAlias = -1;
 int domainIndex = -1;
@@ -128,6 +130,20 @@
 
 /*****************************************************************************/
 
+class MasterIndexParser:
+    public NumberListParser
+{
+    unsigned int getMax()
+    {
+        MasterDevice dev;
+        dev.setIndex(0U);
+        dev.open(MasterDevice::Read);
+        return dev.getMasterCount() - 1;
+    };
+};
+
+/*****************************************************************************/
+
 void getOptions(int argc, char **argv)
 {
     int c, argCount;
@@ -153,16 +169,7 @@
 
         switch (c) {
             case 'm':
-                str.clear();
-                str.str("");
-                str << optarg;
-                str >> resetiosflags(ios::basefield) // guess base from prefix
-                    >> masterIndex;
-                if (str.fail() || masterIndex < 0) {
-                    cerr << "Invalid master number " << optarg << "!" << endl
-                        << endl << usage();
-                    exit(1);
-                }
+                masterIndexList = optarg;
                 break;
 
             case 'a':
@@ -252,6 +259,19 @@
         }
     }
 
+    try {
+        MasterIndexParser p;
+        masterIndices = p.parse(masterIndexList.c_str());
+    } catch (MasterDeviceException &e) {
+        cerr << "Failed to obtain number of masters: " << e.what() << endl;
+        exit(1);
+    } catch (runtime_error &e) {
+        cerr << "Invalid master argument " << masterIndexList
+            << ": " << e.what() << endl
+            << endl << usage();
+        exit(1);
+    }
+
     commandName = argv[optind];
     while (++optind < argc)
         commandArgs.push_back(string(argv[optind]));
@@ -323,13 +343,19 @@
     getOptions(argc, argv);
 
     matchingCommands = getMatchingCommands(commandName);
-    masterDev.setIndex(masterIndex);
+
+    if (masterIndices.empty()) {
+        cerr << "List of master indices may not be empty!" << endl
+            << endl << usage();
+        exit(1);
+    }
 
     if (matchingCommands.size()) {
         if (matchingCommands.size() == 1) {
             cmd = matchingCommands.front();
             if (!helpRequested) {
                 try {
+                    cmd->setMasterIndices(masterIndices);
                     cmd->setVerbosity(verbosity);
                     cmd->setAlias(slaveAlias);
                     cmd->setPosition(slavePosition);
@@ -337,7 +363,7 @@
                     cmd->setDataType(dataTypeStr);
                     cmd->setOutputFile(outputFile);
                     cmd->setForce(force);
-                    cmd->execute(masterDev, commandArgs);
+                    cmd->execute(commandArgs);
                 } catch (InvalidUsageException &e) {
                     cerr << e.what() << endl << endl;
                     cerr << binaryBaseName << " " << cmd->helpString();