Output IDN configuration as part of 'ethercat config -v'.
authorFlorian Pose <fp@igh-essen.com>
Sun, 24 Oct 2010 08:43:44 +0200
changeset 1966 23c638a81fe7
parent 1965 c6e6ec6ba5d8
child 1967 c41b4f4af645
Output IDN configuration as part of 'ethercat config -v'.
TODO
master/cdev.c
master/ioctl.h
master/slave_config.c
master/slave_config.h
tool/CommandConfig.cpp
tool/CommandConfig.h
tool/CommandSoeRead.cpp
tool/CommandSoeRead.h
tool/CommandSoeWrite.cpp
tool/CommandSoeWrite.h
tool/MasterDevice.cpp
tool/MasterDevice.h
tool/SoeCommand.cpp
tool/SoeCommand.h
--- a/TODO	Wed Sep 22 15:41:43 2010 +0200
+++ b/TODO	Sun Oct 24 08:43:44 2010 +0200
@@ -30,7 +30,6 @@
 * Read AL status code on spontaneous state change.
 * recompile tool/CommandVersion.cpp if revision changes.
 * Log SoE IDNs with real name ([SP]-x-yyyy).
-* Output SoE IDN configurations in 'ethercat config'.
 * Only output watchdog config if not default.
 * Implement CompleteAccess for SDO uploads.
 * Output warning when send_ext() is called in illegal context.
--- a/master/cdev.c	Wed Sep 22 15:41:43 2010 +0200
+++ b/master/cdev.c	Sun Oct 24 08:43:44 2010 +0200
@@ -1349,6 +1349,7 @@
     data.watchdog_divider = sc->watchdog_divider;
     data.watchdog_intervals = sc->watchdog_intervals;
     data.sdo_count = ec_slave_config_sdo_count(sc);
+    data.idn_count = ec_slave_config_idn_count(sc);
     data.slave_position = sc->slave ? sc->slave->ring_position : -1;
     data.dc_assign_activate = sc->dc_assign_activate;
     for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) {
@@ -1531,6 +1532,56 @@
 
 /*****************************************************************************/
 
+/** Get slave configuration IDN information.
+ */
+int ec_cdev_ioctl_config_idn(
+        ec_master_t *master, /**< EtherCAT master. */
+        unsigned long arg /**< ioctl() argument. */
+        )
+{
+    ec_ioctl_config_idn_t data;
+    const ec_slave_config_t *sc;
+    const ec_soe_request_t *req;
+
+    if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+        return -EFAULT;
+    }
+
+    if (down_interruptible(&master->master_sem))
+        return -EINTR;
+
+    if (!(sc = ec_master_get_config_const(
+                    master, data.config_index))) {
+        up(&master->master_sem);
+        EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
+                data.config_index);
+        return -EINVAL;
+    }
+
+    if (!(req = ec_slave_config_get_idn_by_pos_const(
+                    sc, data.idn_pos))) {
+        up(&master->master_sem);
+        EC_MASTER_ERR(master, "Invalid IDN position!\n");
+        return -EINVAL;
+    }
+
+    data.drive_no = req->drive_no;
+    data.idn = req->idn;
+    data.state = req->state;
+    data.size = req->data_size;
+    memcpy(&data.data, req->data,
+            min((u32) data.size, (u32) EC_MAX_IDN_DATA_SIZE));
+
+    up(&master->master_sem);
+
+    if (copy_to_user((void __user *) arg, &data, sizeof(data)))
+        return -EFAULT;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 #ifdef EC_EOE
 
 /** Get EoE handler information.
@@ -3564,6 +3615,8 @@
             return ec_cdev_ioctl_config_pdo_entry(master, arg);
         case EC_IOCTL_CONFIG_SDO:
             return ec_cdev_ioctl_config_sdo(master, arg);
+        case EC_IOCTL_CONFIG_IDN:
+            return ec_cdev_ioctl_config_idn(master, arg);
 #ifdef EC_EOE
         case EC_IOCTL_EOE_HANDLER:
             return ec_cdev_ioctl_eoe_handler(master, arg);
--- a/master/ioctl.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/master/ioctl.h	Sun Oct 24 08:43:44 2010 +0200
@@ -56,7 +56,7 @@
  *
  * Increment this when changing the ioctl interface!
  */
-#define EC_IOCTL_VERSION_MAGIC 8
+#define EC_IOCTL_VERSION_MAGIC 9
 
 // Command-line tool
 #define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
@@ -87,54 +87,55 @@
 #define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x19, ec_ioctl_config_pdo_t)
 #define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x1a, ec_ioctl_config_pdo_entry_t)
 #define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x1b, ec_ioctl_config_sdo_t)
