Added 'pdos' command to ethercat tool.
authorFlorian Pose <fp@igh-essen.com>
Mon, 02 Jun 2008 10:51:31 +0000
changeset 935 b954e9d91ea5
parent 934 96241b092fac
child 936 30fddfce8db6
Added 'pdos' command to ethercat tool.
master/cdev.c
master/ioctl.h
tools/Master.cpp
tools/Master.h
tools/main.cpp
--- a/master/cdev.c	Mon Jun 02 10:49:44 2008 +0000
+++ b/master/cdev.c	Mon Jun 02 10:51:31 2008 +0000
@@ -52,15 +52,15 @@
 int eccdev_release(struct inode *, struct file *);
 ssize_t eccdev_read(struct file *, char __user *, size_t, loff_t *);
 ssize_t eccdev_write(struct file *, const char __user *, size_t, loff_t *);
-int eccdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+long eccdev_ioctl(struct file *, unsigned int, unsigned long);
 
 /*****************************************************************************/
 
 static struct file_operations eccdev_fops = {
-    .owner   = THIS_MODULE,
-    .open    = eccdev_open,
-    .release = eccdev_release,
-    .ioctl   = eccdev_ioctl
+    .owner          = THIS_MODULE,
+    .open           = eccdev_open,
+    .release        = eccdev_release,
+    .unlocked_ioctl = eccdev_ioctl
 };
 
 /** \endcond */
@@ -107,9 +107,11 @@
 int eccdev_open(struct inode *inode, struct file *filp)
 {
     ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev);
+    ec_master_t *master = cdev->master;
 
     filp->private_data = cdev;
-    EC_DBG("File opened.\n");
+    if (master->debug_level)
+        EC_DBG("File opened.\n");
     return 0;
 }
 
@@ -117,88 +119,237 @@
 
 int eccdev_release(struct inode *inode, struct file *filp)
 {
-    //ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev);
-
-    EC_DBG("File closed.\n");
+    ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data;
+    ec_master_t *master = cdev->master;
+
+    if (master->debug_level)
+        EC_DBG("File closed.\n");
     return 0;
 }
 
 /*****************************************************************************/
 
-int eccdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-        unsigned long arg)
-{
-    ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev);
+long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data;
     ec_master_t *master = cdev->master;
+    long retval = 0;
 
     if (master->debug_level)
