Redesigned command interface.
authorFlorian Pose <fp@igh-essen.com>
Thu, 24 Jul 2008 13:27:06 +0000
changeset 1142 59be91dfcbe1
parent 1141 7ffbca63fc72
child 1143 09ee878d7214
Redesigned command interface.
tool/Command.cpp
tool/Command.h
tool/CommandAlias.cpp
tool/CommandAlias.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/CommandMaster.cpp
tool/CommandMaster.h
tool/CommandPdos.cpp
tool/CommandPdos.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/CommandXml.cpp
tool/CommandXml.h
tool/Makefile.am
tool/byteorder.h
tool/cmd_alias.cpp
tool/cmd_config.cpp
tool/cmd_data.cpp
tool/cmd_debug.cpp
tool/cmd_domain.cpp
tool/cmd_download.cpp
tool/cmd_master.cpp
tool/cmd_pdos.cpp
tool/cmd_sdos.cpp
tool/cmd_sii_read.cpp
tool/cmd_sii_write.cpp
tool/cmd_slaves.cpp
tool/cmd_states.cpp
tool/cmd_upload.cpp
tool/cmd_xml.cpp
tool/globals.h
tool/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/Command.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include "Command.h"
+
+/*****************************************************************************/
+
+Command::Command(const string &name, const string &briefDesc):
+    name(name),
+    briefDesc(briefDesc),
+    verbosity(Normal)
+{
+}
+
+/*****************************************************************************/
+
+Command::~Command()
+{
+}
+
+/*****************************************************************************/
+
+void Command::setVerbosity(Verbosity v)
+{
+	verbosity = v;
+};
+
+/****************************************************************************/
+
+bool Command::matchesSubstr(const string &cmd) const
+{
+    return name.substr(0, cmd.length()) == cmd;
+}
+    
+/****************************************************************************/
+
+bool Command::matchesAbbrev(const string &abb) const
+{
+    unsigned int i;
+    size_t pos = 0;
+
+    for (i = 0; i < abb.length(); i++) {
+        pos = name.find(abb[i], pos);
+        if (pos == string::npos)
+            return false;
+    }
+
+    return true;
+}
+    
+/*****************************************************************************/
+
+void Command::throwInvalidUsageException(const stringstream &s)
+{
+    throw InvalidUsageException(s);
+}
+
+/*****************************************************************************/
+
+void Command::throwCommandException(const stringstream &s)
+{
+    throw CommandException(s);
+}
+
+/*****************************************************************************/
+
+string Command::numericInfo()
+{
+    stringstream str;
+
+    str << "Numerical values can be specified either with decimal (no" << endl
+        << "prefix), octal (prefix '0') or hexadecimal (prefix '0x') base."
+        << endl;
+
+    return str.str();
+}
+
+/****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/Command.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,117 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMAND_H__
+#define __COMMAND_H__
+
+#include <stdexcept>
+#include <vector>
+using namespace std;
+
+#include "MasterDevice.h"
+
+/*****************************************************************************/
+
+extern unsigned int masterIndex;
+extern int slavePosition;
+extern int domainIndex;
+extern string dataTypeStr;
+extern bool force;
+
+/****************************************************************************/
+
+class InvalidUsageException:
+    public runtime_error
+{
+    friend class Command;
+
+    protected:
+        /** Constructor with stringstream parameter. */
+        InvalidUsageException(
+                const stringstream &s /**< Message. */
+                ): runtime_error(s.str()) {}
+};
+
+/****************************************************************************/
+
+class CommandException:
+    public runtime_error
+{
+    friend class Command;
+
+    protected:
+        /** Constructor with stringstream parameter. */
+        CommandException(
+                const stringstream &s /**< Message. */
+                ): runtime_error(s.str()) {}
+};
+
+/****************************************************************************/
+
+class Command
+{
+    public:
+        Command(const string &, const string &);
+		virtual ~Command();
+
+        enum Verbosity {
+            Quiet,
+            Normal,
+            Verbose
+        };
+        void setVerbosity(Verbosity);
+
+        const string &getName() const;
+        const string &getBriefDescription() const;
+		Verbosity getVerbosity() const;
+
+        bool matchesSubstr(const string &) const;
+        bool matchesAbbrev(const string &) const;
+
+        virtual string helpString() const = 0;
+
+        typedef vector<string> StringVector;
+        virtual void execute(MasterDevice &, const StringVector &) = 0;
+
+    protected:
+        void throwInvalidUsageException(const stringstream &);
+        void throwCommandException(const stringstream &);
+
+		enum {BreakAfterBytes = 16};
+        static string numericInfo();
+
+    private:
+		string name;
+        string briefDesc;
+        Verbosity verbosity;
+
+        Command();
+};
+
+/****************************************************************************/
+
+inline const string &Command::getName() const
+{
+    return name;
+}
+
+/****************************************************************************/
+
+inline const string &Command::getBriefDescription() const
+{
+    return briefDesc;
+}
+
+/****************************************************************************/
+
+inline Command::Verbosity Command::getVerbosity() const
+{
+    return verbosity;
+}
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandAlias.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,153 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+using namespace std;
+
+#include "CommandAlias.h"
+#include "sii_crc.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandAlias::CommandAlias():
+    Command("alias", "Write alias addresses.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandAlias::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS] <ALIAS>" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "Arguments:" << endl
+        << "  ALIAS must be an unsigned 16 bit number. Zero means no alias."
+        << endl << endl
+        << "Command-specific options:" << endl
+        << "  --slave -s <index>  Positive numerical ring position, or 'all'"
+        << endl
+        << "                      for all slaves (default). The --force"
+        << endl
+        << "                      option is required in this case." << endl
+        << "  --force -f          Acknowledge writing aliases of all" << endl
+        << "                      slaves." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/*****************************************************************************/
+
+/** Writes the Secondary slave address (alias) to the slave's SII.
+ */
+void CommandAlias::execute(MasterDevice &m, const StringVector &args)
+{
+    uint16_t alias;
+    stringstream err, strAlias;
+    int number;
+    unsigned int numSlaves, i;
+
+    if (args.size() != 1) {
+        err << "'" << getName() << "' takes exactly one argument!";
+        throwInvalidUsageException(err);
+    }
+
+    strAlias << args[0];
+    strAlias
+        >> resetiosflags(ios::basefield) // guess base from prefix
+        >> number;
+    if (strAlias.fail() || number < 0x0000 || number > 0xffff) {
+        err << "Invalid alias '" << args[0] << "'!";
+        throwInvalidUsageException(err);
+    }
+    alias = number;
+
+    if (slavePosition == -1) {
+        if (!force) {
+            err << "This will write the alias addresses of all slaves to "
+                << alias << "! Please specify --force to proceed.";
+            throwCommandException(err);
+        }
+
+        m.open(MasterDevice::ReadWrite);
+        numSlaves = m.slaveCount();
+
+        for (i = 0; i < numSlaves; i++) {
+            writeSlaveAlias(m, i, alias);
+        }
+    } else {
+        m.open(MasterDevice::ReadWrite);
+        writeSlaveAlias(m, slavePosition, alias);
+    }
+}
+
+/*****************************************************************************/
+
+/** Writes the Secondary slave address (alias) to the slave's SII.
+ */
+void CommandAlias::writeSlaveAlias(
+        MasterDevice &m,
+        uint16_t slavePosition,
+        uint16_t alias
+        )
+{
+    ec_ioctl_slave_sii_t data;
+    ec_ioctl_slave_t slave;
+    stringstream err;
+    uint8_t crc;
+
+    m.getSlave(&slave, slavePosition);
+
+    if (slave.sii_nwords < 8) {
+        err << "Current SII contents are too small to set an alias "
+            << "(" << slave.sii_nwords << " words)!";
+        throwCommandException(err);
+    }
+
+    // read first 8 SII words
+    data.slave_position = slavePosition;
+    data.offset = 0;
+    data.nwords = 8;
+    data.words = new uint16_t[data.nwords];
+
+    try {
+        m.readSii(&data);
+    } catch (MasterDeviceException &e) {
+        delete [] data.words;
+        err << "Failed to read SII: " << e.what();
+        throwCommandException(err);
+    }
+
+    // write new alias address in word 4
+    data.words[4] = cputole16(alias);
+
+    // calculate checksum over words 0 to 6
+    crc = calcSiiCrc((const uint8_t *) data.words, 14);
+
+    // write new checksum into first byte of word 7
+    *(uint8_t *) (data.words + 7) = crc;
+
+    // write first 8 words with new alias and checksum
+    try {
+        m.writeSii(&data);
+    } catch (MasterDeviceException &e) {
+        delete [] data.words;
+        err << "Failed to read SII: " << e.what();
+        throwCommandException(err);
+    }
+
+    delete [] data.words;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandAlias.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDALIAS_H__
+#define __COMMANDALIAS_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandAlias:
+    public Command
+{
+    public:
+        CommandAlias();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+        void writeSlaveAlias(MasterDevice &, uint16_t, uint16_t);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandConfig.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,260 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <list>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+using namespace std;
+
+#include "CommandConfig.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandConfig::CommandConfig():
+    Command("config", "Show slave configurations.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandConfig::helpString() const
+{
+    stringstream str;
+
+    str << "[OPTIONS]" << endl
+    	<< endl
+    	<< "Output information about the slave configurations" << endl
+    	<< "supplied by the application." << endl
+    	<< endl
+    	<< "Without the --verbose option, slave configurations are" << endl
+    	<< "output one-per-line. Example:" << endl
+    	<< endl
+    	<< "1001:0  0x0000003b/0x02010000  -  -" << endl
+    	<< "|       |                      |  |" << endl
+    	<< "|       |                      |  \\- Slave is operational."
+		<< endl
+    	<< "|       |                      \\- Slave has been found." << endl
+    	<< "|       \\- Hexadecimal vendor ID and product code, separated"
+		<< endl
+    	<< "|          by a slash." << endl
+    	<< "\\- Decimal alias and position, separated by a colon." << endl
+    	<< endl
+    	<< "With the --verbose option given, the configured Pdos and" << endl
+    	<< "Sdos are additionally printed." << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --verbose  -v  Show detailed configurations." << endl;
+
+	return str.str();
+}
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+bool operator<(const ec_ioctl_config_t &a, const ec_ioctl_config_t &b)
+{
+    return a.alias < b.alias
+        || (a.alias == b.alias && a.position < b.position);
+}
+
+/*****************************************************************************/
+
+/** Lists the bus configuration.
+ */
+void CommandConfig::execute(MasterDevice &m, const StringVector &args)
+{
+    ec_ioctl_master_t master;
+    unsigned int i;
+    ec_ioctl_config_t config;
+    ConfigList configList;
+
+    m.open(MasterDevice::Read);
+    m.getMaster(&master);
+
+    for (i = 0; i < master.config_count; i++) {
+        m.getConfig(&config, i);
+        configList.push_back(config);
+    }
+
+    configList.sort();
+
+    if (getVerbosity() == Verbose) {
+        showDetailedConfigs(m, configList);
+    } else {
+        listConfigs(configList);
+    }
+}
+
+/*****************************************************************************/
+
+/** Lists the complete bus configuration.
+ */
+void CommandConfig::showDetailedConfigs(
+		MasterDevice &m,
+		const ConfigList &configList
+		)
+{
+    ConfigList::const_iterator configIter;
+    unsigned int j, k, l;
+    ec_ioctl_config_pdo_t pdo;
+    ec_ioctl_config_pdo_entry_t entry;
+    ec_ioctl_config_sdo_t sdo;
+
+    for (configIter = configList.begin();
+            configIter != configList.end();
+            configIter++) {
+
+        cout << "Alias: "
+            << dec << configIter->alias << endl
+            << "Position: " << configIter->position << endl
+            << "Vendor Id: 0x"
+            << hex << setfill('0')
+            << setw(8) << configIter->vendor_id << endl
+            << "Product code: 0x"
+            << setw(8) << configIter->product_code << endl
+            << "Attached: " << (configIter->attached ? "yes" : "no") << endl
+            << "Operational: " << (configIter->operational ? "yes" : "no") << endl;
+
+        for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
+            if (configIter->syncs[j].pdo_count) {
+                cout << "SM" << dec << j << " ("
+                    << (configIter->syncs[j].dir == EC_DIR_INPUT
+                            ? "Input" : "Output") << ")" << endl;
+                for (k = 0; k < configIter->syncs[j].pdo_count; k++) {
+                    m.getConfigPdo(&pdo, configIter->config_index, j, k);
+
+                    cout << "  Pdo 0x" << hex
+                        << setw(4) << pdo.index
+                        << " \"" << pdo.name << "\"" << endl;
+
+                    for (l = 0; l < pdo.entry_count; l++) {
+                        m.getConfigPdoEntry(&entry,
+                                configIter->config_index, j, k, l);
+
+                        cout << "    Pdo entry 0x" << hex
+                            << setw(4) << entry.index << ":"
+                            << setw(2) << (unsigned int) entry.subindex
+                            << ", " << dec << (unsigned int) entry.bit_length
+                            << " bit, \"" << entry.name << "\"" << endl;
+                    }
+                }
+            }
+        }
+
+        cout << "Sdo configuration:" << endl;
+        if (configIter->sdo_count) {
+            for (j = 0; j < configIter->sdo_count; j++) {
+                m.getConfigSdo(&sdo, configIter->config_index, j);
+
+                cout << "  0x"
+                    << hex << setfill('0')
+                    << setw(4) << sdo.index << ":"
+                    << setw(2) << (unsigned int) sdo.subindex
+                    << ", " << dec << 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;
+            }
+        } else {
+            cout << "  None." << endl;
+        }
+
+        cout << endl;
+    }
+}
+
+/*****************************************************************************/
+
+/** Lists the bus configuration.
+ */
+void CommandConfig::listConfigs(const ConfigList &configList)
+{
+    ConfigList::const_iterator configIter;
+    stringstream str;
+    Info info;
+    typedef list<Info> InfoList;
+    InfoList list;
+    InfoList::const_iterator iter;
+    unsigned int maxAliasWidth = 0, maxPosWidth = 0,
+                 maxAttWidth = 0, maxOpWidth = 0;
+
+    for (configIter = configList.begin();
+            configIter != configList.end();
+            configIter++) {
+
+        str << dec << configIter->alias;
+        info.alias = str.str();
+        str.clear();
+        str.str("");
+
+        str << configIter->position;
+        info.pos = str.str();
+        str.clear();
+        str.str("");
+
+        str << hex << setfill('0')
+            << "0x" << setw(8) << configIter->vendor_id
+            << "/0x" << setw(8) << configIter->product_code;
+        info.ident = str.str();
+        str.clear();
+        str.str("");
+
+        str << (configIter->attached ? "attached" : "-");
+        info.att = str.str();
+        str.clear();
+        str.str("");
+
+        str << (configIter->operational ? "operational" : "-");
+        info.op = str.str();
+        str.clear();
+        str.str("");
+
+        list.push_back(info);
+
+        if (info.alias.length() > maxAliasWidth)
+            maxAliasWidth = info.alias.length();
+        if (info.pos.length() > maxPosWidth)
+            maxPosWidth = info.pos.length();
+        if (info.att.length() > maxAttWidth)
+            maxAttWidth = info.att.length();
+        if (info.op.length() > maxOpWidth)
+            maxOpWidth = info.op.length();
+    }
+
+    for (iter = list.begin(); iter != list.end(); iter++) {
+        cout << setfill(' ') << right
+            << setw(maxAliasWidth) << iter->alias
+            << ":" << left
+            << setw(maxPosWidth) << iter->pos
+            << "  "
+            << iter->ident
+            << "  "
+            << setw(maxAttWidth) << iter->att << "  "
+            << setw(maxOpWidth) << iter->op << "  "
+            << endl;
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandConfig.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDCONFIG_H__
+#define __COMMANDCONFIG_H__
+
+#include <list>
+using namespace std;
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandConfig:
+    public Command
+{
+    public:
+        CommandConfig();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+	protected:
+		struct Info {
+			string alias;
+			string pos;
+			string ident;
+			string att;
+			string op;
+		};
+
+		typedef list<ec_ioctl_config_t> ConfigList;
+
+		void showDetailedConfigs(MasterDevice &, const ConfigList &);
+		void listConfigs(const ConfigList &);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandData.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+using namespace std;
+
+#include "CommandData.h"
+
+/*****************************************************************************/
+
+CommandData::CommandData():
+    Command("data", "Output binary domain process data.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandData::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --domain -d <index>  Positive numerical domain index, or" << endl
+    	<< "                       'all' for all domains (default). In" << endl
+    	<< "                       this case, data of all domains are" << endl
+		<< "                       concatenated." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandData::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (domainIndex == -1) {
+        unsigned int i;
+        ec_ioctl_master_t master;
+
+        m.getMaster(&master);
+
+        for (i = 0; i < master.domain_count; i++) {
+            outputDomainData(m, i);
+        }
+    } else {
+        outputDomainData(m, domainIndex);
+    }
+}
+
+/****************************************************************************/
+
+void CommandData::outputDomainData(MasterDevice &m, unsigned int domainIndex)
+{
+    ec_ioctl_domain_t domain;
+    ec_ioctl_domain_data_t data;
+    unsigned char *processData;
+    unsigned int i;
+    
+    m.getDomain(&domain, domainIndex);
+
+    if (!domain.data_size)
+        return;
+
+    processData = new unsigned char[domain.data_size];
+
+    try {
+        m.getData(&data, domainIndex, domain.data_size, processData);
+    } catch (MasterDeviceException &e) {
+        delete [] processData;
+        throw e;
+    }
+
+    for (i = 0; i < data.data_size; i++)
+        cout << processData[i];
+    cout.flush();
+
+    delete [] processData;
+}
+
+/****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandData.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDDATA_H__
+#define __COMMANDDATA_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandData:
+    public Command
+{
+    public:
+        CommandData();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		void outputDomainData(MasterDevice &, unsigned int);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDebug.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,70 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <sstream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandDebug.h"
+
+/*****************************************************************************/
+
+CommandDebug::CommandDebug():
+    Command("debug", "Set the master's debug level.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandDebug::helpString() const
+{
+    stringstream str;
+
+	str << getName() << " <LEVEL>" << endl
+		<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "Debug messages are printed to syslog." << endl
+    	<< endl
+    	<< "Arguments:" << endl
+    	<< "  LEVEL can have one of the following values:" << endl
+    	<< "        0 for no debugging output," << endl
+    	<< "        1 for some debug messages, or" << endl
+    	<< "        2 for printing all frame contents (use with caution!)."
+		<< endl << endl
+    	<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandDebug::execute(MasterDevice &m, const StringVector &args)
+{
+    stringstream str;
+    int debugLevel;
+    
+    if (args.size() != 1) {
+        stringstream err;
+        err << "'" << getName() << "' takes exactly one argument!";
+        throwInvalidUsageException(err);
+    }
+
+    str << args[0];
+    str >> resetiosflags(ios::basefield) // guess base from prefix
+        >> debugLevel;
+
+    if (str.fail()) {
+        stringstream err;
+        err << "Invalid debug level '" << args[0] << "'!";
+        throwInvalidUsageException(err);
+    }
+
+    m.open(MasterDevice::ReadWrite);
+    m.setDebug(debugLevel);
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDebug.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDDEBUG_H__
+#define __COMMANDDEBUG_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandDebug:
+    public Command
+{
+    public:
+        CommandDebug();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDomains.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandDomains.h"
+
+/*****************************************************************************/
+
+CommandDomains::CommandDomains():
+    Command("domains", "Show configured domains.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandDomains::helpString() const
+{
+    stringstream str;
+
+	str << getName() << " [OPTIONS]"
+    	<< endl
+    	<< getBriefDescription() << endl
+        << endl
+    	<< "Without the --verbose option, the domains are displayed" << endl
+        << "one-per-line. Example:" << endl
+    	<< endl
+    	<< "Domain0: LogBaseAddr 0x00000000, Size   6, WorkingCounter 0/1"
+		<< endl << endl
+    	<< "The domain's base address for the logical datagram" << endl
+    	<< "(LRD/LWR/LRW) is displayed followed by the domain's" << endl
+    	<< "process data size in byte. The last values are the current" << endl
+    	<< "datagram working counter sum and the expected working" << endl
+    	<< "counter sum. If the values are equal, all Pdos are exchanged."
+		<< endl << endl
+    	<< "If the --verbose option is given, the participating slave" << endl
+    	<< "configurations/FMMUs and the current process data are" << endl
+    	<< "additionally displayed:" << endl
+    	<< endl
+    	<< "Domain1: LogBaseAddr 0x00000006, Size   6, WorkingCounter 0/1"
+		<< endl
+    	<< "  SlaveConfig 1001:0, SM3 ( Input), LogAddr 0x00000006, Size 6"
+		<< endl
+    	<< "    00 00 00 00 00 00" << endl
+    	<< endl
+    	<< "The process data are displayed as hexadecimal bytes." << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --domain  -d <index>  Positive numerical domain index," << endl
+    	<< "                        or 'all' for all domains (default)."
+		<< endl
+    	<< "  --verbose -v          Show FMMUs and process data" << endl
+		<< "                        additionally." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandDomains::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (domainIndex == -1) {
+        unsigned int i;
+        ec_ioctl_master_t master;
+
+        m.getMaster(&master);
+
+        for (i = 0; i < master.domain_count; i++) {
+            showDomain(m, i);
+        }
+    } else {
+        showDomain(m, domainIndex);
+    }
+}
+
+/****************************************************************************/
+
+void CommandDomains::showDomain(MasterDevice &m, unsigned int domainIndex)
+{
+    ec_ioctl_domain_t domain;
+    unsigned char *processData;
+    ec_ioctl_domain_data_t data;
+    unsigned int i, j;
+    ec_ioctl_domain_fmmu_t fmmu;
+    unsigned int dataOffset;
+    
+    m.getDomain(&domain, domainIndex);
+
+	cout << "Domain" << dec << domainIndex << ":"
+		<< " LogBaseAddr 0x"
+		<< hex << setfill('0')
+        << setw(8) << domain.logical_base_address
+		<< ", Size " << dec << setfill(' ')
+        << setw(3) << domain.data_size
+		<< ", WorkingCounter "
+		<< domain.working_counter << "/"
+        << domain.expected_working_counter << endl;
+
+    if (!domain.data_size || getVerbosity() != Verbose)
+        return;
+
+    processData = new unsigned char[domain.data_size];
+
+    try {
+        m.getData(&data, domainIndex, domain.data_size, processData);
+    } catch (MasterDeviceException &e) {
+        delete [] processData;
+        throw e;
+    }
+
+    for (i = 0; i < domain.fmmu_count; i++) {
+        m.getFmmu(&fmmu, domainIndex, i);
+
+        cout << "  SlaveConfig "
+            << dec << fmmu.slave_config_alias
+            << ":" << fmmu.slave_config_position
+            << ", SM" << (unsigned int) fmmu.sync_index << " ("
+            << setfill(' ') << setw(6)
+            << (fmmu.dir == EC_DIR_INPUT ? "Input" : "Output")
+            << "), LogAddr 0x"
+            << hex << setfill('0')
+            << setw(8) << fmmu.logical_address
+            << ", Size " << dec << fmmu.data_size << endl;
+
+        dataOffset = fmmu.logical_address - domain.logical_base_address;
+        if (dataOffset + fmmu.data_size > domain.data_size) {
+            stringstream err;
+            delete [] processData;
+            err << "Fmmu information corrupted!";
+            throwCommandException(err);
+        }
+
+        cout << "    " << hex << setfill('0');
+        for (j = 0; j < fmmu.data_size; j++) {
+            if (j && !(j % BreakAfterBytes))
+                cout << endl << "    ";
+            cout << setw(2)
+                << (unsigned int) *(processData + dataOffset + j) << " ";
+        }
+        cout << endl;
+    }
+
+    delete [] processData;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDomains.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDDOMAINS_H__
+#define __COMMANDDOMAINS_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandDomains:
+    public Command
+{
+    public:
+        CommandDomains();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		void showDomain(MasterDevice &, unsigned int);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDownload.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,219 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandDownload.h"
+#include "coe_datatypes.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandDownload::CommandDownload():
+    Command("download", "Write an Sdo entry to a slave.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandDownload::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS] <INDEX> <SUBINDEX> <VALUE>" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "The data type of the Sdo entry is taken from the Sdo" << endl
+		<< "dictionary by default. It can be overridden with the" << endl
+		<< "--type option. If the slave does not support the Sdo" << endl
+		<< "information service or the Sdo is not in the dictionary," << endl
+		<< "the --type option is mandatory." << endl
+    	<< endl
+    	<< "These are the valid Sdo entry data types:" << endl
+    	<< "  int8, int16, int32, uint8, uint16, uint32, string." << endl
+    	<< endl
+    	<< "Arguments:"
+    	<< "  INDEX    is the Sdo index and must be an unsigned" << endl
+		<< "           16 bit number." << endl
+    	<< "  SUBINDEX is the Sdo entry subindex and must be an" << endl
+		<< "           unsigned 8 bit number." << endl
+    	<< "  VALUE    is the value to download and must correspond" << endl
+		<< "           to the Sdo entry datatype (see above)." << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --slave -s <index>  Positive numerical ring position" << endl
+		<< "                      (mandatory)." << endl
+    	<< "  --type  -t <type>   Forced Sdo entry data type (see" << endl
+		<< "                      above)." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandDownload::execute(MasterDevice &m, const StringVector &args)
+{
+    stringstream strIndex, strSubIndex, strValue, err;
+    ec_ioctl_slave_sdo_download_t data;
+    unsigned int number;
+    const CoEDataType *dataType = NULL;
+
+    if (slavePosition < 0) {
+        err << "'" << getName() << "' requires a slave! "
+            << "Please specify --slave.";
+        throwInvalidUsageException(err);
+    }
+    data.slave_position = slavePosition;
+
+    if (args.size() != 3) {
+        err << "'" << getName() << "' takes 3 arguments!";
+        throwInvalidUsageException(err);
+    }
+
+    strIndex << args[0];
+    strIndex
+        >> resetiosflags(ios::basefield) // guess base from prefix
+        >> data.sdo_index;
+    if (strIndex.fail()) {
+        err << "Invalid Sdo index '" << args[0] << "'!";
+        throwInvalidUsageException(err);
+    }
+
+    strSubIndex << args[1];
+    strSubIndex
+        >> resetiosflags(ios::basefield) // guess base from prefix
+        >> number;
+    if (strSubIndex.fail() || number > 0xff) {
+        err << "Invalid Sdo subindex '" << args[1] << "'!";
+        throwInvalidUsageException(err);
+    }
+    data.sdo_entry_subindex = number;
+
+    if (dataTypeStr != "") { // data type specified
+        if (!(dataType = findDataType(dataTypeStr))) {
+            err << "Invalid data type '" << dataTypeStr << "'!";
+            throwInvalidUsageException(err);
+        }
+    } else { // no data type specified: fetch from dictionary
+        ec_ioctl_slave_sdo_entry_t entry;
+
+        m.open(MasterDevice::ReadWrite);
+
+        try {
+            m.getSdoEntry(&entry, slavePosition,
+                    data.sdo_index, data.sdo_entry_subindex);
+        } catch (MasterDeviceException &e) {
+            err << "Failed to determine Sdo entry data type. "
+                << "Please specify --type.";
+            throwCommandException(err);
+        }
+        if (!(dataType = findDataType(entry.data_type))) {
+            err << "Pdo entry has unknown data type 0x"
+                << hex << setfill('0') << setw(4) << entry.data_type << "!"
+                << " Please specify --type.";
+            throwCommandException(err);
+        }
+    }
+
+    if (dataType->byteSize) {
+        data.data_size = dataType->byteSize;
+    } else {
+        data.data_size = DefaultBufferSize;
+    }
+
+    data.data = new uint8_t[data.data_size + 1];
+
+    strValue << args[2];
+    strValue >> resetiosflags(ios::basefield); // guess base from prefix
+    strValue.exceptions(ios::failbit);
+
+    try {
+        switch (dataType->coeCode) {
+            case 0x0002: // int8
+                {
+                    int16_t val; // uint8_t is interpreted as char
+                    strValue >> val;
+                    if (val > 127 || val < -128)
+                        throw ios::failure("Value out of range");
+                    *data.data = val;
+                    break;
+                }
+            case 0x0003: // int16
+                {
+                    int16_t val;
+                    strValue >> val;
+                    *(int16_t *) data.data = cputole16(val);
+                    break;
+                }
+            case 0x0004: // int32
+                {
+                    int32_t val;
+                    strValue >> val;
+                    *(int32_t *) data.data = cputole32(val);
+                    break;
+                }
+            case 0x0005: // uint8
+                {
+                    uint16_t val; // uint8_t is interpreted as char
+                    strValue >> val;
+                    if (val > 0xff)
+                        throw ios::failure("Value out of range");
+                    *data.data = val;
+                    break;
+                }
+            case 0x0006: // uint16
+                {
+                    uint16_t val;
+                    strValue >> val;
+                    *(uint16_t *) data.data = cputole16(val);
+                    break;
+                }
+            case 0x0007: // uint32
+                {
+                    uint32_t val;
+                    strValue >> val;
+                    *(uint32_t *) data.data = cputole32(val);
+                    break;
+                }
+            case 0x0009: // string
+                if (strValue.str().size() >= data.data_size) {
+                    err << "String too large";
+                    throwCommandException(err);
+                }
+                data.data_size = strValue.str().size();
+                strValue >> (char *) data.data;
+                break;
+
+            default:
+                delete [] data.data;
+                err << "Unknown data type 0x" << hex << dataType->coeCode;
+                throwCommandException(err);
+        }
+    } catch (ios::failure &e) {
+        delete [] data.data;
+        err << "Invalid value argument '" << args[2]
+            << "' for type '" << dataType->name << "'!";
+        throwInvalidUsageException(err);
+    }
+
+    m.open(MasterDevice::ReadWrite);
+
+	try {
+			m.sdoDownload(&data);
+	} catch(MasterDeviceException &e) {
+        delete [] data.data;
+        throw e;
+    }
+
+    delete [] data.data;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandDownload.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDDOWNLOAD_H__
+#define __COMMANDDOWNLOAD_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandDownload:
+    public Command
+{
+    public:
+        CommandDownload();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+	protected:
+		enum {DefaultBufferSize = 1024};
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandMaster.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,89 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandMaster.h"
+
+/*****************************************************************************/
+
+CommandMaster::CommandMaster():
+    Command("alias", "Show master and Ethernet device information.")
+{
+}
+
+/****************************************************************************/
+
+string CommandMaster::helpString() const
+{
+    stringstream str;
+
+	str << getName() << " [OPTIONS]" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --master -m <index>  Index of the master to use. Default: 0."
+		<< endl << endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandMaster::execute(MasterDevice &m, const StringVector &args)
+{
+    ec_ioctl_master_t data;
+    stringstream err;
+    unsigned int i;
+    
+    m.open(MasterDevice::Read);
+    m.getMaster(&data);
+
+    cout
+        << "Master" << masterIndex << endl
+        << "  Phase: ";
+
+    switch (data.phase) {
+        case 0:  cout << "Waiting for device..."; break;
+        case 1:  cout << "Idle"; break;
+        case 2:  cout << "Operation"; break;
+        default: cout << "???";
+    }
+
+    cout << endl
+        << "  Slaves: " << data.slave_count << endl;
+
+    for (i = 0; i < 2; i++) {
+        cout << "  Device" << i << ": ";
+        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
+                << "    Tx count: " << data.devices[i].tx_count << endl
+                << "    Rx count: " << data.devices[i].rx_count;
+        }
+        cout << endl;
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandMaster.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDMASTER_H__
+#define __COMMANDMASTER_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandMaster:
+    public Command
+{
+    public:
+        CommandMaster();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandPdos.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,142 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandPdos.h"
+
+/*****************************************************************************/
+
+CommandPdos::CommandPdos():
+    Command("pdos", "List Sync managers, Pdo assignment and mapping.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandPdos::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+        << endl
+    	<< "The information is displayed in three layers, which are" << endl
+    	<< "indented accordingly:" << endl
+    	<< endl
+    	<< "1) Sync managers - Contains the sync manager information" << endl
+    	<< "   from the SII: Index, physical start address, default" << endl
+    	<< "   size (value from the SII), control register and enable" << endl
+    	<< "   word. Example:" << endl
+		<< endl
+    	<< "   SM3: PhysAddr 0x1100, DefaultSize 0, ControlRegister 0x20,"
+		<< "Enable 1" << endl
+    	<< endl
+    	<< "2) Assigned Pdos - Pdo direction, hexadecimal index and" << endl
+		<< "   -if available- the Pdo name. Example:" << endl
+    	<< endl
+    	<< "   TxPdo 0x1a00 \"Channel1\"" << endl
+    	<< endl
+    	<< "3) Mapped Pdo entries - Pdo entry index and subindex (both" << endl
+    	<< "   hexadecimal), the length in bit and -if available- the" << endl
+    	<< "   description. Example:" << endl
+    	<< endl
+    	<< "   Pdo entry 0x3101:01, 8 bit, \"Status\"" << endl
+    	<< endl
+    	<< "Note, that the displayed Pdo assignment and Pdo mapping" << endl
+    	<< "information can either originate from the SII or from the" << endl
+		<< "CoE communication area." << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --slave -s <index>  Positive numerical ring position," << endl
+    	<< "                      or 'all' forall slaves (default)." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandPdos::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (slavePosition == -1) {
+        unsigned int numSlaves = m.slaveCount(), i;
+
+        for (i = 0; i < numSlaves; i++) {
+            listSlavePdos(m, i, true);
+        }
+    } else {
+        listSlavePdos(m, slavePosition, false);
+    }
+}
+
+/****************************************************************************/
+
+void CommandPdos::listSlavePdos(
+		MasterDevice &m,
+		uint16_t slavePosition,
+		bool withHeader
+		)
+{
+    ec_ioctl_slave_t slave;
+    ec_ioctl_slave_sync_t sync;
+    ec_ioctl_slave_sync_pdo_t pdo;
+    ec_ioctl_slave_sync_pdo_entry_t entry;
+    unsigned int i, j, k;
+    
+    m.getSlave(&slave, slavePosition);
+
+    if (withHeader)
+        cout << "=== Slave " << slavePosition << " ===" << endl;
+
+    for (i = 0; i < slave.sync_count; i++) {
+        m.getSync(&sync, slavePosition, i);
+
+        cout << "SM" << i << ":"
+            << " PhysAddr 0x"
+            << hex << setfill('0')
+            << setw(4) << sync.physical_start_address
+            << ", DefaultSize "
+            << dec << setfill(' ') << setw(4) << sync.default_size
+            << ", ControlRegister 0x"
+            << hex << setfill('0') << setw(2)
+            << (unsigned int) sync.control_register
+            << ", Enable " << dec << (unsigned int) sync.enable
+            << endl;
+
+        for (j = 0; j < sync.pdo_count; j++) {
+            m.getPdo(&pdo, slavePosition, i, j);
+
+            cout << "  " << (sync.control_register & 0x04 ? "R" : "T")
+                << "xPdo 0x"
+                << hex << setfill('0')
+                << setw(4) << pdo.index
+                << " \"" << pdo.name << "\"" << endl;
+
+            if (getVerbosity() == Quiet)
+                continue;
+
+            for (k = 0; k < pdo.entry_count; k++) {
+                m.getPdoEntry(&entry, slavePosition, i, j, k);
+
+                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;
+            }
+        }
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandPdos.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDPDOS_H__
+#define __COMMANDPDOS_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandPdos:
+    public Command
+{
+    public:
+        CommandPdos();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		void listSlavePdos(MasterDevice &, uint16_t, bool);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSdos.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,124 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandSdos.h"
+#include "coe_datatypes.h"
+
+/*****************************************************************************/
+
+CommandSdos::CommandSdos():
+    Command("sdos", "List Sdo dictionaries.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandSdos::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "Sdo dictionary information is displayed in two layers," << endl
+    	<< "which are indented accordingly:" << endl
+    	<< endl
+    	<< "1) Sdos - Hexadecimal Sdo index and the name. Example:" << endl
+    	<< endl
+    	<< "   Sdo 0x1018, \"Identity object\"" << endl
+    	<< endl
+    	<< "2) Sdo entries - Sdo index and Sdo entry subindex (both" << endl
+		<< "   hexadecimal) followed by the data type, the length in" << endl
+		<< "   bit, and the description. Example:" << endl
+    	<< endl
+    	<< "   0x1018:01, uint32, 32 bit, \"Vendor id\"" << endl
+    	<< endl
+    	<< "If the --quiet option is given, only the Sdos are printed."
+		<< endl << endl
+    	<< "Command-specific options:" << endl
+    	<< "  --slave -s <index>  Positive numerical ring position," << endl
+		<< "                      'all' for all slaves (default)." << endl
+    	<< "  --quiet -q          Print only Sdos (without Sdo" << endl
+		<< "                      entries)." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandSdos::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (slavePosition == -1) {
+        unsigned int numSlaves = m.slaveCount(), i;
+
+        for (i = 0; i < numSlaves; i++) {
+            listSlaveSdos(m, i, true);
+        }
+    } else {
+        listSlaveSdos(m, slavePosition, false);
+    }
+}
+
+/****************************************************************************/
+
+void CommandSdos::listSlaveSdos(
+		MasterDevice &m,
+		uint16_t slavePosition,
+		bool withHeader
+		)
+{
+    ec_ioctl_slave_t slave;
+    ec_ioctl_slave_sdo_t sdo;
+    ec_ioctl_slave_sdo_entry_t entry;
+    unsigned int i, j;
+    const CoEDataType *d;
+    
+    m.getSlave(&slave, slavePosition);
+
+    if (withHeader)
+        cout << "=== Slave " << slavePosition << " ===" << endl;
+
+    for (i = 0; i < slave.sdo_count; i++) {
+        m.getSdo(&sdo, slavePosition, i);
+
+        cout << "Sdo 0x"
+            << hex << setfill('0')
+            << setw(4) << sdo.sdo_index
+            << ", \"" << sdo.name << "\"" << endl;
+
+        if (getVerbosity() == Quiet)
+            continue;
+
+        for (j = 0; j <= sdo.max_subindex; j++) {
+            m.getSdoEntry(&entry, slavePosition, -i, j);
+
+            cout << "  0x" << hex << setfill('0')
+                << setw(4) << sdo.sdo_index << ":"
+                << setw(2) << (unsigned int) entry.sdo_entry_subindex
+                << ", ";
+
+            if ((d = findDataType(entry.data_type))) {
+                cout << d->name;
+            } else {
+                cout << "type " << setw(4) << entry.data_type;
+            }
+
+            cout << ", " << dec << entry.bit_length << " bit, \""
+                << entry.description << "\"" << endl;
+        }
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSdos.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDSDOS_H__
+#define __COMMANDSDOS_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandSdos:
+    public Command
+{
+    public:
+        CommandSdos();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		void listSlaveSdos(MasterDevice &, uint16_t, bool);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSiiRead.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,180 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandSiiRead.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandSiiRead::CommandSiiRead():
+    Command("sii_read", "Output a slave's SII contents.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandSiiRead::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]" << endl
+    	<< endl
+    	<< getBriefDescription() << endl
+    	<< endl
+    	<< "Without the --verbose option, binary SII contents are" << endl
+		<< "output." << endl
+    	<< endl
+    	<< "With the --verbose option given, a textual representation" << endl
+		<< "of the data is output, that is separated by SII category" << endl
+		<< "names." << endl
+    	<< endl
+    	<< "Command-specific options:" << endl
+    	<< "  --slave   -s <index>  Positive numerical ring position" << endl
+		<< "                        (mandatory)." << endl
+    	<< "  --verbose -v          Output textual data with" << endl
+		<< "                        category names." << endl
+    	<< endl
+		<< numericInfo();
+
+	return str.str();
+}
+
+/****************************************************************************/
+
+void CommandSiiRead::execute(MasterDevice &m, const StringVector &args)
+{
+    ec_ioctl_slave_sii_t data;
+    ec_ioctl_slave_t slave;
+    unsigned int i;
+    const uint16_t *categoryHeader;
+    uint16_t categoryType, categorySize;
+    stringstream err;
+
+    if (slavePosition < 0) {
+        err << "'" << getName() << "' requires a slave! "
+            << "Please specify --slave.";
+        throwInvalidUsageException(err);
+    }
+    data.slave_position = slavePosition;
+
+    m.open(MasterDevice::Read);
+
+    m.getSlave(&slave, slavePosition);
+
+    if (!slave.sii_nwords)
+        return;
+
+    data.offset = 0;
+    data.nwords = slave.sii_nwords;
+    data.words = new uint16_t[data.nwords];
+
+	try {
+		m.readSii(&data);
+	} catch (MasterDeviceException &e) {
+        delete [] data.words;
+		throw e;
+	}
+
+    if (getVerbosity() == Verbose) {
+        cout << "SII Area:" << hex << setfill('0');
+        for (i = 0; i < min(data.nwords, 0x0040U) * 2; i++) {
+            if (i % BreakAfterBytes) {
+                cout << " ";
+            } else {
+                cout << endl << "  ";
+            }
+            cout << setw(2) << (unsigned int) *((uint8_t *) data.words + i);
+        }
+        cout << endl;
+
+        if (data.nwords > 0x0040U) {
+            // cycle through categories
+            categoryHeader = data.words + 0x0040U;
+            categoryType = le16tocpu(*categoryHeader);
+            while (categoryType != 0xffff) {
+                cout << "SII Category 0x" << hex
+                    << setw(4) << categoryType
+                    << " (" << getCategoryName(categoryType) << ")" << flush;
+
+                if (categoryHeader + 1 > data.words + data.nwords) {
+                    err << "SII data seem to be corrupted!";
+                    throwCommandException(err);
+                }
+                categorySize = le16tocpu(*(categoryHeader + 1));
+                cout << ", " << dec << categorySize << " words" << flush;
+
+                if (categoryHeader + 2 + categorySize
+                        > data.words + data.nwords) {
+                    err << "SII data seem to be corrupted!";
+                    throwCommandException(err);
+                }
+
+                cout << hex;
+                for (i = 0; i < categorySize * 2U; i++) {
+                    if (i % BreakAfterBytes) {
+                        cout << " ";
+                    } else {
+                        cout << endl << "  ";
+                    }
+                    cout << setw(2) << (unsigned int)
+                        *((uint8_t *) (categoryHeader + 2) + i);
+                }
+                cout << endl;
+
+                if (categoryHeader + 2 + categorySize + 1
+                        > data.words + data.nwords) {
+                    err << "SII data seem to be corrupted!"; 
+                    throwCommandException(err);
+                }
+                categoryHeader += 2 + categorySize;
+                categoryType = le16tocpu(*categoryHeader);
+            }
+        }
+    } else {
+        for (i = 0; i < data.nwords; i++) {
+            uint16_t *w = data.words + i;
+            cout << *(uint8_t *) w << *((uint8_t *) w + 1);
+        }
+    }
+
+    delete [] data.words;
+}
+
+/****************************************************************************/
+
+const CommandSiiRead::CategoryName CommandSiiRead::categoryNames[] = {
+    {0x000a, "STRINGS"},
+    {0x0014, "DataTypes"},
+    {0x001e, "General"},
+    {0x0028, "FMMU"},
+    {0x0029, "SyncM"},
+    {0x0032, "TXPDO"},
+    {0x0033, "RXPDO"},
+    {0x003c, "DC"},
+    {}
+};
+
+/****************************************************************************/
+
+const char *CommandSiiRead::getCategoryName(uint16_t type)
+{
+    const CategoryName *cn = categoryNames;
+
+    while (cn->type) {
+        if (cn->type == type) {
+            return cn->name;
+        }
+        cn++;
+    }
+
+    return "unknown";
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSiiRead.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDSIIREAD_H__
+#define __COMMANDSIIREAD_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandSiiRead:
+    public Command
+{
+    public:
+        CommandSiiRead();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		struct CategoryName {
+			uint16_t type;
+			const char *name;
+		};
+		static const CategoryName categoryNames[];
+		static const char *getCategoryName(uint16_t);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSiiWrite.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,139 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+using namespace std;
+
+#include "CommandSiiWrite.h"
+#include "sii_crc.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandSiiWrite::CommandSiiWrite():
+    Command("sii_write", "Write SII contents to a slave.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandSiiWrite::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS] <FILENAME>" << endl
+        << endl 
+        << getBriefDescription() << endl
+        << endl
+        << "The file contents are checked for validity and integrity." << endl
+        << "These checks can be overridden with the --force option." << endl
+        << endl
+        << "Arguments:" << endl
+        << "  FILENAME must be a path to a file that contains a" << endl
+        << "           positive number of words." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --slave -s <index>  Positive numerical ring position" << endl
+        << "                      (mandatory)." << endl
+        << "  --force -f          Override validity checks." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandSiiWrite::execute(MasterDevice &m, const StringVector &args)
+{
+    stringstream err;
+    ec_ioctl_slave_sii_t data;
+    ifstream file;
+    unsigned int byte_size;
+    const uint16_t *categoryHeader;
+    uint16_t categoryType, categorySize;
+    uint8_t crc;
+
+    if (slavePosition < 0) {
+        err << "'" << getName() << "' requires a slave! "
+            << "Please specify --slave.";
+        throwInvalidUsageException(err);
+    }
+    data.slave_position = slavePosition;
+
+    if (args.size() != 1) {
+        err << "'" << getName() << "' takes exactly one argument!";
+        throwInvalidUsageException(err);
+    }
+
+    file.open(args[0].c_str(), ifstream::in | ifstream::binary);
+    if (file.fail()) {
+        err << "Failed to open '" << args[0] << "'!";
+        throwCommandException(err);
+    }
+
+    // get length of file
+    file.seekg(0, ios::end);
+    byte_size = file.tellg();
+    file.seekg(0, ios::beg);
+
+    if (!byte_size || byte_size % 2) {
+        err << "Invalid file size! Must be non-zero and even.";
+        throwCommandException(err);
+    }
+
+    data.nwords = byte_size / 2;
+    if (data.nwords < 0x0041 && !force) {
+        err << "SII data too short (" << data.nwords << " words)! Mimimum is"
+                " 40 fixed words + 1 delimiter. Use --force to write anyway.";
+        throwCommandException(err);
+    }
+
+    // allocate buffer and read file into buffer
+    data.words = new uint16_t[data.nwords];
+    file.read((char *) data.words, byte_size);
+    file.close();
+
+    if (!force) {
+        // calculate checksum over words 0 to 6
+        crc = calcSiiCrc((const uint8_t *) data.words, 14);
+        if (crc != ((const uint8_t *) data.words)[14]) {
+            err << "CRC incorrect. Must be 0x"
+                << hex << setfill('0') << setw(2) << (unsigned int) crc
+                << ". Use --force to write anyway.";
+            throwCommandException(err);
+        }
+
+        // cycle through categories to detect corruption
+        categoryHeader = data.words + 0x0040U;
+        categoryType = le16tocpu(*categoryHeader);
+        while (categoryType != 0xffff) {
+            if (categoryHeader + 1 > data.words + data.nwords) {
+                err << "SII data seem to be corrupted! "
+                    << "Use --force to write anyway.";
+                throwCommandException(err);
+            }
+            categorySize = le16tocpu(*(categoryHeader + 1));
+            if (categoryHeader + 2 + categorySize + 1
+                    > data.words + data.nwords) {
+                err << "SII data seem to be corrupted! "
+                    "Use --force to write anyway.";
+                throwCommandException(err);
+            }
+            categoryHeader += 2 + categorySize;
+            categoryType = le16tocpu(*categoryHeader);
+        }
+    }
+
+    // send data to master
+    m.open(MasterDevice::ReadWrite);
+    data.offset = 0;
+	m.writeSii(&data);
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSiiWrite.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDSIIWRITE_H__
+#define __COMMANDSIIWRITE_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandSiiWrite:
+    public Command
+{
+    public:
+        CommandSiiWrite();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSlaves.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,290 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+#include <list>
+using namespace std;
+
+#include "CommandSlaves.h"
+
+/*****************************************************************************/
+
+CommandSlaves::CommandSlaves():
+    Command("slaves", "Display slaves on the bus.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandSlaves::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "If the --verbose option is not given, the slaves are" << endl
+        << "displayed one-per-line. Example:" << endl
+        << endl
+        << "1  5555:0  PREOP  +  EL3162 2C. Ana. Input 0-10V" << endl
+        << "|  |    |  |      |  |" << endl
+        << "|  |    |  |      |  \\- Name from SII if avaliable," << endl
+        << "|  |    |  |      |     otherwise hexadecimal vendor ID" << endl
+        << "|  |    |  |      |     and product code separated by a" << endl
+        << "|  |    |  |      |     colon." << endl
+        << "|  |    |  |      \\- Error flag. '+' means no error," << endl
+        << "|  |    |  |         'E' means that scanning or" << endl
+        << "|  |    |  |         configuration failed." << endl
+        << "|  |    |  \\- Current slave state." << endl
+        << "|  |    \\- Relative position (decimal) after the last" << endl
+        << "|  |       slave with an alias address set." << endl
+        << "|  \\- Alias address of the slave (if set to non-zero)," << endl
+        << "|     or the alias of the last slave with an alias set," << endl
+        << "|     or zero if there is none." << endl
+        << "\\- Ring position (use this with any --slave option)." << endl
+        << endl
+        << "If the --verbose option is given, a detailed (multi-line)" << endl
+        << "description is output for each slave." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --slave   -s <index>  Positive numerical ring position," << endl
+        << "                        or 'all' for all slaves (default)." << endl
+        << "  --verbose -v          Show detailed slave information." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandSlaves::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (getVerbosity() == Verbose) {
+        if (slavePosition == -1) {
+            unsigned int numSlaves = m.slaveCount(), i;
+
+            for (i = 0; i < numSlaves; i++) {
+                showSlave(m, i);
+            }
+        } else {
+            showSlave(m, slavePosition);
+        }
+    } else {
+        listSlaves(m, slavePosition);
+    }
+}
+
+/****************************************************************************/
+
+void CommandSlaves::listSlaves(
+        MasterDevice &m,
+        int slavePosition
+        )
+{
+    unsigned int numSlaves, i;
+    ec_ioctl_slave_t slave;
+    uint16_t lastAlias, aliasIndex;
+    Info info;
+    typedef list<Info> InfoList;
+    InfoList infoList;
+    InfoList::const_iterator iter;
+    stringstream str;
+    unsigned int maxPosWidth = 0, maxAliasWidth = 0,
+                 maxRelPosWidth = 0, maxStateWidth = 0;
+    
+    numSlaves = m.slaveCount();
+
+    lastAlias = 0;
+    aliasIndex = 0;
+    for (i = 0; i < numSlaves; i++) {
+        m.getSlave(&slave, i);
+        
+        if (slave.alias) {
+            lastAlias = slave.alias;
+            aliasIndex = 0;
+        }
+
+        if (slavePosition == -1 || i == (unsigned int) slavePosition) {
+            str << dec << i;
+            info.pos = str.str();
+            str.clear();
+            str.str("");
+
+            str << lastAlias;
+            info.alias = str.str();
+            str.str("");
+
+            str << aliasIndex;
+            info.relPos = str.str();
+            str.str("");
+
+            info.state = slaveState(slave.state);
+            info.flag = (slave.error_flag ? 'E' : '+');
+
+            if (strlen(slave.name)) {
+                info.name = slave.name;
+            } else {
+                str << "0x" << hex << setfill('0')
+                    << setw(8) << slave.vendor_id << ":0x"
+                    << setw(8) << slave.product_code;
+                info.name = str.str();
+                str.str("");
+            }
+
+
+            infoList.push_back(info);
+
+            if (info.pos.length() > maxPosWidth)
+                maxPosWidth = info.pos.length();
+            if (info.alias.length() > maxAliasWidth)
+                maxAliasWidth = info.alias.length();
+            if (info.relPos.length() > maxRelPosWidth)
+                maxRelPosWidth = info.relPos.length();
+            if (info.state.length() > maxStateWidth)
+                maxStateWidth = info.state.length();
+        }
+
+        aliasIndex++;
+    }
+
+    for (iter = infoList.begin(); iter != infoList.end(); iter++) {
+        cout << setfill(' ') << right
+            << setw(maxPosWidth) << iter->pos << "  "
+            << setw(maxAliasWidth) << iter->alias
+            << ":" << left
+            << setw(maxRelPosWidth) << iter->relPos << "  "
+            << setw(maxStateWidth) << iter->state << "  "
+            << iter->flag << "  "
+            << iter->name << endl;
+    }
+}
+
+/****************************************************************************/
+
+void CommandSlaves::showSlave(
+        MasterDevice &m,
+        uint16_t slavePosition
+        )
+{
+    ec_ioctl_slave_t slave;
+    list<string> protoList;
+    list<string>::const_iterator protoIter;
+    
+    m.getSlave(&slave, slavePosition);
+        
+    cout << "=== Slave " << dec << slavePosition << " ===" << endl;
+    
+    if (slave.alias)
+        cout << "Alias: " << slave.alias << endl;
+
+    cout
+        << "State: " << slaveState(slave.state) << endl
+        << "Flag: " << (slave.error_flag ? 'E' : '+') << endl
+        << "Identity:" << endl
+        << "  Vendor Id:       0x"
+        << hex << setfill('0')
+        << setw(8) << slave.vendor_id << endl
+        << "  Product code:    0x"
+        << setw(8) << slave.product_code << endl
+        << "  Revision number: 0x"
+        << setw(8) << slave.revision_number << endl
+        << "  Serial number:   0x"
+        << setw(8) << slave.serial_number << endl;
+
+    if (slave.mailbox_protocols) {
+        cout << "Mailboxes:" << endl
+        << "  RX: 0x"
+        << hex << setw(4) << slave.rx_mailbox_offset << "/"
+        << dec << slave.rx_mailbox_size
+        << ", TX: 0x"
+        << hex << setw(4) << slave.tx_mailbox_offset << "/"
+        << dec << slave.tx_mailbox_size << endl
+        << "  Supported protocols: ";
+
+        if (slave.mailbox_protocols & EC_MBOX_AOE) {
+            protoList.push_back("AoE");
+        }
+        if (slave.mailbox_protocols & EC_MBOX_EOE) {
+            protoList.push_back("EoE");
+        }
+        if (slave.mailbox_protocols & EC_MBOX_COE) {
+            protoList.push_back("CoE");
+        }
+        if (slave.mailbox_protocols & EC_MBOX_FOE) {
+            protoList.push_back("FoE");
+        }
+        if (slave.mailbox_protocols & EC_MBOX_SOE) {
+            protoList.push_back("SoE");
+        }
+        if (slave.mailbox_protocols & EC_MBOX_VOE) {
+            protoList.push_back("VoE");
+        }
+
+        for (protoIter = protoList.begin(); protoIter != protoList.end();
+                protoIter++) {
+            if (protoIter != protoList.begin())
+                cout << ", ";
+            cout << *protoIter;
+        }
+        cout << endl;
+    }
+
+    if (slave.has_general_category) {
+        cout << "General:" << endl
+            << "  Group: " << slave.group << endl
+            << "  Image name: " << slave.image << endl
+            << "  Order number: " << slave.order << endl
+            << "  Device name: " << slave.name << endl;
+
+        if (slave.mailbox_protocols & EC_MBOX_COE) {
+            cout << "  CoE details:" << endl
+                << "    Enable Sdo: "
+                << (slave.coe_details.enable_sdo ? "yes" : "no") << endl
+                << "    Enable Sdo Info: "
+                << (slave.coe_details.enable_sdo_info ? "yes" : "no") << endl
+                << "    Enable Pdo Assign: "
+                << (slave.coe_details.enable_pdo_assign
+                        ? "yes" : "no") << endl
+                << "    Enable Pdo Configuration: "
+                << (slave.coe_details.enable_pdo_configuration
+                        ? "yes" : "no") << endl
+                << "    Enable Upload at startup: "
+                << (slave.coe_details.enable_upload_at_startup
+                        ? "yes" : "no") << endl
+                << "    Enable Sdo complete access: "
+                << (slave.coe_details.enable_sdo_complete_access
+                        ? "yes" : "no") << endl;
+        }
+
+        cout << "  Flags:" << endl
+            << "    Enable SafeOp: "
+            << (slave.general_flags.enable_safeop ? "yes" : "no") << endl
+            << "    Enable notLRW: "
+            << (slave.general_flags.enable_not_lrw ? "yes" : "no") << endl
+            << "  Current consumption: "
+            << dec << slave.current_on_ebus << " mA" << endl;
+    }
+}
+
+/****************************************************************************/
+
+string CommandSlaves::slaveState(uint8_t state)
+{
+    switch (state) {
+        case 1: return "INIT";
+        case 2: return "PREOP";
+        case 4: return "SAFEOP";
+        case 8: return "OP";
+        default: return "???";
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandSlaves.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDSLAVES_H__
+#define __COMMANDSLAVES_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandSlaves:
+    public Command
+{
+    public:
+        CommandSlaves();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+        struct Info {
+            string pos;
+            string alias;
+            string relPos;
+            string state;
+            string flag;
+            string name;
+        };
+
+        void listSlaves(MasterDevice &, int);
+        void showSlave(MasterDevice &, uint16_t);
+
+        static string slaveState(uint8_t);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandStates.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+using namespace std;
+
+#include "CommandStates.h"
+
+/*****************************************************************************/
+
+CommandStates::CommandStates():
+    Command("states", "Request application-layer states.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandStates::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS] <STATE>" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "Arguments:" << endl
+        << "  STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'" << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --slave -s <index>  Positive numerical ring position," << endl
+        << "                      or 'all' for all slaves (default)." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandStates::execute(MasterDevice &m, const StringVector &args)
+{
+    stringstream err;
+    string stateStr;
+    uint8_t state = 0x00;
+    
+    if (args.size() != 1) {
+        err << "'" << getName() << "' takes exactly one argument!";
+        throwInvalidUsageException(err);
+    }
+
+    stateStr = args[0];
+    transform(stateStr.begin(), stateStr.end(),
+            stateStr.begin(), (int (*) (int)) std::toupper);
+
+    if (stateStr == "INIT") {
+        state = 0x01;
+    } else if (stateStr == "PREOP") {
+        state = 0x02;
+    } else if (stateStr == "SAFEOP") {
+        state = 0x04;
+    } else if (stateStr == "OP") {
+        state = 0x08;
+    } else {
+        err << "Invalid state '" << args[0] << "'!";
+        throwInvalidUsageException(err);
+    }
+
+    m.open(MasterDevice::ReadWrite);
+
+    if (slavePosition == -1) {
+        unsigned int i, numSlaves = m.slaveCount();
+        for (i = 0; i < numSlaves; i++)
+            m.requestState(i, state);
+    } else {
+        m.requestState(slavePosition, state);
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandStates.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDSTATES_H__
+#define __COMMANDSTATES_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandStates:
+    public Command
+{
+    public:
+        CommandStates();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandUpload.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,205 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandUpload.h"
+#include "coe_datatypes.h"
+#include "byteorder.h"
+
+/*****************************************************************************/
+
+CommandUpload::CommandUpload():
+    Command("upload", "Read an Sdo entry from a slave.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandUpload::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS] <INDEX> <SUBINDEX>" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "The data type of the Sdo entry is taken from the Sdo" << endl
+        << "dictionary by default. It can be overridden with the" << endl
+        << "--type option. If the slave does not support the Sdo" << endl
+        << "information service or the Sdo is not in the dictionary," << endl
+        << "the --type option is mandatory."  << endl
+        << endl
+        << "These are the valid Sdo entry data types:" << endl
+        << "  int8, int16, int32, uint8, uint16, uint32, string." << endl
+        << endl
+        << "Arguments:" << endl
+        << "  INDEX    is the Sdo index and must be an unsigned" << endl
+        << "           16 bit number." << endl
+        << "  SUBINDEX is the Sdo entry subindex and must be an" << endl
+        << "           unsigned 8 bit number." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --slave -s <index>  Positive numerical ring position" << endl
+        << "                      (mandatory)." << endl
+        << "  --type  -t <type>   Forced Sdo entry data type (see" << endl
+        << "                      above)." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandUpload::execute(MasterDevice &m, const StringVector &args)
+{
+    stringstream err, strIndex, strSubIndex;
+    int sval;
+    ec_ioctl_slave_sdo_upload_t data;
+    unsigned int uval;
+    const CoEDataType *dataType = NULL;
+
+    if (slavePosition < 0) {
+        err << "'" << getName() << "' requires a slave! "
+            << "Please specify --slave.";
+        throwInvalidUsageException(err);
+    }
+    data.slave_position = slavePosition;
+
+    if (args.size() != 2) {
+        err << "'" << getName() << "' takes two arguments!";
+        throwInvalidUsageException(err);
+    }
+
+    strIndex << args[0];
+    strIndex
+        >> resetiosflags(ios::basefield) // guess base from prefix
+        >> data.sdo_index;
+    if (strIndex.fail()) {
+        err << "Invalid Sdo index '" << args[0] << "'!";
+        throwInvalidUsageException(err);
+    }
+
+    strSubIndex << args[1];
+    strSubIndex
+        >> resetiosflags(ios::basefield) // guess base from prefix
+        >> uval;
+    if (strSubIndex.fail() || uval > 0xff) {
+        err << "Invalid Sdo subindex '" << args[1] << "'!";
+        throwInvalidUsageException(err);
+    }
+    data.sdo_entry_subindex = uval;
+
+    if (dataTypeStr != "") { // data type specified
+        if (!(dataType = findDataType(dataTypeStr))) {
+            err << "Invalid data type '" << dataTypeStr << "'!";
+            throwInvalidUsageException(err);
+        }
+    } else { // no data type specified: fetch from dictionary
+        ec_ioctl_slave_sdo_entry_t entry;
+
+        m.open(MasterDevice::Read);
+
+        try {
+            m.getSdoEntry(&entry, slavePosition,
+                    data.sdo_index, data.sdo_entry_subindex);
+        } catch (MasterDeviceException &e) {
+            err << "Failed to determine Sdo entry data type. "
+                << "Please specify --type.";
+            throwCommandException(err);
+        }
+        if (!(dataType = findDataType(entry.data_type))) {
+            err << "Pdo entry has unknown data type 0x"
+                << hex << setfill('0') << setw(4) << entry.data_type << "!"
+                << " Please specify --type.";
+            throwCommandException(err);
+        }
+    }
+
+    if (dataType->byteSize) {
+        data.target_size = dataType->byteSize;
+    } else {
+        data.target_size = DefaultBufferSize;
+    }
+
+    data.target = new uint8_t[data.target_size + 1];
+
+    m.open(MasterDevice::Read);
+
+	try {
+		m.sdoUpload(&data);
+	} catch (MasterDeviceException &e) {
+        delete [] data.target;
+        throw e;
+    }
+
+    m.close();
+
+    if (dataType->byteSize && data.data_size != dataType->byteSize) {
+        err << "Data type mismatch. Expected " << dataType->name
+            << " with " << dataType->byteSize << " byte, but got "
+            << data.data_size << " byte.";
+        throwCommandException(err);
+    }
+
+    cout << setfill('0');
+    switch (dataType->coeCode) {
+        case 0x0002: // int8
+            sval = *(int8_t *) data.target;
+            cout << sval << " 0x" << hex << setw(2) << sval << endl;
+            break;
+        case 0x0003: // int16
+            sval = le16tocpu(*(int16_t *) data.target);
+            cout << sval << " 0x" << hex << setw(4) << sval << endl;
+            break;
+        case 0x0004: // int32
+            sval = le32tocpu(*(int32_t *) data.target);
+            cout << sval << " 0x" << hex << setw(8) << sval << endl;
+            break;
+        case 0x0005: // uint8
+            uval = (unsigned int) *(uint8_t *) data.target;
+            cout << uval << " 0x" << hex << setw(2) << uval << endl;
+            break;
+        case 0x0006: // uint16
+            uval = le16tocpu(*(uint16_t *) data.target);
+            cout << uval << " 0x" << hex << setw(4) << uval << endl;
+            break;
+        case 0x0007: // uint32
+            uval = le32tocpu(*(uint32_t *) data.target);
+            cout << uval << " 0x" << hex << setw(8) << uval << endl;
+            break;
+        case 0x0009: // string
+            cout << string((const char *) data.target, data.data_size)
+                << endl;
+            break;
+        default:
+            printRawData(data.target, data.data_size); // FIXME
+            break;
+    }
+
+    delete [] data.target;
+}
+
+/****************************************************************************/
+
+void CommandUpload::printRawData(
+		const uint8_t *data,
+		unsigned int size
+		)
+{
+    cout << hex << setfill('0');
+    while (size--) {
+        cout << "0x" << setw(2) << (unsigned int) *data++;
+        if (size)
+            cout << " ";
+    }
+    cout << endl;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandUpload.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDUPLOAD_H__
+#define __COMMANDUPLOAD_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandUpload:
+    public Command
+{
+    public:
+        CommandUpload();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+		enum {DefaultBufferSize = 1024};
+
+        static void printRawData(const uint8_t *, unsigned int);
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandXml.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,180 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandXml.h"
+
+/*****************************************************************************/
+
+CommandXml::CommandXml():
+    Command("xml", "Generate slave information XML.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandXml::helpString() const
+{
+    stringstream str;
+
+    str << getName() << " [OPTIONS]"
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "Note that the Pdo information can either originate" << endl
+        << "from the SII or from the CoE communication area. For" << endl
+        << "some slaves, this is dependant on the last slave" << endl
+        << "configuration." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --slave -s <index>  Positive numerical ring position," << endl
+        << "                      or 'all' for all slaves (default)." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandXml::execute(MasterDevice &m, const StringVector &args)
+{
+    m.open(MasterDevice::Read);
+
+    if (slavePosition == -1) {
+        unsigned int numSlaves = m.slaveCount(), i;
+
+        for (i = 0; i < numSlaves; i++) {
+            generateSlaveXml(m, i);
+        }
+    } else {
+        generateSlaveXml(m, slavePosition);
+    }
+}
+
+/****************************************************************************/
+
+void CommandXml::generateSlaveXml(MasterDevice &m, uint16_t slavePosition)
+{
+    ec_ioctl_slave_t slave;
+    ec_ioctl_slave_sync_t sync;
+    ec_ioctl_slave_sync_pdo_t pdo;
+    string pdoType;
+    ec_ioctl_slave_sync_pdo_entry_t entry;
+    unsigned int i, j, k;
+    
+    m.getSlave(&slave, slavePosition);
+
+    cout
+        << "<?xml version=\"1.0\" ?>" << endl
+        << "  <EtherCATInfo>" << endl
+        << "    <!-- Slave " << slave.position << " -->" << endl
+        << "    <Vendor>" << endl
+        << "      <Id>" << slave.vendor_id << "</Id>" << endl
+        << "    </Vendor>" << endl
+        << "    <Descriptions>" << endl
+        << "      <Devices>" << endl
+        << "        <Device>" << endl
+        << "          <Type ProductCode=\"#x"
+        << hex << setfill('0') << setw(8) << slave.product_code
+        << "\" RevisionNo=\"#x"
+        << hex << setfill('0') << setw(8) << slave.revision_number
+        << "\">" << slave.order << "</Type>" << endl;
+
+    if (strlen(slave.name)) {
+        cout
+            << "          <Name><![CDATA["
+            << slave.name
+            << "]]></Name>" << endl;
+    }
+
+    for (i = 0; i < slave.sync_count; i++) {
+        m.getSync(&sync, slavePosition, i);
+
+        cout
+            << "          <Sm Enable=\"" << dec << (unsigned int) sync.enable
+            << "\" StartAddress=\"" << sync.physical_start_address
+            << "\" ControlByte=\"" << (unsigned int) sync.control_register
+            << "\" DefaultSize=\"" << sync.default_size
+            << "\" />" << endl;
+    }
+
+    for (i = 0; i < slave.sync_count; i++) {
+        m.getSync(&sync, slavePosition, i);
+
+        for (j = 0; j < sync.pdo_count; j++) {
+            m.getPdo(&pdo, slavePosition, i, j);
+            pdoType = (sync.control_register & 0x04 ? "R" : "T");
+            pdoType += "xPdo";
+
+            cout
+                << "          <" << pdoType
+                << " Sm=\"" << i << "\" Fixed=\"1\" Mandatory=\"1\">" << endl
+                << "            <Index>#x"
+                << hex << setfill('0') << setw(4) << pdo.index
+                << "</Index>" << endl
+                << "            <Name>" << pdo.name << "</Name>" << endl;
+
+            for (k = 0; k < pdo.entry_count; k++) {
+                m.getPdoEntry(&entry, slavePosition, i, j, k);
+
+                cout
+                    << "            <Entry>" << endl
+                    << "              <Index>#x"
+                    << hex << setfill('0') << setw(4) << entry.index
+                    << "</Index>" << endl;
+                if (entry.index)
+                    cout
+                        << "              <SubIndex>"
+                        << dec << (unsigned int) entry.subindex
+                        << "</SubIndex>" << endl;
+                
+                cout
+                    << "              <BitLen>"
+                    << dec << (unsigned int) entry.bit_length
+                    << "</BitLen>" << endl;
+
+                if (entry.index) {
+                    cout
+                        << "              <Name>" << entry.name
+                        << "</Name>" << endl
+                        << "              <DataType>";
+
+                    if (entry.bit_length == 1) {
+                        cout << "BOOL";
+                    } else if (!(entry.bit_length % 8)) {
+                        if (entry.bit_length <= 64)
+                            cout << "UINT" << (unsigned int) entry.bit_length;
+                        else
+                            cout << "STRING("
+                                << (unsigned int) (entry.bit_length / 8)
+                                << ")";
+                    } else {
+                        cerr << "Invalid bit length "
+                            << (unsigned int) entry.bit_length << endl;
+                    }
+
+                        cout << "</DataType>" << endl;
+                }
+
+                cout << "            </Entry>" << endl;
+            }
+
+            cout
+                << "          </" << pdoType << ">" << endl;
+        }
+    }
+
+    cout
+        << "        </Device>" << endl
+        << "     </Devices>" << endl
+        << "  </Descriptions>" << endl
+        << "</EtherCATInfo>" << endl;
+}
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandXml.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDXML_H__
+#define __COMMANDXML_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandXml:
+    public Command
+{
+    public:
+        CommandXml();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+
+    protected:
+        void generateSlaveXml(MasterDevice &, uint16_t);
+};
+
+/****************************************************************************/
+
+#endif
--- a/tool/Makefile.am	Thu Jul 24 08:15:44 2008 +0000
+++ b/tool/Makefile.am	Thu Jul 24 13:27:06 2008 +0000
@@ -29,30 +29,33 @@
 #  standard) as the (only) precondition to have the right to use EtherCAT
 #  Technology, IP and trade marks.
 #
+#  vim: syntax=make
+#
 #------------------------------------------------------------------------------
 
 bin_PROGRAMS = ethercat
 
 ethercat_SOURCES = \
-    MasterDevice.cpp MasterDevice.h \
+	MasterDevice.cpp MasterDevice.h \
+	Command.cpp \
+	CommandAlias.cpp \
+	CommandConfig.cpp \
+	CommandData.cpp \
+	CommandDebug.cpp \
+	CommandDomains.cpp \
+	CommandDownload.cpp \
+	CommandMaster.cpp \
+	CommandPdos.cpp \
+	CommandSdos.cpp \
+	CommandSiiRead.cpp \
+	CommandSiiWrite.cpp \
+	CommandSlaves.cpp \
+	CommandStates.cpp \
+	CommandUpload.cpp \
+	CommandXml.cpp \
 	coe_datatypes.cpp \
 	sii_crc.cpp \
-    cmd_alias.cpp \
-    cmd_config.cpp \
-    cmd_data.cpp \
-    cmd_debug.cpp \
-	cmd_domain.cpp \
-	cmd_master.cpp \
-	cmd_pdos.cpp \
-	cmd_sdos.cpp \
-	cmd_download.cpp \
-	cmd_upload.cpp \
-	cmd_slaves.cpp \
-	cmd_sii_read.cpp \
-	cmd_sii_write.cpp \
-	cmd_states.cpp \
-	cmd_xml.cpp \
-    main.cpp
+	main.cpp
 
 ethercat_CXXFLAGS = -I../master -Wall
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/byteorder.h	Thu Jul 24 13:27:06 2008 +0000
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <sys/types.h>
+
+/*****************************************************************************/
+
+#define swap16(x) \
+        ((uint16_t)( \
+        (((uint16_t)(x) & 0x00ffU) << 8) | \
+        (((uint16_t)(x) & 0xff00U) >> 8) ))
+#define swap32(x) \
+        ((uint32_t)( \
+        (((uint32_t)(x) & 0x000000ffUL) << 24) | \
+        (((uint32_t)(x) & 0x0000ff00UL) <<  8) | \
+        (((uint32_t)(x) & 0x00ff0000UL) >>  8) | \
+        (((uint32_t)(x) & 0xff000000UL) >> 24) ))
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#define le16tocpu(x) x
+#define le32tocpu(x) x
+
+#define cputole16(x) x
+#define cputole32(x) x
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+#define le16tocpu(x) swap16(x)
+#define le32tocpu(x) swap32(x)
+
+#define cputole16(x) swap16(x)
+#define cputole32(x) swap32(x)
+
+#endif
+
+/****************************************************************************/
--- a/tool/cmd_alias.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-#include <sstream>
-using namespace std;
-
-#include "globals.h"
-#include "sii_crc.h"
-
-/*****************************************************************************/
-
-const char *help_alias =
-    "[OPTIONS] <ALIAS>\n"
-    "\n"
-    "Write the secondary slave address (alias) for either\n"
-    "one or for multiple slaves.\n"
-    "\n"
-    "Arguments:\n"
-    "  ALIAS must be an unsigned 16 bit number. Zero means no alias.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                      all slaves (default). The --force option is\n"
-    "                      required in this case.\n"
-    "  --force             Acknowledge writing aliases of all slaves.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/*****************************************************************************/
-
-void writeSlaveAlias(uint16_t, uint16_t);
-
-/*****************************************************************************/
-
-/** Writes the Secondary slave address (alias) to the slave's SII.
- */
-void command_alias(void)
-{
-    uint16_t alias;
-    stringstream err, strAlias;
-    int number;
-    unsigned int numSlaves, i;
-
-    if (commandArgs.size() != 1) {
-        err << "'" << commandName << "' takes exactly one argument!";
-        throw InvalidUsageException(err);
-    }
-
-    strAlias << commandArgs[0];
-    strAlias
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> number;
-    if (strAlias.fail() || number < 0x0000 || number > 0xffff) {
-        err << "Invalid alias '" << commandArgs[0] << "'!";
-        throw InvalidUsageException(err);
-    }
-    alias = number;
-
-    if (slavePosition == -1) {
-        if (!force) {
-            err << "This will write the alias addresses of all slaves to "
-                << alias << "! Please specify --force to proceed.";
-            throw CommandException(err);
-        }
-
-        masterDev.open(MasterDevice::ReadWrite);
-        numSlaves = masterDev.slaveCount();
-
-        for (i = 0; i < numSlaves; i++) {
-            writeSlaveAlias(i, alias);
-        }
-    } else {
-        masterDev.open(MasterDevice::ReadWrite);
-        writeSlaveAlias(slavePosition, alias);
-    }
-}
-
-/*****************************************************************************/
-
-/** Writes the Secondary slave address (alias) to the slave's SII.
- */
-void writeSlaveAlias(
-        uint16_t slavePosition,
-        uint16_t alias
-        )
-{
-    ec_ioctl_slave_sii_t data;
-    ec_ioctl_slave_t slave;
-    stringstream err;
-    uint8_t crc;
-
-    masterDev.getSlave(&slave, slavePosition);
-
-    if (slave.sii_nwords < 8) {
-        err << "Current SII contents are too small to set an alias "
-            << "(" << slave.sii_nwords << " words)!";
-        throw CommandException(err);
-    }
-
-    // read first 8 SII words
-    data.slave_position = slavePosition;
-    data.offset = 0;
-    data.nwords = 8;
-    data.words = new uint16_t[data.nwords];
-
-    try {
-        masterDev.readSii(&data);
-    } catch (MasterDeviceException &e) {
-        delete [] data.words;
-        err << "Failed to read SII: " << e.what();
-        throw CommandException(err);
-    }
-
-    // write new alias address in word 4
-    data.words[4] = cputole16(alias);
-
-    // calculate checksum over words 0 to 6
-    crc = calcSiiCrc((const uint8_t *) data.words, 14);
-
-    // write new checksum into first byte of word 7
-    *(uint8_t *) (data.words + 7) = crc;
-
-    // write first 8 words with new alias and checksum
-    try {
-        masterDev.writeSii(&data);
-    } catch (MasterDeviceException &e) {
-        delete [] data.words;
-        err << "Failed to read SII: " << e.what();
-        throw CommandException(err);
-    }
-
-    delete [] data.words;
-}
-
-/*****************************************************************************/
--- a/tool/cmd_config.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <list>
-#include <iostream>
-#include <iomanip>
-#include <sstream>
-using namespace std;
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-const char *help_config =
-    "[OPTIONS]\n"
-    "\n"
-    "Output information about the slave configurations supplied by the\n"
-    "application.\n"
-    "\n"
-    "Without the --verbose option, each line of output shows one slave\n"
-    "configuration. Example:\n"
-    "\n"
-    "1001:0  0x0000003b/0x02010000  -  -\n"
-    "|       |                      |  |\n"
-    "|       |                      |  \\- Slave is operational.\n"
-    "|       |                      \\- Slave has been found.\n"
-    "|       \\- Hexadecimal vendor ID and product code, separated by a\n"
-    "|          slash.\n"
-    "\\- Decimal alias and position, separated by a colon.\n"
-    "\n"
-    "With the --verbose option given, the configured Pdos and Sdos are\n"
-    "additionally printed.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --verbose  -v  Show detailed configurations.\n";
-
-/*****************************************************************************/
-
-struct ConfigInfo {
-    string alias;
-    string pos;
-    string ident;
-    string att;
-    string op;
-};
-
-typedef list<ec_ioctl_config_t> ConfigList;
-
-void showDetailedConfigs(const ConfigList &configList);
-void listConfigs(const ConfigList &configList);
-
-/*****************************************************************************/
-
-bool operator<(const ec_ioctl_config_t &a, const ec_ioctl_config_t &b)
-{
-    return a.alias < b.alias
-        || (a.alias == b.alias && a.position < b.position);
-}
-
-/*****************************************************************************/
-
-/** Lists the bus configuration.
- */
-void command_config(void)
-{
-    ec_ioctl_master_t master;
-    unsigned int i;
-    ec_ioctl_config_t config;
-    ConfigList configList;
-
-    masterDev.open(MasterDevice::Read);
-    masterDev.getMaster(&master);
-
-    for (i = 0; i < master.config_count; i++) {
-        masterDev.getConfig(&config, i);
-        configList.push_back(config);
-    }
-
-    configList.sort();
-
-    if (verbosity == Verbose) {
-        showDetailedConfigs(configList);
-    } else {
-        listConfigs(configList);
-    }
-}
-
-/*****************************************************************************/
-
-/** Lists the complete bus configuration.
- */
-void showDetailedConfigs(const ConfigList &configList)
-{
-    ConfigList::const_iterator configIter;
-    unsigned int j, k, l;
-    ec_ioctl_config_pdo_t pdo;
-    ec_ioctl_config_pdo_entry_t entry;
-    ec_ioctl_config_sdo_t sdo;
-
-    for (configIter = configList.begin();
-            configIter != configList.end();
-            configIter++) {
-
-        cout << "Alias: "
-            << dec << configIter->alias << endl
-            << "Position: " << configIter->position << endl
-            << "Vendor Id: 0x"
-            << hex << setfill('0')
-            << setw(8) << configIter->vendor_id << endl
-            << "Product code: 0x"
-            << setw(8) << configIter->product_code << endl
-            << "Attached: " << (configIter->attached ? "yes" : "no") << endl
-            << "Operational: " << (configIter->operational ? "yes" : "no") << endl;
-
-        for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
-            if (configIter->syncs[j].pdo_count) {
-                cout << "SM" << dec << j << " ("
-                    << (configIter->syncs[j].dir == EC_DIR_INPUT
-                            ? "Input" : "Output") << ")" << endl;
-                for (k = 0; k < configIter->syncs[j].pdo_count; k++) {
-                    masterDev.getConfigPdo(&pdo, configIter->config_index, j, k);
-
-                    cout << "  Pdo 0x" << hex
-                        << setw(4) << pdo.index
-                        << " \"" << pdo.name << "\"" << endl;
-
-                    for (l = 0; l < pdo.entry_count; l++) {
-                        masterDev.getConfigPdoEntry(&entry,
-                                configIter->config_index, j, k, l);
-
-                        cout << "    Pdo entry 0x" << hex
-                            << setw(4) << entry.index << ":"
-                            << setw(2) << (unsigned int) entry.subindex
-                            << ", " << dec << (unsigned int) entry.bit_length
-                            << " bit, \"" << entry.name << "\"" << endl;
-                    }
-                }
-            }
-        }
-
-        cout << "Sdo configuration:" << endl;
-        if (configIter->sdo_count) {
-            for (j = 0; j < configIter->sdo_count; j++) {
-                masterDev.getConfigSdo(&sdo, configIter->config_index, j);
-
-                cout << "  0x"
-                    << hex << setfill('0')
-                    << setw(4) << sdo.index << ":"
-                    << setw(2) << (unsigned int) sdo.subindex
-                    << ", " << dec << 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;
-            }
-        } else {
-            cout << "  None." << endl;
-        }
-
-        cout << endl;
-    }
-}
-
-/*****************************************************************************/
-
-/** Lists the bus configuration.
- */
-void listConfigs(const ConfigList &configList)
-{
-    ConfigList::const_iterator configIter;
-    stringstream str;
-    ConfigInfo info;
-    typedef list<ConfigInfo> ConfigInfoList;
-    ConfigInfoList list;
-    ConfigInfoList::const_iterator iter;
-    unsigned int maxAliasWidth = 0, maxPosWidth = 0,
-                 maxAttWidth = 0, maxOpWidth = 0;
-
-    for (configIter = configList.begin();
-            configIter != configList.end();
-            configIter++) {
-
-        str << dec << configIter->alias;
-        info.alias = str.str();
-        str.clear();
-        str.str("");
-
-        str << configIter->position;
-        info.pos = str.str();
-        str.clear();
-        str.str("");
-
-        str << hex << setfill('0')
-            << "0x" << setw(8) << configIter->vendor_id
-            << "/0x" << setw(8) << configIter->product_code;
-        info.ident = str.str();
-        str.clear();
-        str.str("");
-
-        str << (configIter->attached ? "attached" : "-");
-        info.att = str.str();
-        str.clear();
-        str.str("");
-
-        str << (configIter->operational ? "operational" : "-");
-        info.op = str.str();
-        str.clear();
-        str.str("");
-
-        list.push_back(info);
-
-        if (info.alias.length() > maxAliasWidth)
-            maxAliasWidth = info.alias.length();
-        if (info.pos.length() > maxPosWidth)
-            maxPosWidth = info.pos.length();
-        if (info.att.length() > maxAttWidth)
-            maxAttWidth = info.att.length();
-        if (info.op.length() > maxOpWidth)
-            maxOpWidth = info.op.length();
-    }
-
-    for (iter = list.begin(); iter != list.end(); iter++) {
-        cout << setfill(' ') << right
-            << setw(maxAliasWidth) << iter->alias
-            << ":" << left
-            << setw(maxPosWidth) << iter->pos
-            << "  "
-            << iter->ident
-            << "  "
-            << setw(maxAttWidth) << iter->att << "  "
-            << setw(maxOpWidth) << iter->op << "  "
-            << endl;
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_data.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-using namespace std;
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-const char *help_data =
-    "[OPTIONS]\n"
-    "\n"
-    "Output binary domain data.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --domain -d <index> Positive numerical domain index, or 'all' for\n"
-    "                      all domains (default). In this case, data of all\n"
-    "                      domains are concatenated.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void outputDomainData(unsigned int);
-
-/****************************************************************************/
-
-void command_data()
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (domainIndex == -1) {
-        unsigned int i;
-        ec_ioctl_master_t master;
-
-        masterDev.getMaster(&master);
-
-        for (i = 0; i < master.domain_count; i++) {
-            outputDomainData(i);
-        }
-    } else {
-        outputDomainData(domainIndex);
-    }
-}
-
-/****************************************************************************/
-
-void outputDomainData(unsigned int domainIndex)
-{
-    ec_ioctl_domain_t domain;
-    ec_ioctl_domain_data_t data;
-    unsigned char *processData;
-    unsigned int i;
-    
-    masterDev.getDomain(&domain, domainIndex);
-
-    if (!domain.data_size)
-        return;
-
-    processData = new unsigned char[domain.data_size];
-
-    try {
-        masterDev.getData(&data, domainIndex, domain.data_size, processData);
-    } catch (MasterDeviceException &e) {
-        delete [] processData;
-        throw e;
-    }
-
-    for (i = 0; i < data.data_size; i++)
-        cout << processData[i];
-    cout.flush();
-
-    delete [] processData;
-}
-
-/****************************************************************************/
--- a/tool/cmd_debug.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <sstream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-const char *help_debug =
-    "<LEVEL>\n"
-    "\n"
-    "Set the master debug level.\n"
-    "\n"
-    "Debug messages are printed to syslog.\n"
-    "\n"
-    "Arguments:\n"
-    "  LEVEL can have one of the following values:\n"
-    "        0 for no debugging output,\n"
-    "        1 for some debug messages, or\n"
-    "        2 for printing all frame contents (use with caution!).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void command_debug(void)
-{
-    stringstream str;
-    int debugLevel;
-    
-    if (commandArgs.size() != 1) {
-        stringstream err;
-        err << "'" << commandName << "' takes exactly one argument!";
-        throw InvalidUsageException(err);
-    }
-
-    str << commandArgs[0];
-    str >> resetiosflags(ios::basefield) // guess base from prefix
-        >> debugLevel;
-
-    if (str.fail()) {
-        stringstream err;
-        err << "Invalid debug level '" << commandArgs[0] << "'!";
-        throw InvalidUsageException(err);
-    }
-
-    masterDev.open(MasterDevice::ReadWrite);
-    masterDev.setDebug(debugLevel);
-}
-
-/*****************************************************************************/
--- a/tool/cmd_domain.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-const char *help_domains =
-    "[OPTIONS]\n"
-    "\n"
-    "Show information about the application's configured domains.\n"
-    "\n"
-    "Without the --verbose option, the domains are displayed one-per-line.\n"
-    "Example:\n"
-    "\n"
-    "Domain0: LogBaseAddr 0x00000000, Size   6, WorkingCounter 0/1\n"
-    "\n"
-    "The domain's base address for the logical datagram (LRD/LWR/LRW)\n"
-    "is displayed followed by the domain's process data size in byte.\n"
-    "The last values are the current datagram working counter sum and\n"
-    "the expected working counter sum. If the values are equal, all\n"
-    "Pdos are exchanged.\n"
-    "\n"
-    "If the --verbose option is given, the participating slave\n"
-    "configurations/FMMUs and the current process data are additionally\n"
-    "displayed:\n"
-    "\n"
-    "Domain1: LogBaseAddr 0x00000006, Size   6, WorkingCounter 0/1\n"
-    "  SlaveConfig 1001:0, SM3 ( Input), LogAddr 0x00000006, Size 6\n"
-    "    00 00 00 00 00 00\n"
-    "\n"
-    "The process data are displayed as hexadecimal bytes.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --domain   -d <index> Positive numerical domain index, or 'all'\n"
-    "                        for all domains (default).\n"
-    "  --verbose  -v         Show FMMUs and process data additionally.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void showDomain(unsigned int);
-
-/****************************************************************************/
-
-void command_domains(void)
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (domainIndex == -1) {
-        unsigned int i;
-        ec_ioctl_master_t master;
-
-        masterDev.getMaster(&master);
-
-        for (i = 0; i < master.domain_count; i++) {
-            showDomain(i);
-        }
-    } else {
-        showDomain(domainIndex);
-    }
-}
-
-/****************************************************************************/
-
-void showDomain(unsigned int domainIndex)
-{
-    ec_ioctl_domain_t domain;
-    unsigned char *processData;
-    ec_ioctl_domain_data_t data;
-    unsigned int i, j;
-    ec_ioctl_domain_fmmu_t fmmu;
-    unsigned int dataOffset;
-    
-    masterDev.getDomain(&domain, domainIndex);
-
-	cout << "Domain" << dec << domainIndex << ":"
-		<< " LogBaseAddr 0x"
-		<< hex << setfill('0')
-        << setw(8) << domain.logical_base_address
-		<< ", Size " << dec << setfill(' ')
-        << setw(3) << domain.data_size
-		<< ", WorkingCounter "
-		<< domain.working_counter << "/"
-        << domain.expected_working_counter << endl;
-
-    if (!domain.data_size || verbosity != Verbose)
-        return;
-
-    processData = new unsigned char[domain.data_size];
-
-    try {
-        masterDev.getData(&data, domainIndex, domain.data_size, processData);
-    } catch (MasterDeviceException &e) {
-        delete [] processData;
-        throw e;
-    }
-
-    for (i = 0; i < domain.fmmu_count; i++) {
-        masterDev.getFmmu(&fmmu, domainIndex, i);
-
-        cout << "  SlaveConfig "
-            << dec << fmmu.slave_config_alias
-            << ":" << fmmu.slave_config_position
-            << ", SM" << (unsigned int) fmmu.sync_index << " ("
-            << setfill(' ') << setw(6)
-            << (fmmu.dir == EC_DIR_INPUT ? "Input" : "Output")
-            << "), LogAddr 0x"
-            << hex << setfill('0')
-            << setw(8) << fmmu.logical_address
-            << ", Size " << dec << fmmu.data_size << endl;
-
-        dataOffset = fmmu.logical_address - domain.logical_base_address;
-        if (dataOffset + fmmu.data_size > domain.data_size) {
-            stringstream err;
-            delete [] processData;
-            err << "Fmmu information corrupted!";
-            throw CommandException(err);
-        }
-
-        cout << "    " << hex << setfill('0');
-        for (j = 0; j < fmmu.data_size; j++) {
-            if (j && !(j % BreakAfterBytes))
-                cout << endl << "    ";
-            cout << setw(2)
-                << (unsigned int) *(processData + dataOffset + j) << " ";
-        }
-        cout << endl;
-    }
-
-    delete [] processData;
-}
-
-/*****************************************************************************/
--- a/tool/cmd_download.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-#include "coe_datatypes.h"
-
-/****************************************************************************/
-
-const char *help_download =
-    "[OPTIONS] <INDEX> <SUBINDEX> <VALUE>\n"
-    "\n"
-    "Download an Sdo entry to a slave.\n"
-    "\n"
-    "The data type of the Sdo entry is taken from the Sdo dictionary by\n"
-    "default. It can be overridden with the --type option. If the slave\n"
-    "does not support the Sdo information service or the Sdo is not in the\n"
-    "dictionary, the --type option is mandatory.\n"
-    "\n"
-    "These are the valid Sdo entry data types:\n"
-    "  int8, int16, int32, uint8, uint16, uint32, string.\n"
-    "\n"
-    "Arguments:\n"
-    "  INDEX    is the Sdo index and must be an unsigned 16 bit number.\n"
-    "  SUBINDEX is the Sdo entry subindex and must be an unsigned 8 bit\n"
-    "           number.\n"
-    "  VALUE    is the value to download and must correspond to the Sdo\n"
-    "           entry datatype (see above).\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position (mandatory).\n"
-    "  --type  -t <type>   Forced Sdo entry data type (see above).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-
-/****************************************************************************/
-
-void command_download(void)
-{
-    stringstream strIndex, strSubIndex, strValue, err;
-    ec_ioctl_slave_sdo_download_t data;
-    unsigned int number;
-    const CoEDataType *dataType = NULL;
-
-    if (slavePosition < 0) {
-        err << "'" << commandName << "' requires a slave! "
-            << "Please specify --slave.";
-        throw InvalidUsageException(err);
-    }
-    data.slave_position = slavePosition;
-
-    if (commandArgs.size() != 3) {
-        err << "'" << commandName << "' takes 3 arguments!";
-        throw InvalidUsageException(err);
-    }
-
-    strIndex << commandArgs[0];
-    strIndex
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> data.sdo_index;
-    if (strIndex.fail()) {
-        err << "Invalid Sdo index '" << commandArgs[0] << "'!";
-        throw InvalidUsageException(err);
-    }
-
-    strSubIndex << commandArgs[1];
-    strSubIndex
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> number;
-    if (strSubIndex.fail() || number > 0xff) {
-        err << "Invalid Sdo subindex '" << commandArgs[1] << "'!";
-        throw InvalidUsageException(err);
-    }
-    data.sdo_entry_subindex = number;
-
-    if (dataTypeStr != "") { // data type specified
-        if (!(dataType = findDataType(dataTypeStr))) {
-            err << "Invalid data type '" << dataTypeStr << "'!";
-            throw InvalidUsageException(err);
-        }
-    } else { // no data type specified: fetch from dictionary
-        ec_ioctl_slave_sdo_entry_t entry;
-
-        masterDev.open(MasterDevice::ReadWrite);
-
-        try {
-            masterDev.getSdoEntry(&entry, slavePosition,
-                    data.sdo_index, data.sdo_entry_subindex);
-        } catch (MasterDeviceException &e) {
-            err << "Failed to determine Sdo entry data type. "
-                << "Please specify --type.";
-            throw CommandException(err);
-        }
-        if (!(dataType = findDataType(entry.data_type))) {
-            err << "Pdo entry has unknown data type 0x"
-                << hex << setfill('0') << setw(4) << entry.data_type << "!"
-                << " Please specify --type.";
-            throw CommandException(err);
-        }
-    }
-
-    if (dataType->byteSize) {
-        data.data_size = dataType->byteSize;
-    } else {
-        data.data_size = DefaultBufferSize;
-    }
-
-    data.data = new uint8_t[data.data_size + 1];
-
-    strValue << commandArgs[2];
-    strValue >> resetiosflags(ios::basefield); // guess base from prefix
-    strValue.exceptions(ios::failbit);
-
-    try {
-        switch (dataType->coeCode) {
-            case 0x0002: // int8
-                {
-                    int16_t val; // uint8_t is interpreted as char
-                    strValue >> val;
-                    if (val > 127 || val < -128)
-                        throw ios::failure("Value out of range");
-                    *data.data = val;
-                    break;
-                }
-            case 0x0003: // int16
-                {
-                    int16_t val;
-                    strValue >> val;
-                    *(int16_t *) data.data = cputole16(val);
-                    break;
-                }
-            case 0x0004: // int32
-                {
-                    int32_t val;
-                    strValue >> val;
-                    *(int32_t *) data.data = cputole32(val);
-                    break;
-                }
-            case 0x0005: // uint8
-                {
-                    uint16_t val; // uint8_t is interpreted as char
-                    strValue >> val;
-                    if (val > 0xff)
-                        throw ios::failure("Value out of range");
-                    *data.data = val;
-                    break;
-                }
-            case 0x0006: // uint16
-                {
-                    uint16_t val;
-                    strValue >> val;
-                    *(uint16_t *) data.data = cputole16(val);
-                    break;
-                }
-            case 0x0007: // uint32
-                {
-                    uint32_t val;
-                    strValue >> val;
-                    *(uint32_t *) data.data = cputole32(val);
-                    break;
-                }
-            case 0x0009: // string
-                if (strValue.str().size() >= data.data_size) {
-                    err << "String too large";
-                    throw CommandException(err);
-                }
-                data.data_size = strValue.str().size();
-                strValue >> (char *) data.data;
-                break;
-
-            default:
-                delete [] data.data;
-                err << "Unknown data type 0x" << hex << dataType->coeCode;
-                throw CommandException(err);
-        }
-    } catch (ios::failure &e) {
-        delete [] data.data;
-        err << "Invalid value argument '" << commandArgs[2]
-            << "' for type '" << dataType->name << "'!";
-        throw InvalidUsageException(err);
-    }
-
-    masterDev.open(MasterDevice::ReadWrite);
-
-	try {
-		masterDev.sdoDownload(&data);
-	} catch(MasterDeviceException &e) {
-        delete [] data.data;
-        throw e;
-    }
-
-    delete [] data.data;
-}
-
-/*****************************************************************************/
--- a/tool/cmd_master.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_master =
-    "[OPTIONS]\n"
-    "\n"
-    "Show master and Ethernet device information.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --master -m <index>  Index of the master to use. Default: 0.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void command_master(void)
-{
-    ec_ioctl_master_t data;
-    stringstream err;
-    unsigned int i;
-    
-    masterDev.open(MasterDevice::Read);
-    masterDev.getMaster(&data);
-
-    cout
-        << "Master" << masterIndex << endl
-        << "  Phase: ";
-
-    switch (data.phase) {
-        case 0:  cout << "Waiting for device..."; break;
-        case 1:  cout << "Idle"; break;
-        case 2:  cout << "Operation"; break;
-        default: cout << "???";
-    }
-
-    cout << endl
-        << "  Slaves: " << data.slave_count << endl;
-
-    for (i = 0; i < 2; i++) {
-        cout << "  Device" << i << ": ";
-        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
-                << "    Tx count: " << data.devices[i].tx_count << endl
-                << "    Rx count: " << data.devices[i].rx_count;
-        }
-        cout << endl;
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_pdos.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_pdos =
-    "[OPTIONS]\n"
-    "\n"
-    "Displays sync managers, assigned Pdos and mapped Pdo entries.\n"
-    "\n"
-    "The information is displayed in three layers, which are indented\n"
-    "accordingly:\n"
-    "\n"
-    "1) Sync managers - Contains the sync manager information from the\n"
-    "   SII: Index, physical start address, default size (raw value from\n"
-    "   the SII), control register and enable word. Example:\n"
-    "\n"
-    "   SM3: PhysAddr 0x1100, DefaultSize 0, ControlRegister 0x20, Enable 1\n"
-    "\n"
-    "2) Assigned Pdos - Pdo direction, hexadecimal index and -if available-\n"
-    "   the Pdo name. Example:\n"
-    "\n"
-    "   TxPdo 0x1a00 \"Channel1\"\n"
-    "\n"
-    "3) Mapped Pdo entries - Pdo entry index and subindex (both\n"
-    "   hexadecimal), the length in bit and -if available- the\n"
-    "   description. Example:\n"
-    "\n"
-    "   Pdo entry 0x3101:01, 8 bit, \"Status\"\n"
-    "\n"
-    "Note, that the displayed Pdo assignment and Pdo mapping information\n"
-    "can either originate from the SII or from the CoE communication area.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                      all slaves (default).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-	
-void listSlavePdos(uint16_t, bool);
-
-/****************************************************************************/
-
-void command_pdos(void)
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (slavePosition == -1) {
-        unsigned int numSlaves = masterDev.slaveCount(), i;
-
-        for (i = 0; i < numSlaves; i++) {
-            listSlavePdos(i, true);
-        }
-    } else {
-        listSlavePdos(slavePosition, false);
-    }
-}
-
-/****************************************************************************/
-
-void listSlavePdos(uint16_t slavePosition, bool withHeader)
-{
-    ec_ioctl_slave_t slave;
-    ec_ioctl_slave_sync_t sync;
-    ec_ioctl_slave_sync_pdo_t pdo;
-    ec_ioctl_slave_sync_pdo_entry_t entry;
-    unsigned int i, j, k;
-    
-    masterDev.getSlave(&slave, slavePosition);
-
-    if (withHeader)
-        cout << "=== Slave " << slavePosition << " ===" << endl;
-
-    for (i = 0; i < slave.sync_count; i++) {
-        masterDev.getSync(&sync, slavePosition, i);
-
-        cout << "SM" << i << ":"
-            << " PhysAddr 0x"
-            << hex << setfill('0')
-            << setw(4) << sync.physical_start_address
-            << ", DefaultSize "
-            << dec << setfill(' ') << setw(4) << sync.default_size
-            << ", ControlRegister 0x"
-            << hex << setfill('0') << setw(2)
-            << (unsigned int) sync.control_register
-            << ", Enable " << dec << (unsigned int) sync.enable
-            << endl;
-
-        for (j = 0; j < sync.pdo_count; j++) {
-            masterDev.getPdo(&pdo, slavePosition, i, j);
-
-            cout << "  " << (sync.control_register & 0x04 ? "R" : "T")
-                << "xPdo 0x"
-                << hex << setfill('0')
-                << setw(4) << pdo.index
-                << " \"" << pdo.name << "\"" << endl;
-
-            if (verbosity == Quiet)
-                continue;
-
-            for (k = 0; k < pdo.entry_count; k++) {
-                masterDev.getPdoEntry(&entry, slavePosition, i, j, k);
-
-                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;
-            }
-        }
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_sdos.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-#include "coe_datatypes.h"
-
-/****************************************************************************/
-
-const char *help_sdos =
-    "[OPTIONS]\n"
-    "\n"
-    "Displays the Sdo dictionary with Sdos and Sdo entries.\n"
-    "\n"
-    "Sdo dictionary information is displayed in two layers, with are\n"
-    "indented accordingly:\n"
-    "\n"
-    "1) Sdos - Hexadecimal Sdo index and the name. Example:\n"
-    "\n"
-    "   Sdo 0x1018, \"Identity object\"\n"
-    "\n"
-    "2) Sdo entries - Sdo index and Sdo entry subindex (both hexadecimal)\n"
-    "   followed by the data type, the length in bit, and the description.\n"
-    "   Example:\n"
-    "\n"
-    "   0x1018:01, uint32, 32 bit, \"Vendor id\"\n"
-    "\n"
-    "If the --quiet option is given, only the Sdos are printed.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                      all slaves (default).\n"
-    "  --quiet -q          Print only Sdos (without Sdo entries).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void listSlaveSdos(uint16_t, bool);
-
-/****************************************************************************/
-
-void command_sdos(void)
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (slavePosition == -1) {
-        unsigned int numSlaves = masterDev.slaveCount(), i;
-
-        for (i = 0; i < numSlaves; i++) {
-            listSlaveSdos(i, true);
-        }
-    } else {
-        listSlaveSdos(slavePosition, false);
-    }
-}
-
-/****************************************************************************/
-
-void listSlaveSdos(
-		uint16_t slavePosition,
-		bool withHeader
-		)
-{
-    ec_ioctl_slave_t slave;
-    ec_ioctl_slave_sdo_t sdo;
-    ec_ioctl_slave_sdo_entry_t entry;
-    unsigned int i, j;
-    const CoEDataType *d;
-    
-    masterDev.getSlave(&slave, slavePosition);
-
-    if (withHeader)
-        cout << "=== Slave " << slavePosition << " ===" << endl;
-
-    for (i = 0; i < slave.sdo_count; i++) {
-        masterDev.getSdo(&sdo, slavePosition, i);
-
-        cout << "Sdo 0x"
-            << hex << setfill('0')
-            << setw(4) << sdo.sdo_index
-            << ", \"" << sdo.name << "\"" << endl;
-
-        if (verbosity == Quiet)
-            continue;
-
-        for (j = 0; j <= sdo.max_subindex; j++) {
-            masterDev.getSdoEntry(&entry, slavePosition, -i, j);
-
-            cout << "  0x" << hex << setfill('0')
-                << setw(4) << sdo.sdo_index << ":"
-                << setw(2) << (unsigned int) entry.sdo_entry_subindex
-                << ", ";
-
-            if ((d = findDataType(entry.data_type))) {
-                cout << d->name;
-            } else {
-                cout << "type " << setw(4) << entry.data_type;
-            }
-
-            cout << ", " << dec << entry.bit_length << " bit, \""
-                << entry.description << "\"" << endl;
-        }
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_sii_read.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_sii_read =
-    "[OPTIONS]\n"
-    "\n"
-    "Outputs the SII (EEPROM) contents of a slave.\n"
-    "\n"
-    "Without the --verbose option, binary SII contents are output. They can\n"
-    "be piped to a tool like hexdump, for example:\n"
-    "\n"
-    "  ethercat sii_read -s2 | hexdump -C\n"
-    "\n"
-    "With the --verbose option given, a textual representation of the data\n"
-    "is output, that is separated by SII category names.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave   -s <index>  Positive numerical ring position (mandatory).\n"
-    "  --verbose -v          Output textual data with category names.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-struct CategoryName {
-    uint16_t type;
-    const char *name;
-};
-
-static const CategoryName categoryNames[] = {
-    {0x000a, "STRINGS"},
-    {0x0014, "DataTypes"},
-    {0x001e, "General"},
-    {0x0028, "FMMU"},
-    {0x0029, "SyncM"},
-    {0x0032, "TXPDO"},
-    {0x0033, "RXPDO"},
-    {0x003c, "DC"},
-    {}
-};
-
-/****************************************************************************/
-
-const char *getCategoryName(uint16_t type)
-{
-    const CategoryName *cn = categoryNames;
-
-    while (cn->type) {
-        if (cn->type == type) {
-            return cn->name;
-        }
-        cn++;
-    }
-
-    return "unknown";
-}
-
-/****************************************************************************/
-
-void command_sii_read(void)
-{
-    ec_ioctl_slave_sii_t data;
-    ec_ioctl_slave_t slave;
-    unsigned int i;
-    const uint16_t *categoryHeader;
-    uint16_t categoryType, categorySize;
-    stringstream err;
-
-    if (slavePosition < 0) {
-        err << "'" << commandName << "' requires a slave! "
-            << "Please specify --slave.";
-        throw InvalidUsageException(err);
-    }
-    data.slave_position = slavePosition;
-
-    masterDev.open(MasterDevice::Read);
-
-    masterDev.getSlave(&slave, slavePosition);
-
-    if (!slave.sii_nwords)
-        return;
-
-    data.offset = 0;
-    data.nwords = slave.sii_nwords;
-    data.words = new uint16_t[data.nwords];
-
-	try {
-		masterDev.readSii(&data);
-	} catch (MasterDeviceException &e) {
-        delete [] data.words;
-		throw e;
-	}
-
-    if (verbosity == Verbose) {
-        cout << "SII Area:" << hex << setfill('0');
-        for (i = 0; i < min(data.nwords, 0x0040U) * 2; i++) {
-            if (i % BreakAfterBytes) {
-                cout << " ";
-            } else {
-                cout << endl << "  ";
-            }
-            cout << setw(2) << (unsigned int) *((uint8_t *) data.words + i);
-        }
-        cout << endl;
-
-        if (data.nwords > 0x0040U) {
-            // cycle through categories
-            categoryHeader = data.words + 0x0040U;
-            categoryType = le16tocpu(*categoryHeader);
-            while (categoryType != 0xffff) {
-                cout << "SII Category 0x" << hex
-                    << setw(4) << categoryType
-                    << " (" << getCategoryName(categoryType) << ")" << flush;
-
-                if (categoryHeader + 1 > data.words + data.nwords) {
-                    err << "SII data seem to be corrupted!";
-                    throw CommandException(err);
-                }
-                categorySize = le16tocpu(*(categoryHeader + 1));
-                cout << ", " << dec << categorySize << " words" << flush;
-
-                if (categoryHeader + 2 + categorySize
-                        > data.words + data.nwords) {
-                    err << "SII data seem to be corrupted!";
-                    throw CommandException(err);
-                }
-
-                cout << hex;
-                for (i = 0; i < categorySize * 2U; i++) {
-                    if (i % BreakAfterBytes) {
-                        cout << " ";
-                    } else {
-                        cout << endl << "  ";
-                    }
-                    cout << setw(2) << (unsigned int)
-                        *((uint8_t *) (categoryHeader + 2) + i);
-                }
-                cout << endl;
-
-                if (categoryHeader + 2 + categorySize + 1
-                        > data.words + data.nwords) {
-                    err << "SII data seem to be corrupted!"; 
-                    throw CommandException(err);
-                }
-                categoryHeader += 2 + categorySize;
-                categoryType = le16tocpu(*categoryHeader);
-            }
-        }
-    } else {
-        for (i = 0; i < data.nwords; i++) {
-            uint16_t *w = data.words + i;
-            cout << *(uint8_t *) w << *((uint8_t *) w + 1);
-        }
-    }
-
-    delete [] data.words;
-}
-
-/*****************************************************************************/
--- a/tool/cmd_sii_write.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-#include <fstream>
-using namespace std;
-
-#include "globals.h"
-#include "sii_crc.h"
-
-/****************************************************************************/
-
-const char *help_sii_write =
-    "[OPTIONS] <FILENAME>\n"
-    "\n"
-    "Writes SII contents from a local file to a slave.\n"
-    "\n"
-    "The file contents are checked for validity and integrity. These checks\n"
-    "can be overridden with the --force option.\n"
-    "\n"
-    "Arguments:\n"
-    "  FILENAME must be a path to a file that contains a positive number\n"
-    "           of words.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position (mandatory).\n"
-    "  --force             Override validity checks.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void command_sii_write(void)
-{
-    stringstream err;
-    ec_ioctl_slave_sii_t data;
-    ifstream file;
-    unsigned int byte_size;
-    const uint16_t *categoryHeader;
-    uint16_t categoryType, categorySize;
-    uint8_t crc;
-
-    if (slavePosition < 0) {
-        err << "'" << commandName << "' requires a slave! "
-            << "Please specify --slave.";
-        throw InvalidUsageException(err);
-    }
-    data.slave_position = slavePosition;
-
-    if (commandArgs.size() != 1) {
-        err << "'" << commandName << "' takes exactly one argument!";
-        throw InvalidUsageException(err);
-    }
-
-    file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary);
-    if (file.fail()) {
-        err << "Failed to open '" << commandArgs[0] << "'!";
-        throw CommandException(err);
-    }
-
-    // get length of file
-    file.seekg(0, ios::end);
-    byte_size = file.tellg();
-    file.seekg(0, ios::beg);
-
-    if (!byte_size || byte_size % 2) {
-        err << "Invalid file size! Must be non-zero and even.";
-        throw CommandException(err);
-    }
-
-    data.nwords = byte_size / 2;
-    if (data.nwords < 0x0041 && !force) {
-        err << "SII data too short (" << data.nwords << " words)! Mimimum is"
-                " 40 fixed words + 1 delimiter. Use --force to write anyway.";
-        throw CommandException(err);
-    }
-
-    // allocate buffer and read file into buffer
-    data.words = new uint16_t[data.nwords];
-    file.read((char *) data.words, byte_size);
-    file.close();
-
-    if (!force) {
-        // calculate checksum over words 0 to 6
-        crc = calcSiiCrc((const uint8_t *) data.words, 14);
-        if (crc != ((const uint8_t *) data.words)[14]) {
-            err << "CRC incorrect. Must be 0x"
-                << hex << setfill('0') << setw(2) << (unsigned int) crc
-                << ". Use --force to write anyway.";
-            throw CommandException(err);
-        }
-
-        // cycle through categories to detect corruption
-        categoryHeader = data.words + 0x0040U;
-        categoryType = le16tocpu(*categoryHeader);
-        while (categoryType != 0xffff) {
-            if (categoryHeader + 1 > data.words + data.nwords) {
-                err << "SII data seem to be corrupted! "
-                    << "Use --force to write anyway.";
-                throw CommandException(err);
-            }
-            categorySize = le16tocpu(*(categoryHeader + 1));
-            if (categoryHeader + 2 + categorySize + 1
-                    > data.words + data.nwords) {
-                err << "SII data seem to be corrupted! "
-                    "Use --force to write anyway.";
-                throw CommandException(err);
-            }
-            categoryHeader += 2 + categorySize;
-            categoryType = le16tocpu(*categoryHeader);
-        }
-    }
-
-    // send data to master
-    masterDev.open(MasterDevice::ReadWrite);
-    data.offset = 0;
-	masterDev.writeSii(&data);
-}
-
-/*****************************************************************************/
--- a/tool/cmd_slaves.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-#include <list>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_slaves =
-    "[OPTIONS]\n"
-    "\n"
-    "Display slaves on the bus.\n"
-    "\n"
-    "If the --verbose option is not given, the slaves are displayed\n"
-    "one-per-line. Example:\n"
-    "\n"
-    "1  5555:0  PREOP  +  EL3162 2C. Ana. Input 0-10V\n"
-    "|  |    |  |      |  |\n"
-    "|  |    |  |      |  \\- Name from SII if avaliable, otherwise\n"
-    "|  |    |  |      |     hexadecimal vendor ID and product code\n"
-    "|  |    |  |      |     separated by a colon.\n"
-    "|  |    |  |      \\- Error flag. '+' means no error, 'E' means,\n"
-    "|  |    |  |         that scanning or configuration failed.\n"
-    "|  |    |  \\- Current slave state.\n"
-    "|  |    \\- Relative position (decimal) after the last slave with an\n"
-    "|  |       alias address set.\n"
-    "|  \\- Alias address of the slave (if set to non-zero), or the alias\n"
-    "|     of the last slave with an alias set, or zero if there is none.\n"
-    "\\- Ring position (use this with any --slave option).\n"
-    "\n"
-    "If the --verbose option is given, a detailed (multi-line) description\n"
-    "is output for each slave.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave   -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                        all slaves (default).\n"
-    "  --verbose -v          Show detailed slave information.\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void listSlaves(int);
-void showSlave(uint16_t);
-
-/****************************************************************************/
-
-void command_slaves()
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (verbosity == Verbose) {
-        if (slavePosition == -1) {
-            unsigned int numSlaves = masterDev.slaveCount(), i;
-
-            for (i = 0; i < numSlaves; i++) {
-                showSlave(i);
-            }
-        } else {
-            showSlave(slavePosition);
-        }
-    } else {
-        listSlaves(slavePosition);
-    }
-}
-
-/****************************************************************************/
-
-string slaveState(uint8_t state)
-{
-    switch (state) {
-        case 1: return "INIT";
-        case 2: return "PREOP";
-        case 4: return "SAFEOP";
-        case 8: return "OP";
-        default: return "???";
-    }
-}
-
-/****************************************************************************/
-
-struct SlaveInfo {
-    string pos;
-    string alias;
-    string relPos;
-    string state;
-    string flag;
-    string name;
-};
-
-void listSlaves(int slavePosition)
-{
-    unsigned int numSlaves, i;
-    ec_ioctl_slave_t slave;
-    uint16_t lastAlias, aliasIndex;
-    SlaveInfo slaveInfo;
-    typedef list<SlaveInfo> SlaveInfoList;
-    SlaveInfoList slaveInfoList;
-    SlaveInfoList::const_iterator iter;
-    stringstream str;
-    unsigned int maxPosWidth = 0, maxAliasWidth = 0,
-                 maxRelPosWidth = 0, maxStateWidth = 0;
-    
-    numSlaves = masterDev.slaveCount();
-
-    lastAlias = 0;
-    aliasIndex = 0;
-    for (i = 0; i < numSlaves; i++) {
-        masterDev.getSlave(&slave, i);
-        
-        if (slave.alias) {
-            lastAlias = slave.alias;
-            aliasIndex = 0;
-        }
-
-        if (slavePosition == -1 || i == (unsigned int) slavePosition) {
-            str << dec << i;
-            slaveInfo.pos = str.str();
-            str.clear();
-            str.str("");
-
-            str << lastAlias;
-            slaveInfo.alias = str.str();
-            str.str("");
-
-            str << aliasIndex;
-            slaveInfo.relPos = str.str();
-            str.str("");
-
-            slaveInfo.state = slaveState(slave.state);
-            slaveInfo.flag = (slave.error_flag ? 'E' : '+');
-
-            if (strlen(slave.name)) {
-                slaveInfo.name = slave.name;
-            } else {
-                str << "0x" << hex << setfill('0')
-                    << setw(8) << slave.vendor_id << ":0x"
-                    << setw(8) << slave.product_code;
-                slaveInfo.name = str.str();
-                str.str("");
-            }
-
-
-            slaveInfoList.push_back(slaveInfo);
-
-            if (slaveInfo.pos.length() > maxPosWidth)
-                maxPosWidth = slaveInfo.pos.length();
-            if (slaveInfo.alias.length() > maxAliasWidth)
-                maxAliasWidth = slaveInfo.alias.length();
-            if (slaveInfo.relPos.length() > maxRelPosWidth)
-                maxRelPosWidth = slaveInfo.relPos.length();
-            if (slaveInfo.state.length() > maxStateWidth)
-                maxStateWidth = slaveInfo.state.length();
-        }
-
-        aliasIndex++;
-    }
-
-    for (iter = slaveInfoList.begin(); iter != slaveInfoList.end(); iter++) {
-        cout << setfill(' ') << right
-            << setw(maxPosWidth) << iter->pos << "  "
-            << setw(maxAliasWidth) << iter->alias
-            << ":" << left
-            << setw(maxRelPosWidth) << iter->relPos << "  "
-            << setw(maxStateWidth) << iter->state << "  "
-            << iter->flag << "  "
-            << iter->name << endl;
-    }
-}
-
-/****************************************************************************/
-
-void showSlave(uint16_t slavePosition)
-{
-    ec_ioctl_slave_t slave;
-    list<string> protoList;
-    list<string>::const_iterator protoIter;
-    
-    masterDev.getSlave(&slave, slavePosition);
-        
-    cout << "=== Slave " << dec << slavePosition << " ===" << endl;
-    
-    if (slave.alias)
-        cout << "Alias: " << slave.alias << endl;
-
-    cout
-        << "State: " << slaveState(slave.state) << endl
-        << "Flag: " << (slave.error_flag ? 'E' : '+') << endl
-        << "Identity:" << endl
-        << "  Vendor Id:       0x"
-        << hex << setfill('0')
-        << setw(8) << slave.vendor_id << endl
-        << "  Product code:    0x"
-        << setw(8) << slave.product_code << endl
-        << "  Revision number: 0x"
-        << setw(8) << slave.revision_number << endl
-        << "  Serial number:   0x"
-        << setw(8) << slave.serial_number << endl;
-
-    if (slave.mailbox_protocols) {
-        cout << "Mailboxes:" << endl
-        << "  RX: 0x"
-        << hex << setw(4) << slave.rx_mailbox_offset << "/"
-        << dec << slave.rx_mailbox_size
-        << ", TX: 0x"
-        << hex << setw(4) << slave.tx_mailbox_offset << "/"
-        << dec << slave.tx_mailbox_size << endl
-        << "  Supported protocols: ";
-
-        if (slave.mailbox_protocols & EC_MBOX_AOE) {
-            protoList.push_back("AoE");
-        }
-        if (slave.mailbox_protocols & EC_MBOX_EOE) {
-            protoList.push_back("EoE");
-        }
-        if (slave.mailbox_protocols & EC_MBOX_COE) {
-            protoList.push_back("CoE");
-        }
-        if (slave.mailbox_protocols & EC_MBOX_FOE) {
-            protoList.push_back("FoE");
-        }
-        if (slave.mailbox_protocols & EC_MBOX_SOE) {
-            protoList.push_back("SoE");
-        }
-        if (slave.mailbox_protocols & EC_MBOX_VOE) {
-            protoList.push_back("VoE");
-        }
-
-        for (protoIter = protoList.begin(); protoIter != protoList.end();
-                protoIter++) {
-            if (protoIter != protoList.begin())
-                cout << ", ";
-            cout << *protoIter;
-        }
-        cout << endl;
-    }
-
-    if (slave.has_general_category) {
-        cout << "General:" << endl
-            << "  Group: " << slave.group << endl
-            << "  Image name: " << slave.image << endl
-            << "  Order number: " << slave.order << endl
-            << "  Device name: " << slave.name << endl;
-
-        if (slave.mailbox_protocols & EC_MBOX_COE) {
-            cout << "  CoE details:" << endl
-                << "    Enable Sdo: "
-                << (slave.coe_details.enable_sdo ? "yes" : "no") << endl
-                << "    Enable Sdo Info: "
-                << (slave.coe_details.enable_sdo_info ? "yes" : "no") << endl
-                << "    Enable Pdo Assign: "
-                << (slave.coe_details.enable_pdo_assign
-                        ? "yes" : "no") << endl
-                << "    Enable Pdo Configuration: "
-                << (slave.coe_details.enable_pdo_configuration
-                        ? "yes" : "no") << endl
-                << "    Enable Upload at startup: "
-                << (slave.coe_details.enable_upload_at_startup
-                        ? "yes" : "no") << endl
-                << "    Enable Sdo complete access: "
-                << (slave.coe_details.enable_sdo_complete_access
-                        ? "yes" : "no") << endl;
-        }
-
-        cout << "  Flags:" << endl
-            << "    Enable SafeOp: "
-            << (slave.general_flags.enable_safeop ? "yes" : "no") << endl
-            << "    Enable notLRW: "
-            << (slave.general_flags.enable_not_lrw ? "yes" : "no") << endl
-            << "  Current consumption: "
-            << dec << slave.current_on_ebus << " mA" << endl;
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_states.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_states =
-    "[OPTIONS] <STATE>\n"
-    "\n"
-    "Request an application-layer state change for the specified slaves.\n"
-    "\n"
-    "Arguments:\n"
-    "  STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                      all slaves (default).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void command_states(void)
-{
-    stringstream err;
-    string stateStr;
-    uint8_t state;
-    
-    if (commandArgs.size() != 1) {
-        err << "'" << commandName << "' takes exactly one argument!";
-        throw InvalidUsageException(err);
-    }
-
-    stateStr = commandArgs[0];
-    transform(stateStr.begin(), stateStr.end(),
-            stateStr.begin(), (int (*) (int)) std::toupper);
-
-    if (stateStr == "INIT") {
-        state = 0x01;
-    } else if (stateStr == "PREOP") {
-        state = 0x02;
-    } else if (stateStr == "SAFEOP") {
-        state = 0x04;
-    } else if (stateStr == "OP") {
-        state = 0x08;
-    } else {
-        err << "Invalid state '" << commandArgs[0] << "'!";
-        throw InvalidUsageException(err);
-    }
-
-    masterDev.open(MasterDevice::ReadWrite);
-
-    if (slavePosition == -1) {
-        unsigned int i, numSlaves = masterDev.slaveCount();
-        for (i = 0; i < numSlaves; i++)
-            masterDev.requestState(i, state);
-    } else {
-        masterDev.requestState(slavePosition, state);
-    }
-}
-
-/*****************************************************************************/
--- a/tool/cmd_upload.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-#include "coe_datatypes.h"
-
-/****************************************************************************/
-
-const char *help_upload =
-    "[OPTIONS] <INDEX> <SUBINDEX>\n"
-    "\n"
-    "Upload an Sdo entry from a slave.\n"
-    "\n"
-    "The data type of the Sdo entry is taken from the Sdo dictionary by\n"
-    "default. It can be overridden with the --type option. If the slave\n"
-    "does not support the Sdo information service or the Sdo is not in the\n"
-    "dictionary, the --type option is mandatory.\n"
-    "\n"
-    "These are the valid Sdo entry data types:\n"
-    "  int8, int16, int32, uint8, uint16, uint32, string.\n"
-    "\n"
-    "Arguments:\n"
-    "  INDEX    is the Sdo index and must be an unsigned 16 bit number.\n"
-    "  SUBINDEX is the Sdo entry subindex and must be an unsigned 8 bit\n"
-    "           number.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position (mandatory).\n"
-    "  --type  -t <type>   Forced Sdo entry data type (see above).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void command_upload(void)
-{
-    stringstream err, strIndex, strSubIndex;
-    int sval;
-    ec_ioctl_slave_sdo_upload_t data;
-    unsigned int uval;
-    const CoEDataType *dataType = NULL;
-
-    if (slavePosition < 0) {
-        err << "'" << commandName << "' requires a slave! "
-            << "Please specify --slave.";
-        throw InvalidUsageException(err);
-    }
-    data.slave_position = slavePosition;
-
-    if (commandArgs.size() != 2) {
-        err << "'" << commandName << "' takes two arguments!";
-        throw InvalidUsageException(err);
-    }
-
-    strIndex << commandArgs[0];
-    strIndex
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> data.sdo_index;
-    if (strIndex.fail()) {
-        err << "Invalid Sdo index '" << commandArgs[0] << "'!";
-        throw InvalidUsageException(err);
-    }
-
-    strSubIndex << commandArgs[1];
-    strSubIndex
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> uval;
-    if (strSubIndex.fail() || uval > 0xff) {
-        err << "Invalid Sdo subindex '" << commandArgs[1] << "'!";
-        throw InvalidUsageException(err);
-    }
-    data.sdo_entry_subindex = uval;
-
-    if (dataTypeStr != "") { // data type specified
-        if (!(dataType = findDataType(dataTypeStr))) {
-            err << "Invalid data type '" << dataTypeStr << "'!";
-            throw InvalidUsageException(err);
-        }
-    } else { // no data type specified: fetch from dictionary
-        ec_ioctl_slave_sdo_entry_t entry;
-
-        masterDev.open(MasterDevice::Read);
-
-        try {
-            masterDev.getSdoEntry(&entry, slavePosition,
-                    data.sdo_index, data.sdo_entry_subindex);
-        } catch (MasterDeviceException &e) {
-            err << "Failed to determine Sdo entry data type. "
-                << "Please specify --type.";
-            throw CommandException(err);
-        }
-        if (!(dataType = findDataType(entry.data_type))) {
-            err << "Pdo entry has unknown data type 0x"
-                << hex << setfill('0') << setw(4) << entry.data_type << "!"
-                << " Please specify --type.";
-            throw CommandException(err);
-        }
-    }
-
-    if (dataType->byteSize) {
-        data.target_size = dataType->byteSize;
-    } else {
-        data.target_size = DefaultBufferSize;
-    }
-
-    data.target = new uint8_t[data.target_size + 1];
-
-    masterDev.open(MasterDevice::Read);
-
-	try {
-		masterDev.sdoUpload(&data);
-	} catch (MasterDeviceException &e) {
-        delete [] data.target;
-        throw e;
-    }
-
-    masterDev.close();
-
-    if (dataType->byteSize && data.data_size != dataType->byteSize) {
-        err << "Data type mismatch. Expected " << dataType->name
-            << " with " << dataType->byteSize << " byte, but got "
-            << data.data_size << " byte.";
-        throw CommandException(err);
-    }
-
-    cout << setfill('0');
-    switch (dataType->coeCode) {
-        case 0x0002: // int8
-            sval = *(int8_t *) data.target;
-            cout << sval << " 0x" << hex << setw(2) << sval << endl;
-            break;
-        case 0x0003: // int16
-            sval = le16tocpu(*(int16_t *) data.target);
-            cout << sval << " 0x" << hex << setw(4) << sval << endl;
-            break;
-        case 0x0004: // int32
-            sval = le32tocpu(*(int32_t *) data.target);
-            cout << sval << " 0x" << hex << setw(8) << sval << endl;
-            break;
-        case 0x0005: // uint8
-            uval = (unsigned int) *(uint8_t *) data.target;
-            cout << uval << " 0x" << hex << setw(2) << uval << endl;
-            break;
-        case 0x0006: // uint16
-            uval = le16tocpu(*(uint16_t *) data.target);
-            cout << uval << " 0x" << hex << setw(4) << uval << endl;
-            break;
-        case 0x0007: // uint32
-            uval = le32tocpu(*(uint32_t *) data.target);
-            cout << uval << " 0x" << hex << setw(8) << uval << endl;
-            break;
-        case 0x0009: // string
-            cout << string((const char *) data.target, data.data_size)
-                << endl;
-            break;
-        default:
-            printRawData(data.target, data.data_size);
-            break;
-    }
-
-    delete [] data.target;
-}
-
-/*****************************************************************************/
--- a/tool/cmd_xml.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <iostream>
-#include <iomanip>
-using namespace std;
-
-#include "globals.h"
-
-/****************************************************************************/
-
-const char *help_xml =
-    "[OPTIONS]\n"
-    "\n"
-    "Generate slave description XMLs from the master's slave information.\n"
-    "\n"
-    "Note that the Pdo information can either originate from the SII or\n"
-    "from the CoE communication area. For some slaves, this is dependant on\n"
-    "the last slave configuration.\n"
-    "\n"
-    "Command-specific options:\n"
-    "  --slave -s <index>  Positive numerical ring position, or 'all' for\n"
-    "                      all slaves (default).\n"
-    "\n"
-    "Numerical values can be specified either with decimal (no prefix),\n"
-    "octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
-
-/****************************************************************************/
-
-void generateSlaveXml(uint16_t);
-
-/****************************************************************************/
-
-void command_xml(void)
-{
-    masterDev.open(MasterDevice::Read);
-
-    if (slavePosition == -1) {
-        unsigned int numSlaves = masterDev.slaveCount(), i;
-
-        for (i = 0; i < numSlaves; i++) {
-            generateSlaveXml(i);
-        }
-    } else {
-        generateSlaveXml(slavePosition);
-    }
-}
-
-/****************************************************************************/
-
-void generateSlaveXml(uint16_t slavePosition)
-{
-    ec_ioctl_slave_t slave;
-    ec_ioctl_slave_sync_t sync;
-    ec_ioctl_slave_sync_pdo_t pdo;
-    string pdoType;
-    ec_ioctl_slave_sync_pdo_entry_t entry;
-    unsigned int i, j, k;
-    
-    masterDev.getSlave(&slave, slavePosition);
-
-    cout
-        << "<?xml version=\"1.0\" ?>" << endl
-        << "  <EtherCATInfo>" << endl
-        << "    <!-- Slave " << slave.position << " -->" << endl
-        << "    <Vendor>" << endl
-        << "      <Id>" << slave.vendor_id << "</Id>" << endl
-        << "    </Vendor>" << endl
-        << "    <Descriptions>" << endl
-        << "      <Devices>" << endl
-        << "        <Device>" << endl
-        << "          <Type ProductCode=\"#x"
-        << hex << setfill('0') << setw(8) << slave.product_code
-        << "\" RevisionNo=\"#x"
-        << hex << setfill('0') << setw(8) << slave.revision_number
-        << "\">" << slave.order << "</Type>" << endl;
-
-    if (strlen(slave.name)) {
-        cout
-            << "          <Name><![CDATA["
-            << slave.name
-            << "]]></Name>" << endl;
-    }
-
-    for (i = 0; i < slave.sync_count; i++) {
-        masterDev.getSync(&sync, slavePosition, i);
-
-        cout
-            << "          <Sm Enable=\"" << dec << (unsigned int) sync.enable
-            << "\" StartAddress=\"" << sync.physical_start_address
-            << "\" ControlByte=\"" << (unsigned int) sync.control_register
-            << "\" DefaultSize=\"" << sync.default_size
-            << "\" />" << endl;
-    }
-
-    for (i = 0; i < slave.sync_count; i++) {
-        masterDev.getSync(&sync, slavePosition, i);
-
-        for (j = 0; j < sync.pdo_count; j++) {
-            masterDev.getPdo(&pdo, slavePosition, i, j);
-            pdoType = (sync.control_register & 0x04 ? "R" : "T");
-            pdoType += "xPdo";
-
-            cout
-                << "          <" << pdoType
-                << " Sm=\"" << i << "\" Fixed=\"1\" Mandatory=\"1\">" << endl
-                << "            <Index>#x"
-                << hex << setfill('0') << setw(4) << pdo.index
-                << "</Index>" << endl
-                << "            <Name>" << pdo.name << "</Name>" << endl;
-
-            for (k = 0; k < pdo.entry_count; k++) {
-                masterDev.getPdoEntry(&entry, slavePosition, i, j, k);
-
-                cout
-                    << "            <Entry>" << endl
-                    << "              <Index>#x"
-                    << hex << setfill('0') << setw(4) << entry.index
-                    << "</Index>" << endl;
-                if (entry.index)
-                    cout
-                        << "              <SubIndex>"
-                        << dec << (unsigned int) entry.subindex
-                        << "</SubIndex>" << endl;
-                
-                cout
-                    << "              <BitLen>"
-                    << dec << (unsigned int) entry.bit_length
-                    << "</BitLen>" << endl;
-
-                if (entry.index) {
-                    cout
-                        << "              <Name>" << entry.name
-                        << "</Name>" << endl
-                        << "              <DataType>";
-
-                    if (entry.bit_length == 1) {
-                        cout << "BOOL";
-                    } else if (!(entry.bit_length % 8)) {
-                        if (entry.bit_length <= 64)
-                            cout << "UINT" << (unsigned int) entry.bit_length;
-                        else
-                            cout << "STRING("
-                                << (unsigned int) (entry.bit_length / 8)
-                                << ")";
-                    } else {
-                        cerr << "Invalid bit length "
-                            << (unsigned int) entry.bit_length << endl;
-                    }
-
-                        cout << "</DataType>" << endl;
-                }
-
-                cout << "            </Entry>" << endl;
-            }
-
-            cout
-                << "          </" << pdoType << ">" << endl;
-        }
-    }
-
-    cout
-        << "        </Device>" << endl
-        << "     </Devices>" << endl
-        << "  </Descriptions>" << endl
-        << "</EtherCATInfo>" << endl;
-}
-/*****************************************************************************/
--- a/tool/globals.h	Thu Jul 24 08:15:44 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*****************************************************************************
- *
- * $Id$
- *
- ****************************************************************************/
-
-#include <sys/types.h>
-
-#include <string>
-#include <sstream>
-#include <vector>
-using namespace std;
-
-#include "MasterDevice.h"
-
-/*****************************************************************************/
-
-enum Verbosity {
-    Quiet,
-    Normal,
-    Verbose
-};
-
-extern string commandName;
-extern unsigned int masterIndex;
-extern int slavePosition;
-extern int domainIndex;
-extern vector<string> commandArgs;
-extern Verbosity verbosity;
-extern string dataTypeStr;
-extern bool force;
-
-extern MasterDevice masterDev;
-
-/****************************************************************************/
-
-class InvalidUsageException:
-    public runtime_error
-{
-    public:
-        /** Constructor with std::string parameter. */
-        InvalidUsageException(
-                const stringstream &s /**< Message. */
-                ): runtime_error(s.str()) {}
-};
-
-/****************************************************************************/
-
-class CommandException:
-    public runtime_error
-{
-    public:
-        /** Constructor with std::string parameter. */
-        CommandException(
-                const stringstream &s /**< Message. */
-                ): runtime_error(s.str()) {}
-};
-
-/*****************************************************************************/
-
-#define swap16(x) \
-        ((uint16_t)( \
-        (((uint16_t)(x) & 0x00ffU) << 8) | \
-        (((uint16_t)(x) & 0xff00U) >> 8) ))
-#define swap32(x) \
-        ((uint32_t)( \
-        (((uint32_t)(x) & 0x000000ffUL) << 24) | \
-        (((uint32_t)(x) & 0x0000ff00UL) <<  8) | \
-        (((uint32_t)(x) & 0x00ff0000UL) >>  8) | \
-        (((uint32_t)(x) & 0xff000000UL) >> 24) ))
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-#define le16tocpu(x) x
-#define le32tocpu(x) x
-
-#define cputole16(x) x
-#define cputole32(x) x
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-#define le16tocpu(x) swap16(x)
-#define le32tocpu(x) swap32(x)
-
-#define cputole16(x) swap16(x)
-#define cputole32(x) swap32(x)
-
-#endif
-
-/****************************************************************************/
-
-enum {BreakAfterBytes = 16};
-enum {DefaultBufferSize = 1024};
-
-void printRawData(const uint8_t *, unsigned int);
-
-/****************************************************************************/
--- a/tool/main.cpp	Thu Jul 24 08:15:44 2008 +0000
+++ b/tool/main.cpp	Thu Jul 24 13:27:06 2008 +0000
@@ -9,96 +9,54 @@
 
 #include <iostream>
 #include <iomanip>
-#include <string>
-#include <vector>
-#include <list>
 using namespace std;
 
-#include "globals.h"
+#include "CommandAlias.h"
+#include "CommandConfig.h"
+#include "CommandData.h"
+#include "CommandDebug.h"
+#include "CommandDomains.h"
+#include "CommandMaster.h"
+#include "CommandPdos.h"
+#include "CommandSdos.h"
+#include "CommandDownload.h"
+#include "CommandUpload.h"
+#include "CommandSlaves.h"
+#include "CommandSiiRead.h"
+#include "CommandSiiWrite.h"
+#include "CommandStates.h"
+#include "CommandXml.h"
 
 /*****************************************************************************/
 
+typedef list<Command *> CommandList;
+CommandList commandList;
+
+MasterDevice masterDev;
+
 string binaryBaseName;
+string commandName;
+Command::StringVector commandArgs;
+
+// option variables
 unsigned int masterIndex = 0;
 int slavePosition = -1;
 int domainIndex = -1;
-string commandName;
-vector<string> commandArgs;
-Verbosity verbosity = Normal;
 string dataTypeStr;
+Command::Verbosity verbosity = Command::Normal;
 bool force = false;
-
 bool helpRequested = false;
 
-MasterDevice masterDev;
-
-/*****************************************************************************/
-
-struct Command {
-    const char *name;
-    void (*func)(void);
-    const char *helpString;
-    const char *briefDesc;
-
-    int execute(void) const;
-    string getHelpString(void) const;
-};
-
-/*****************************************************************************/
-
-#define DEFINE_EXTERN_COMMAND(name) \
-    void command_##name(void); \
-    extern const char *help_##name
-
-#define INIT_COMMAND(name, desc) \
-    {#name, command_##name, help_##name, desc}
-
-DEFINE_EXTERN_COMMAND(alias);
-DEFINE_EXTERN_COMMAND(config);
-DEFINE_EXTERN_COMMAND(data);
-DEFINE_EXTERN_COMMAND(debug);
-DEFINE_EXTERN_COMMAND(domains);
-DEFINE_EXTERN_COMMAND(master);
-DEFINE_EXTERN_COMMAND(pdos);
-DEFINE_EXTERN_COMMAND(sdos);
-DEFINE_EXTERN_COMMAND(download);
-DEFINE_EXTERN_COMMAND(upload);
-DEFINE_EXTERN_COMMAND(slaves);
-DEFINE_EXTERN_COMMAND(sii_read);
-DEFINE_EXTERN_COMMAND(sii_write);
-DEFINE_EXTERN_COMMAND(states);
-DEFINE_EXTERN_COMMAND(xml);
-
-static const Command commands[] = {
-    INIT_COMMAND(alias, "Write alias addresses."),
-    INIT_COMMAND(config, "Show bus configuration."),
-    INIT_COMMAND(data, "Output binary domain process data."),
-    INIT_COMMAND(debug, "Set the master's debug level."),
-    INIT_COMMAND(domains, "Show domain information."),
-    INIT_COMMAND(master, "Show master information."),
-    INIT_COMMAND(pdos, "List Pdo assignment/mapping."),
-    INIT_COMMAND(sdos, "List Sdo dictionaries."),
-    INIT_COMMAND(download, "Write an Sdo entry."),
-    INIT_COMMAND(upload, "Read an Sdo entry."),
-    INIT_COMMAND(slaves, "Show slaves."),
-    INIT_COMMAND(sii_read, "Output a slave's SII contents."),
-    INIT_COMMAND(sii_write, "Write slave's SII contents."),
-    INIT_COMMAND(states, "Request slave states."),
-    INIT_COMMAND(xml, "Generate slave information XML."),
-};
-
-static const Command *cmdEnd = commands + sizeof(commands) / sizeof(Command);
-
 /*****************************************************************************/
 
 void printUsage()
 {
-    const Command *cmd;
+    CommandList::const_iterator ci;
     size_t maxWidth = 0;
 
-    for (cmd = commands; cmd < cmdEnd; cmd++) {
-        if (strlen(cmd->name) > maxWidth) {
-            maxWidth = strlen(cmd->name);
+    for (ci = commandList.begin(); ci != commandList.end(); ci++) {
+        if ((*ci)->getName().length() > maxWidth) {
+            maxWidth = (*ci)->getName().length();
         }
     }
 
@@ -108,9 +66,9 @@
 		<< "Commands (can be abbreviated):" << endl;
 
     cerr << left;
-    for (cmd = commands; cmd < cmdEnd; cmd++) {
-        cerr << "  " << setw(maxWidth) << cmd->name
-            << " " << cmd->briefDesc << endl;
+    for (ci = commandList.begin(); ci != commandList.end(); ci++) {
+        cerr << "  " << setw(maxWidth) << (*ci)->getName()
+            << "  " << (*ci)->getBriefDescription() << endl;
     }
 
     cerr
@@ -207,11 +165,11 @@
                 break;
 
             case 'q':
-                verbosity = Quiet;
+                verbosity = Command::Quiet;
                 break;
 
             case 'v':
-                verbosity = Verbose;
+                verbosity = Command::Verbose;
                 break;
 
             case 'h':
@@ -245,76 +203,23 @@
 
 /****************************************************************************/
 
-int Command::execute() const
+list<Command *> getMatchingCommands(const string &cmdStr)
 {
-    try {
-        func();
-    } catch (InvalidUsageException &e) {
-        cerr << e.what() << endl << endl;
-        cerr << getHelpString();
-        return 1;
-    } catch (CommandException &e) {
-        cerr << e.what() << endl;
-        return 1;
-    } catch (MasterDeviceException &e) {
-        cerr << e.what() << endl;
-        return 1;
-    }
-
-    return 0;
-}
-
-/****************************************************************************/
-
-string Command::getHelpString() const
-{
-    stringstream help;
-    help << binaryBaseName << " " << commandName << " " << helpString;
-    return help.str();
-}
-
-/****************************************************************************/
-
-bool substrMatch(const string &abb, const string &full)
-{
-    return full.substr(0, abb.length()) == abb;
-}
-    
-/****************************************************************************/
-
-bool abbrevMatch(const string &abb, const string &full)
-{
-    unsigned int abbIndex;
-    size_t fullPos = 0;
-
-    for (abbIndex = 0; abbIndex < abb.length(); abbIndex++) {
-        fullPos = full.find(abb[abbIndex], fullPos);
-        if (fullPos == string::npos)
-            return false;
-    }
-
-    return true;
-}
-    
-/****************************************************************************/
-
-list<const Command *> getMatchingCommands(const string &cmdStr)
-{
-    const Command *cmd;
-    list<const Command *> res;
+    CommandList::iterator ci;
+    list<Command *> res;
 
     // find matching commands from beginning of the string
-    for (cmd = commands; cmd < cmdEnd; cmd++) {
-        if (substrMatch(cmdStr, cmd->name)) {
-            res.push_back(cmd);
+    for (ci = commandList.begin(); ci != commandList.end(); ci++) {
+        if ((*ci)->matchesSubstr(cmdStr)) {
+            res.push_back(*ci);
         }
     }
 
     if (!res.size()) { // nothing found
         // find /any/ matching commands
-        for (cmd = commands; cmd < cmdEnd; cmd++) {
-            if (abbrevMatch(cmdStr, cmd->name)) {
-                res.push_back(cmd);
+        for (ci = commandList.begin(); ci != commandList.end(); ci++) {
+            if ((*ci)->matchesAbbrev(cmdStr)) {
+                res.push_back(*ci);
             }
         }
     }
@@ -327,29 +232,59 @@
 int main(int argc, char **argv)
 {
     int retval = 0;
-    list<const Command *> commands;
-    list<const Command *>::const_iterator ci;
-    const Command *cmd;
+    list<Command *> matchingCommands;
+    list<Command *>::const_iterator ci;
+    Command *cmd;
 
     binaryBaseName = basename(argv[0]);
+
+    commandList.push_back(new CommandAlias());
+    commandList.push_back(new CommandConfig());
+    commandList.push_back(new CommandData());
+    commandList.push_back(new CommandDebug());
+    commandList.push_back(new CommandDomains());
+    commandList.push_back(new CommandDownload());
+    commandList.push_back(new CommandMaster());
+    commandList.push_back(new CommandPdos());
+    commandList.push_back(new CommandSdos());
+    commandList.push_back(new CommandSiiRead());
+    commandList.push_back(new CommandSiiWrite());
+    commandList.push_back(new CommandSlaves());
+    commandList.push_back(new CommandStates());
+    commandList.push_back(new CommandUpload());
+    commandList.push_back(new CommandXml());
+
 	getOptions(argc, argv);
 
-    commands = getMatchingCommands(commandName);
-
-    if (commands.size()) {
-        if (commands.size() == 1) {
-            cmd = commands.front();
-            commandName = cmd->name;
+    matchingCommands = getMatchingCommands(commandName);
+    masterDev.setIndex(masterIndex);
+
+    if (matchingCommands.size()) {
+        if (matchingCommands.size() == 1) {
+            cmd = matchingCommands.front();
             if (!helpRequested) {
-                masterDev.setIndex(masterIndex);
-                retval = cmd->execute();
+                try {
+                    cmd->execute(masterDev, commandArgs);
+                } catch (InvalidUsageException &e) {
+                    cerr << e.what() << endl << endl;
+                    cerr << cmd->helpString();
+                    retval = 1;
+                } catch (CommandException &e) {
+                    cerr << e.what() << endl;
+                    retval = 1;
+                } catch (MasterDeviceException &e) {
+                    cerr << e.what() << endl;
+                    retval = 1;
+                }
             } else {
-                cout << cmd->getHelpString();
+                cout << cmd->helpString();
             }
         } else {
             cerr << "Ambiguous command abbreviation! Matching:" << endl;
-            for (ci = commands.begin(); ci != commands.end(); ci++) {
-                cerr << (*ci)->name << endl;
+            for (ci = matchingCommands.begin();
+                    ci != matchingCommands.end();
+                    ci++) {
+                cerr << (*ci)->getName() << endl;
             }
             cerr << endl;
             printUsage();
@@ -365,19 +300,3 @@
 }
 
 /****************************************************************************/
-
-void printRawData(
-		const uint8_t *data,
-		unsigned int size
-		)
-{
-    cout << hex << setfill('0');
-    while (size--) {
-        cout << "0x" << setw(2) << (unsigned int) *data++;
-        if (size)
-            cout << " ";
-    }
-    cout << endl;
-}
-
-/****************************************************************************/