+#define EC_IOCTL_CONFIG_IDN           EC_IOWR(0x1c, ec_ioctl_config_idn_t)
 #ifdef EC_EOE
-#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x1c, ec_ioctl_eoe_handler_t)
+#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x1d, ec_ioctl_eoe_handler_t)
 #endif
 
 // Application interface
-#define EC_IOCTL_REQUEST                EC_IO(0x1d)
-#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1e)
-#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x1f, ec_ioctl_config_t)
-#define EC_IOCTL_ACTIVATE              EC_IOR(0x20, size_t)
-#define EC_IOCTL_DEACTIVATE             EC_IO(0x21)
-#define EC_IOCTL_SEND                   EC_IO(0x22)
-#define EC_IOCTL_RECEIVE                EC_IO(0x23)
-#define EC_IOCTL_MASTER_STATE          EC_IOR(0x24, ec_master_state_t)
-#define EC_IOCTL_APP_TIME              EC_IOW(0x25, ec_ioctl_app_time_t)
-#define EC_IOCTL_SYNC_REF               EC_IO(0x26)
-#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x27)
-#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x28)
-#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x29, uint32_t)
-#define EC_IOCTL_SC_SYNC               EC_IOW(0x2a, ec_ioctl_config_t)
-#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x2b, ec_ioctl_config_t)
-#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x2c, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x2d, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x2e, ec_ioctl_add_pdo_entry_t)
-#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x2f, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x20, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_DC                 EC_IOW(0x31, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO                EC_IOW(0x32, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x33, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x34, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x35, ec_ioctl_sc_state_t)
-#define EC_IOCTL_SC_IDN                EC_IOW(0x36, ec_ioctl_sc_idn_t)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x37)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x38)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x39)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x3a, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x3b, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x3c, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x3d, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x40, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x41, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x42, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x43, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x44, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x45, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x46, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x47, size_t)
+#define EC_IOCTL_REQUEST                EC_IO(0x1e)
+#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1f)
+#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x10, ec_ioctl_config_t)
+#define EC_IOCTL_ACTIVATE              EC_IOR(0x21, size_t)
+#define EC_IOCTL_DEACTIVATE             EC_IO(0x22)
+#define EC_IOCTL_SEND                   EC_IO(0x23)
+#define EC_IOCTL_RECEIVE                EC_IO(0x24)
+#define EC_IOCTL_MASTER_STATE          EC_IOR(0x25, ec_master_state_t)
+#define EC_IOCTL_APP_TIME              EC_IOW(0x26, ec_ioctl_app_time_t)
+#define EC_IOCTL_SYNC_REF               EC_IO(0x27)
+#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x28)
+#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x29)
+#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x2a, uint32_t)
+#define EC_IOCTL_SC_SYNC               EC_IOW(0x2b, ec_ioctl_config_t)
+#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x2c, ec_ioctl_config_t)
+#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x2d, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x2e, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x2f, ec_ioctl_add_pdo_entry_t)
+#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x20, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x21, ec_ioctl_reg_pdo_entry_t)
+#define EC_IOCTL_SC_DC                 EC_IOW(0x32, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO                EC_IOW(0x33, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x34, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x35, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x36, ec_ioctl_sc_state_t)
+#define EC_IOCTL_SC_IDN                EC_IOW(0x37, ec_ioctl_sc_idn_t)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x38)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x39)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x3a)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x3b, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x3c, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x3d, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x30, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x41, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x42, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x43, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x44, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x45, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x46, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x47, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x48, size_t)
 
 /*****************************************************************************/
 
@@ -458,6 +459,7 @@
     uint16_t watchdog_divider;
     uint16_t watchdog_intervals;
     uint32_t sdo_count;
+    uint32_t idn_count;
     int32_t slave_position;
     uint16_t dc_assign_activate;
     ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT];
@@ -514,6 +516,26 @@
 
 /*****************************************************************************/
 