-        EC_DBG("ioctl(inode = %x, filp = %x, cmd = %u, arg = %u)\n",
-                (u32) inode, (u32) filp, (u32) cmd, (u32) arg);
-
+        EC_DBG("ioctl(filp = %x, cmd = %u, arg = %u)\n",
+                (u32) filp, (u32) cmd, (u32) arg);
+
+    // FIXME lock
+    
     switch (cmd) {
         case EC_IOCTL_SLAVE_COUNT:
+            retval = master->slave_count;
+            break;
+
+        case EC_IOCTL_SLAVE:
             {
-                unsigned int slave_count = master->slave_count;
-                EC_INFO("EC_IOCTL_SLAVE_COUNT\n");
-                if (!arg)
-                    return -EFAULT;
-                if (copy_to_user((void __user *) arg, &slave_count,
-                            sizeof(unsigned int)))
-                    return -EFAULT;
-                return 0;
+                ec_ioctl_slave_t data;
+                const ec_slave_t *slave;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+
+                if (!(slave = ec_master_find_slave(
+                                master, 0, data.position))) {
+                    EC_ERR("Slave %u does not exist!\n", data.position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.vendor_id = slave->sii.vendor_id;
+                data.product_code = slave->sii.product_code;
+                data.alias = slave->sii.alias;
+                data.state = slave->current_state;
+
+                data.sync_count = slave->sii.sync_count;
+
+                if (slave->sii.name) {
+                    strncpy(data.name, slave->sii.name,
+                            EC_IOCTL_SLAVE_NAME_SIZE);
+                    data.name[EC_IOCTL_SLAVE_NAME_SIZE - 1] = 0;
+                } else {
+                    data.name[0] = 0;
+                }
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+
+                break;
             }
 
-        case EC_IOCTL_SLAVE_INFO:
+        case EC_IOCTL_SYNC:
             {
-                struct ec_ioctl_slave_info *infos, *info;
-                unsigned int slave_count = master->slave_count;
+                ec_ioctl_sync_t data;
                 const ec_slave_t *slave;
-                unsigned int i = 0;
-
-                if (master->debug_level)
-                    EC_DBG("EC_IOCTL_SLAVE_INFOS\n");
-
-                if (!slave_count)
-                    return 0;
-
-                if (!arg)
-                    return -EFAULT;
-
-                if (!(infos = kmalloc(slave_count *
-                                sizeof(struct ec_ioctl_slave_info),
-                                GFP_KERNEL)))
-                    return -ENOMEM;
-
-                list_for_each_entry(slave, &master->slaves, list) {
-                    info = &infos[i++];
-                    info->vendor_id = slave->sii.vendor_id;
-                    info->product_code = slave->sii.product_code;
-                    info->alias = slave->sii.alias;
-                    info->ring_position = slave->ring_position;
-                    info->state = slave->current_state;
-                    if (slave->sii.name) {
-                        strncpy(info->description, slave->sii.name,
-                                EC_IOCTL_SLAVE_INFO_DESC_SIZE);
-                        info->description[EC_IOCTL_SLAVE_INFO_DESC_SIZE - 1]
-                            = 0;
-                    } else {
-                        info->description[0] = 0;
-                    }
-                }
-
-                if (copy_to_user((void __user *) arg, infos, slave_count *
-                            sizeof(struct ec_ioctl_slave_info))) {
-                    kfree(infos);
-                    return -EFAULT;
-                }
-
-                kfree(infos);
-                return 0;
+                const ec_sync_t *sync;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(slave = ec_master_find_slave(
+                                master, 0, data.slave_position))) {
+                    EC_ERR("Slave %u does not exist!\n", data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (data.sync_index >= slave->sii.sync_count) {
+                    EC_ERR("Sync manager %u does not exist in slave %u!\n",
+                            data.sync_index, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                sync = &slave->sii.syncs[data.sync_index];
+
+                data.physical_start_address = sync->physical_start_address;
+                data.default_size = sync->length;
+                data.control_register = sync->control_register;
+                data.enable = sync->enable;
+                data.assign_source = sync->assign_source;
+                data.pdo_count = ec_pdo_list_count(&sync->pdos);
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
             }
 
+        case EC_IOCTL_PDO:
+            {
+                ec_ioctl_pdo_t data;
+                const ec_slave_t *slave;
+                const ec_sync_t *sync;
+                const ec_pdo_t *pdo;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(slave = ec_master_find_slave(
+                                master, 0, data.slave_position))) {
+                    EC_ERR("Slave %u does not exist!\n", data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (data.sync_index >= slave->sii.sync_count) {
+                    EC_ERR("Sync manager %u does not exist in slave %u!\n",
+                            data.sync_index, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                sync = &slave->sii.syncs[data.sync_index];
+                if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
+                                &sync->pdos, data.pdo_pos))) {
+                    EC_ERR("Sync manager %u does not contain a Pdo with "
+                            "position %u in slave %u!\n", data.sync_index,
+                            data.pdo_pos, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.dir = pdo->dir;
+                data.index = pdo->index;
+                data.entry_count = ec_pdo_entry_count(pdo);
+
+                if (pdo->name) {
+                    strncpy(data.name, pdo->name, EC_IOCTL_PDO_NAME_SIZE);
+                    data.name[EC_IOCTL_PDO_NAME_SIZE - 1] = 0;
+                } else {
+                    data.name[0] = 0;
+                }
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
+        case EC_IOCTL_PDO_ENTRY:
+            {
+                ec_ioctl_pdo_entry_t data;
+                const ec_slave_t *slave;
+                const ec_sync_t *sync;
+                const ec_pdo_t *pdo;
+                const ec_pdo_entry_t *entry;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(slave = ec_master_find_slave(
+                                master, 0, data.slave_position))) {
+                    EC_ERR("Slave %u does not exist!\n", data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (data.sync_index >= slave->sii.sync_count) {
+                    EC_ERR("Sync manager %u does not exist in slave %u!\n",
+                            data.sync_index, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                sync = &slave->sii.syncs[data.sync_index];
+                if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
+                                &sync->pdos, data.pdo_pos))) {
+                    EC_ERR("Sync manager %u does not contain a Pdo with "
+                            "position %u in slave %u!\n", data.sync_index,
+                            data.pdo_pos, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (!(entry = ec_pdo_find_entry_by_pos_const(
+                                pdo, data.entry_pos))) {
+                    EC_ERR("Pdo 0x%04X does not contain an entry with "
+                            "position %u in slave %u!\n", data.pdo_pos,
+                            data.entry_pos, data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                data.index = entry->index;
+                data.subindex = entry->subindex;
+                data.bit_length = entry->bit_length;
+                if (entry->name) {
+                    strncpy(data.name, entry->name,
+                            EC_IOCTL_PDO_ENTRY_NAME_SIZE);
+                    data.name[EC_IOCTL_PDO_ENTRY_NAME_SIZE - 1] = 0;
+                } else {
+                    data.name[0] = 0;
+                }
+
+                if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                break;
+            }
+
         default:
-            return -ENOIOCTLCMD;
+            retval = -ENOIOCTLCMD;
     }
-}
-
-/*****************************************************************************/
+
+    return retval;
+}
+
+/*****************************************************************************/
--- a/master/ioctl.h	Mon Jun 02 10:49:44 2008 +0000
+++ b/master/ioctl.h	Mon Jun 02 10:51:31 2008 +0000
@@ -44,22 +44,80 @@
 /*****************************************************************************/
 
 enum {
-    EC_IOCTL_SLAVE_COUNT = 0,
-    EC_IOCTL_SLAVE_INFO,
+    EC_IOCTL_SLAVE_COUNT,
+    EC_IOCTL_SLAVE,
+    EC_IOCTL_SYNC,
+    EC_IOCTL_PDO,
+    EC_IOCTL_PDO_ENTRY,
 };
 
 /*****************************************************************************/
 
-#define EC_IOCTL_SLAVE_INFO_DESC_SIZE 243
+#define EC_IOCTL_SLAVE_NAME_SIZE 114
 
-struct ec_ioctl_slave_info {
+typedef struct {
+    // input
+    uint16_t position;
+
+    // outputs
     uint32_t vendor_id;
     uint32_t product_code;
     uint16_t alias;
-    uint16_t ring_position;
     uint8_t state;
-    char description[EC_IOCTL_SLAVE_INFO_DESC_SIZE];
-};
+    uint8_t sync_count;
+    char name[EC_IOCTL_SLAVE_NAME_SIZE];
+} ec_ioctl_slave_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint16_t slave_position;
+    unsigned int sync_index;
+
+    // outputs
+    uint16_t physical_start_address;
+    uint16_t default_size;
+    uint8_t control_register;
+    uint8_t enable;
+    uint8_t assign_source;
+    uint8_t pdo_count;
+} ec_ioctl_sync_t;
+
+/*****************************************************************************/
+
+#define EC_IOCTL_PDO_NAME_SIZE 114
+
+typedef struct {
+    // inputs
+    uint16_t slave_position;
+    unsigned int sync_index;
+    unsigned int pdo_pos;
+
+    // outputs
+    uint8_t dir;
+    uint16_t index;
+    uint8_t entry_count;
+    char name[EC_IOCTL_PDO_NAME_SIZE];
+} ec_ioctl_pdo_t;
+
+/*****************************************************************************/
+
+#define EC_IOCTL_PDO_ENTRY_NAME_SIZE 110
+
+typedef struct {
+    // inputs
+    uint16_t slave_position;
+    unsigned int sync_index;
+    unsigned int pdo_pos;
+    unsigned int entry_pos;
+
+    // outputs
+    uint16_t index;
+    uint8_t subindex;
+    uint8_t bit_length;
+    char name[EC_IOCTL_PDO_NAME_SIZE];
+} ec_ioctl_pdo_entry_t;
 
 /*****************************************************************************/
 
--- a/tools/Master.cpp	Mon Jun 02 10:49:44 2008 +0000
+++ b/tools/Master.cpp	Mon Jun 02 10:51:31 2008 +0000
@@ -16,7 +16,6 @@
 using namespace std;
 
 #include "Master.h"
-#include "../master/ioctl.h"
 
 /****************************************************************************/
 
@@ -63,70 +62,205 @@
 
 /****************************************************************************/
 
-unsigned int Master::slaveCount()
-{
-    unsigned int numSlaves;
-
-    if (ioctl(fd, EC_IOCTL_SLAVE_COUNT, &numSlaves)) {
-        stringstream err;
-        err << "Failed to get number of slaves: " << strerror(errno);
-        throw MasterException(err.str());
-    }
-
-    return numSlaves;
-}
-
-/****************************************************************************/
-
 void Master::listSlaves()
 {
     unsigned int numSlaves = slaveCount(), i;
-    struct ec_ioctl_slave_info *infos, *info;
+    ec_ioctl_slave_t slave;
     uint16_t lastAlias, aliasIndex;
     
-    if (!numSlaves)
-        return;
-    
-    infos = new struct ec_ioctl_slave_info[numSlaves];
-
-    if (ioctl(fd, EC_IOCTL_SLAVE_INFO, infos)) {
-        stringstream err;
-        err << "Failed to get slave information: " << strerror(errno);
-        throw MasterException(err.str());
-    }
-
     lastAlias = 0;
     aliasIndex = 0;
     for (i = 0; i < numSlaves; i++) {
-        info = &infos[i];
-        cout << setw(2) << info->ring_position << "  ";
-
-        if (info->alias) {
-            lastAlias = info->alias;
+        getSlave(&slave, i);
+        cout << setw(2) << i << "  ";
+
+        if (slave.alias) {
+            lastAlias = slave.alias;
             aliasIndex = 0;
         }
         if (lastAlias) {
             cout << setw(10) << "#" << lastAlias << ":" << aliasIndex;
         }
 
-        cout << "  " << slaveState(info->state) << "  ";
-
-        if (strlen(info->description)) {
-            cout << info->description;
+        cout << "  " << slaveState(slave.state) << "  ";
+
+        if (strlen(slave.name)) {
+            cout << slave.name;
         } else {
-            cout << "0x" << hex << setfill('0') << info->vendor_id
-                << ":0x" << info->product_code;
+            cout << "0x" << hex << setfill('0') << slave.vendor_id
+                << ":0x" << slave.product_code;
         }
 
         cout << endl;
     }
-
-    delete [] infos;
-}
-
-/****************************************************************************/
-
-string Master::slaveState(uint8_t state) const
+}
+
+/****************************************************************************/
+
+void Master::listPdos(int slavePosition)
+{
+    ec_ioctl_slave_t slave;
+    ec_ioctl_sync_t sync;
+    ec_ioctl_pdo_t pdo;
+    ec_ioctl_pdo_entry_t entry;
+    unsigned int i, j, k;
+    
+    getSlave(&slave, slavePosition);
+
+    for (i = 0; i < slave.sync_count; i++) {
+        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++) {
+            getPdo(&pdo, slavePosition, i, j);
+
+            cout << "  " << (pdo.dir ? "T" : "R") << "xPdo 0x"
+                << hex << setfill('0') << setw(4) << pdo.index
+                << " \"" << pdo.name << "\"" << endl;
+
+            for (k = 0; k < pdo.entry_count; k++) {
+                getPdoEntry(&entry, slavePosition, i, j, k);
+
+                cout << "    Pdo entry 0x"
+                    << hex << setfill('0') << setw(4) << entry.index
+                    << ":" << hex << setfill('0') << setw(2)
+                    << (unsigned int) entry.subindex
+                    << ", " << dec << (unsigned int) entry.bit_length
+                    << " bit, \"" << entry.name << "\"" << endl;
+            }
+        }
+    }
+}
+
+/****************************************************************************/
+
+unsigned int Master::slaveCount()
+{
+    int ret;
+
+    if ((ret = ioctl(fd, EC_IOCTL_SLAVE_COUNT, 0)) < 0) {
+        stringstream err;
+        err << "Failed to get slave: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+
+    return ret;
+}
+
+/****************************************************************************/
+
+void Master::getSlave(ec_ioctl_slave_t *slave, uint16_t slaveIndex)
+{
+    slave->position = slaveIndex;
+
+    if (ioctl(fd, EC_IOCTL_SLAVE, slave)) {
+        stringstream err;
+        err << "Failed to get slave: ";
+        if (errno == EINVAL)
+            err << "Slave " << slaveIndex << " does not exist!";
+        else
+            err << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getSync(
+        ec_ioctl_sync_t *sync,
+        uint16_t slaveIndex,
+        uint8_t syncIndex
+        )
+{
+    sync->slave_position = slaveIndex;
+    sync->sync_index = syncIndex;
+
+    if (ioctl(fd, EC_IOCTL_SYNC, sync)) {
+        stringstream err;
+        err << "Failed to get sync manager: ";
+        if (errno == EINVAL)
+            err << "Either slave " << slaveIndex << " does not exist, "
+                << "or contains less than " << (unsigned int) syncIndex + 1
+                << " sync managers!";
+        else
+            err << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getPdo(
+        ec_ioctl_pdo_t *pdo,
+        uint16_t slaveIndex,
+        uint8_t syncIndex,
+        uint8_t pdoPos
+        )
+{
+    pdo->slave_position = slaveIndex;
+    pdo->sync_index = syncIndex;
+    pdo->pdo_pos = pdoPos;
+
+    if (ioctl(fd, EC_IOCTL_PDO, pdo)) {
+        stringstream err;
+        err << "Failed to get Pdo: ";
+        if (errno == EINVAL)
+            err << "Either slave " << slaveIndex << " does not exist, "
+                << "or contains less than " << (unsigned int) syncIndex + 1
+                << " sync managers, or sync manager "
+                << (unsigned int) syncIndex << " contains less than "
+                << pdoPos + 1 << " Pdos!" << endl;
+        else
+            err << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::getPdoEntry(
+        ec_ioctl_pdo_entry_t *entry,
+        uint16_t slaveIndex,
+        uint8_t syncIndex,
+        uint8_t pdoPos,
+        uint8_t entryPos
+        )
+{
+    entry->slave_position = slaveIndex;
+    entry->sync_index = syncIndex;
+    entry->pdo_pos = pdoPos;
+    entry->entry_pos = entryPos;
+
+    if (ioctl(fd, EC_IOCTL_PDO_ENTRY, entry)) {
+        stringstream err;
+        err << "Failed to get Pdo entry: ";
+        if (errno == EINVAL)
+            err << "Either slave " << slaveIndex << " does not exist, "
+                << "or contains less than " << (unsigned int) syncIndex + 1
+                << " sync managers, or sync manager "
+                << (unsigned int) syncIndex << " contains less than "
+                << pdoPos + 1 << " Pdos, or the Pdo at position " << pdoPos
+                << " contains less than " << (unsigned int) entryPos + 1
+                << " entries!" << endl;
+        else
+            err << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+string Master::slaveState(uint8_t state)
 {
     switch (state) {
         case 1: return "INIT";
--- a/tools/Master.h	Mon Jun 02 10:49:44 2008 +0000
+++ b/tools/Master.h	Mon Jun 02 10:51:31 2008 +0000
@@ -10,6 +10,8 @@
 #include <stdexcept>
 using namespace std;
 
+#include "../master/ioctl.h"
+
 /****************************************************************************/
 
 class MasterException:
@@ -38,11 +40,19 @@
         void open(unsigned int);
         void close();
 
-        unsigned int slaveCount();
         void listSlaves();
+        void listPdos(int);
 
     protected:
-        string slaveState(uint8_t) const;
+        unsigned int slaveCount();
+        void slaveSyncs(uint16_t);
+        void getSlave(ec_ioctl_slave_t *, uint16_t);
+        void getSync(ec_ioctl_sync_t *, uint16_t, uint8_t);
+        void getPdo(ec_ioctl_pdo_t *, uint16_t, uint8_t, uint8_t);
+        void getPdoEntry(ec_ioctl_pdo_entry_t *, uint16_t, uint8_t, uint8_t,
+                uint8_t);
+
+        static string slaveState(uint8_t);
         
     private:
         unsigned int index;
--- a/tools/main.cpp	Mon Jun 02 10:49:44 2008 +0000
+++ b/tools/main.cpp	Mon Jun 02 10:51:31 2008 +0000
@@ -19,7 +19,7 @@
 #define DEFAULT_SLAVESPEC ""
 
 static unsigned int masterIndex = DEFAULT_MASTER;
-static string slaveSpec = DEFAULT_SLAVESPEC;
+static int slavePosition = -1;
 static string command = DEFAULT_COMMAND;
 
 /*****************************************************************************/
@@ -30,10 +30,11 @@
         << "Usage: ethercat <COMMAND> [OPTIONS]" << endl
 		<< "Commands:" << endl
         << "  list (ls, slaves)  List all slaves (former 'lsec')." << endl
+        << "  pdos               List Pdo mapping of given slaves." << endl
 		<< "Global options:" << endl
         << "  --master  -m <master>  Index of the master to use. Default: "
 		<< DEFAULT_MASTER	<< endl
-        << "  --slave   -s <slave>   Slave specification. Default: All "
+        << "  --slave   -s <slave>   Numerical ring position. Default: All "
         "slaves." << endl
         << "  --help    -h           Show this help." << endl;
 }
@@ -68,7 +69,14 @@
                 break;
 
             case 's':
-				slaveSpec = optarg;
+                number = strtoul(optarg, &remainder, 0);
+                if (remainder == optarg || *remainder
+                        || number < 0 || number > 0xFFFF) {
+                    cerr << "Invalid slave position " << optarg << "!" << endl;
+                    printUsage();
+                    exit(1);
+                }
+				slavePosition = number;
                 break;
 
             case 'h':
@@ -101,13 +109,21 @@
     
 	getOptions(argc, argv);
 
-    master.open(masterIndex);
+    try {
+        master.open(masterIndex);
 
-    if (command == "list" || command == "ls" || command == "slaves") {
-        master.listSlaves();
-    } else {
-        cerr << "Unknown command " << command << "!" << endl;
-        printUsage();
+        if (command == "list" || command == "ls" || command == "slaves") {
+            master.listSlaves();
+
+        } else if (command == "pdos") {
+            master.listPdos(slavePosition);
+        } else {
+            cerr << "Unknown command " << command << "!" << endl;
+            printUsage();
+            exit(1);
+        }
+    } catch (MasterException &e) {
+        cerr << e.what() << endl;
         exit(1);
     }