+/** Maximum size for displayed IDN data.
+ * \todo Make this dynamic.
+ */
+#define EC_MAX_IDN_DATA_SIZE 1024
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
+    uint32_t idn_pos;
+
+    // outputs
+    uint8_t drive_no;
+    uint16_t idn;
+    ec_al_state_t state;
+    uint32_t size;
+    uint8_t data[EC_MAX_IDN_DATA_SIZE];
+} ec_ioctl_config_idn_t;
+
+/*****************************************************************************/
+
 #ifdef EC_EOE
 
 typedef struct {
--- a/master/slave_config.c	Wed Sep 22 15:41:43 2010 +0200
+++ b/master/slave_config.c	Sun Oct 24 08:43:44 2010 +0200
@@ -371,6 +371,48 @@
 
 /*****************************************************************************/
 
+/** Get the number of IDN configurations.
+ *
+ * \return Number of SDO configurations.
+ */
+unsigned int ec_slave_config_idn_count(
+        const ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+    const ec_soe_request_t *req;
+    unsigned int count = 0;
+
+    list_for_each_entry(req, &sc->soe_configs, list) {
+        count++;
+    }
+
+    return count;
+}
+
+/*****************************************************************************/
+
+/** Finds an IDN configuration via its position in the list.
+ *
+ * Const version.
+ */
+const ec_soe_request_t *ec_slave_config_get_idn_by_pos_const(
+        const ec_slave_config_t *sc, /**< Slave configuration. */
+        unsigned int pos /**< Position in the list. */
+        )
+{
+    const ec_soe_request_t *req;
+
+    list_for_each_entry(req, &sc->soe_configs, list) {
+        if (pos--)
+            continue;
+        return req;
+    }
+
+    return NULL;
+}
+
+/*****************************************************************************/
+
 /** Finds a VoE handler via its position in the list.
  */
 ec_sdo_request_t *ec_slave_config_find_sdo_request(
@@ -951,7 +993,8 @@
             __func__, sc, drive_no, idn, state, data, size);
 
     if (drive_no > 7) {
-        EC_CONFIG_ERR(sc, "Invalid drive number!\n");
+        EC_CONFIG_ERR(sc, "Invalid drive number %u!\n",
+                (unsigned int) drive_no);
         return -EINVAL;
     }
 
--- a/master/slave_config.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/master/slave_config.h	Sun Oct 24 08:43:44 2010 +0200
@@ -160,6 +160,9 @@
 unsigned int ec_slave_config_sdo_count(const ec_slave_config_t *);
 const ec_sdo_request_t *ec_slave_config_get_sdo_by_pos_const(
         const ec_slave_config_t *, unsigned int);
+unsigned int ec_slave_config_idn_count(const ec_slave_config_t *);
+const ec_soe_request_t *ec_slave_config_get_idn_by_pos_const(
+        const ec_slave_config_t *, unsigned int);
 ec_sdo_request_t *ec_slave_config_find_sdo_request(ec_slave_config_t *,
         unsigned int);
 ec_voe_handler_t *ec_slave_config_find_voe_handler(ec_slave_config_t *,
--- a/tool/CommandConfig.cpp	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandConfig.cpp	Sun Oct 24 08:43:44 2010 +0200
@@ -153,6 +153,7 @@
     ec_ioctl_config_pdo_t pdo;
     ec_ioctl_config_pdo_entry_t entry;
     ec_ioctl_config_sdo_t sdo;
+    ec_ioctl_config_idn_t idn;
     string indent(doIndent ? "  " : "");
 
     for (configIter = configList.begin();
@@ -259,6 +260,34 @@
             cout << indent << "  None." << endl;
         }
 
+        cout << indent << "IDN configuration:" << endl;
+        if (configIter->idn_count) {
+            for (j = 0; j < configIter->idn_count; j++) {
+                m.getConfigIdn(&idn, configIter->config_index, j);
+
+                cout << indent << "  Drive " << (unsigned int) idn.drive_no
+                    << ", " << outputIdn(idn.idn)
+                    << ", " << dec << idn.size << " byte" << endl;
+
+                cout << indent << "    " << hex << setfill('0');
+                for (i = 0; i < min((uint32_t) idn.size,
+                            (uint32_t) EC_MAX_IDN_DATA_SIZE); i++) {
+                    cout << setw(2) << (unsigned int) idn.data[i];
+                    if ((i + 1) % 16 == 0 && i < idn.size - 1) {
+                        cout << endl << indent << "    ";
+                    } else {
+                        cout << " ";
+                    }
+                }
+
+                cout << endl;
+                if (idn.size > EC_MAX_IDN_DATA_SIZE) {
+                    cout << indent << "    ..." << endl;
+                }
+            }
+        } else {
+            cout << indent << "  None." << endl;
+        }
         if (configIter->dc_assign_activate) {
             int i;
 
--- a/tool/CommandConfig.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandConfig.h	Sun Oct 24 08:43:44 2010 +0200
@@ -34,11 +34,13 @@
 using namespace std;
 
 #include "Command.h"
+#include "SoeCommand.h"
 
 /****************************************************************************/
 
 class CommandConfig:
-    public Command
+    public Command,
+    public SoeCommand
 {
     public:
         CommandConfig();
--- a/tool/CommandSoeRead.cpp	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandSoeRead.cpp	Sun Oct 24 08:43:44 2010 +0200
@@ -36,7 +36,7 @@
 /*****************************************************************************/
 
 CommandSoeRead::CommandSoeRead():
-    SoeCommand("soe_read", "Read an SoE IDN from a slave.")
+    Command("soe_read", "Read an SoE IDN from a slave.")
 {
 }
 
--- a/tool/CommandSoeRead.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandSoeRead.h	Sun Oct 24 08:43:44 2010 +0200
@@ -35,6 +35,8 @@
 /****************************************************************************/
 
 class CommandSoeRead:
+    public Command,
+    public DataTypeHandler,
     public SoeCommand
 {
     public:
--- a/tool/CommandSoeWrite.cpp	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandSoeWrite.cpp	Sun Oct 24 08:43:44 2010 +0200
@@ -36,7 +36,7 @@
 /*****************************************************************************/
 
 CommandSoeWrite::CommandSoeWrite():
-    SoeCommand("soe_write", "Write an SoE IDN to a slave.")
+    Command("soe_write", "Write an SoE IDN to a slave.")
 {
 }
 
--- a/tool/CommandSoeWrite.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/CommandSoeWrite.h	Sun Oct 24 08:43:44 2010 +0200
@@ -35,6 +35,8 @@
 /****************************************************************************/
 
 class CommandSoeWrite:
+    public Command,
+    public DataTypeHandler,
     public SoeCommand
 {
     public:
--- a/tool/MasterDevice.cpp	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/MasterDevice.cpp	Sun Oct 24 08:43:44 2010 +0200
@@ -200,6 +200,24 @@
 
 /****************************************************************************/
 
+void MasterDevice::getConfigIdn(
+        ec_ioctl_config_idn_t *data,
+        unsigned int index,
+        unsigned int pos
+        )
+{
+    data->config_index = index;
+    data->idn_pos = pos;
+
+    if (ioctl(fd, EC_IOCTL_CONFIG_IDN, data) < 0) {
+        stringstream err;
+        err << "Failed to get slave config IDN: " << strerror(errno);
+        throw MasterDeviceException(err);
+    }
+}
+
+/****************************************************************************/
+
 void MasterDevice::getDomain(ec_ioctl_domain_t *data, unsigned int index)
 {
     data->index = index;
--- a/tool/MasterDevice.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/MasterDevice.h	Sun Oct 24 08:43:44 2010 +0200
@@ -116,6 +116,7 @@
         void getConfigPdoEntry(ec_ioctl_config_pdo_entry_t *, unsigned int,
                 uint8_t, uint16_t, uint8_t);
         void getConfigSdo(ec_ioctl_config_sdo_t *, unsigned int, unsigned int);
+        void getConfigIdn(ec_ioctl_config_idn_t *, unsigned int, unsigned int);
         void getDomain(ec_ioctl_domain_t *, unsigned int);
         void getFmmu(ec_ioctl_domain_fmmu_t *, unsigned int, unsigned int);
         void getData(ec_ioctl_domain_data_t *, unsigned int, unsigned int,
--- a/tool/SoeCommand.cpp	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/SoeCommand.cpp	Sun Oct 24 08:43:44 2010 +0200
@@ -36,13 +36,6 @@
 
 /*****************************************************************************/
 
-SoeCommand::SoeCommand(const string &name, const string &briefDesc):
-    Command(name, briefDesc)
-{
-}
-
-/*****************************************************************************/
-
 uint16_t SoeCommand::parseIdn(const string &str)
 {
     uint16_t idn = 0x0000;
@@ -109,6 +102,19 @@
 
 /*****************************************************************************/
 
+string SoeCommand::outputIdn(uint16_t idn)
+{
+    stringstream str;
+
+    str << ((idn & 0x8000) ? 'P' : 'S')
+        << "-" << ((idn >> 12) & 0x07)
+        << "-" << setfill('0') << setw(4) << (idn & 0x0fff);
+
+    return str.str();
+}
+
+/*****************************************************************************/
+
 /** Outputs an SoE error code.
 */
 std::string SoeCommand::errorMsg(uint16_t code)
--- a/tool/SoeCommand.h	Wed Sep 22 15:41:43 2010 +0200
+++ b/tool/SoeCommand.h	Sun Oct 24 08:43:44 2010 +0200
@@ -37,15 +37,11 @@
 
 /****************************************************************************/
 
-class SoeCommand:
-    public Command,
-    public DataTypeHandler
+class SoeCommand
 {
-    public:
-        SoeCommand(const string &, const string &);
-
     protected:
         static uint16_t parseIdn(const string &);
+        static std::string outputIdn(uint16_t);
         static std::string errorMsg(uint16_t);
 };