Added the new ethercat comman-line tool with lsec functionality.
authorFlorian Pose <fp@igh-essen.com>
Thu, 29 May 2008 15:11:26 +0000
changeset 922 fede1d8f5b71
parent 921 c8c2caf0d667
child 923 a6b51990e7e6
Added the new ethercat comman-line tool with lsec functionality.
Makefile.am
NEWS
TODO
configure.ac
master/Kbuild.in
master/Makefile.am
master/cdev.c
master/cdev.h
master/ioctl.h
master/master.c
master/master.h
master/module.c
script/init.d/ethercat
tools/Makefile.am
tools/Master.cpp
tools/Master.h
tools/main.cpp
--- a/Makefile.am	Thu May 29 09:53:10 2008 +0000
+++ b/Makefile.am	Thu May 29 15:11:26 2008 +0000
@@ -31,9 +31,20 @@
 #
 #------------------------------------------------------------------------------
 
-SUBDIRS = master devices script include
+SUBDIRS = \
+    devices \
+    include \
+    master \
+    script \
+    tools
 
-DIST_SUBDIRS = master devices script include examples
+DIST_SUBDIRS = \
+    devices \
+    examples \
+    include \
+    master \
+    script \
+    tools
 
 EXTRA_DIST = \
 	Doxyfile \
--- a/NEWS	Thu May 29 09:53:10 2008 +0000
+++ b/NEWS	Thu May 29 15:11:26 2008 +0000
@@ -49,6 +49,8 @@
     - Exported ecrt_slave_config_sdo(), the generic Sdo configuration
       function.
     - Removed the bus_state and bus_tainted flags from ec_master_state_t.
+* Replaces the Sysfs interface with a new 'ethercat' command-line tool. See
+  'ethercat --help'.
 * Removed include/ecdb.h.
 * Sdo dictionaries will now also be fetched in operation mode.
 * SII write requests will now also be processed in operation mode.
@@ -58,6 +60,7 @@
 * Network driver news:
     - Added 8139too driver for kernel 2.6.22, thanks to Erwin Burgstaller.
     - Added 8139too driver for kernel 2.6.23, thanks to Richard Hacker.
+    - Added 8139too driver for kernel 2.6.24.
     - Added e1000 driver for kernel 2.6.22.
     - Added e1000 driver for kernel 2.6.24, thanks to Matthias Luescher.
     - Added alpha support for the Reaktek r8169 chipset, thanks to Scott
--- a/TODO	Thu May 29 09:53:10 2008 +0000
+++ b/TODO	Thu May 29 15:11:26 2008 +0000
@@ -8,8 +8,7 @@
 
 Version 1.4.0:
 
-* Replace Sysfs interface with cdev and a user space program
-  to replace lsec; move a few sysfs attributes to proc.
+* Replace all Sysfs files via the new ethercat tool.
 * Remove the end state of the master state machine.
 * Supply new ec_master_state_t.
 * Implement ecrt_slave_config_state().
--- a/configure.ac	Thu May 29 09:53:10 2008 +0000
+++ b/configure.ac	Thu May 29 15:11:26 2008 +0000
@@ -19,6 +19,8 @@
 AC_DEFINE_UNQUOTED(BRANCH, ["$branch"], [Subversion branch])
 AC_SUBST(BRANCH, [$branch])
 
+AC_PROG_CXX
+
 #------------------------------------------------------------------------------
 # Linux sources
 #------------------------------------------------------------------------------
@@ -510,6 +512,7 @@
         script/Makefile
         script/init.d/Makefile
         script/sysconfig/Makefile
+        tools/Makefile
 ])
 AC_OUTPUT
 
--- a/master/Kbuild.in	Thu May 29 09:53:10 2008 +0000
+++ b/master/Kbuild.in	Thu May 29 15:11:26 2008 +0000
@@ -36,6 +36,7 @@
 obj-m := ec_master.o
 
 ec_master-objs := \
+	cdev.o \
     datagram.o \
     device.o \
     domain.o \
--- a/master/Makefile.am	Thu May 29 09:53:10 2008 +0000
+++ b/master/Makefile.am	Thu May 29 15:11:26 2008 +0000
@@ -33,6 +33,7 @@
 
 EXTRA_DIST = \
 	Kbuild.in \
+	cdev.c cdev.h \
 	datagram.c datagram.h \
 	debug.c	debug.h \
 	device.c device.h \
@@ -50,6 +51,7 @@
 	fsm_slave_config.c fsm_slave_config.h \
 	fsm_slave_scan.c fsm_slave_scan.h \
 	globals.h \
+	ioctl.h \
 	mailbox.c mailbox.h \
 	master.c master.h \
 	module.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/cdev.c	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT master character device.
+*/
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "cdev.h"
+#include "master.h"
+#include "ioctl.h"
+
+/*****************************************************************************/
+
+/** \cond */
+
+int eccdev_open(struct inode *, struct file *);
+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);
+
+/*****************************************************************************/
+
+static struct file_operations eccdev_fops = {
+    .owner   = THIS_MODULE,
+    .open    = eccdev_open,
+    .release = eccdev_release,
+    .ioctl   = eccdev_ioctl
+};
+
+/** \endcond */
+
+/*****************************************************************************/
+
+/** Constructor.
+ * 
+ * \return 0 in case of success, else < 0
+ */
+int ec_cdev_init(
+		ec_cdev_t *cdev, /**< EtherCAT master character device. */
+		ec_master_t *master, /**< Parent master. */
+		dev_t dev_num /**< Device number. */
+		)
+{
+    cdev->master = master;
+
+    cdev_init(&cdev->cdev, &eccdev_fops);
+    cdev->cdev.owner = THIS_MODULE;
+
+    if (cdev_add(&cdev->cdev,
+		 MKDEV(MAJOR(dev_num), master->index), 1)) {
+		EC_ERR("Failed to add character device!\n");
+		return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Destructor.
+ */
+void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */)
+{
+    cdev_del(&cdev->cdev);
+}
+
+/******************************************************************************
+ * File operations
+ *****************************************************************************/
+
+int eccdev_open(struct inode *inode, struct file *filp)
+{
+    ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev);
+
+    filp->private_data = cdev;
+    EC_DBG("File opened.\n");
+    return 0;
+}
+
+/*****************************************************************************/
+
+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");
+    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);
+    ec_master_t *master = cdev->master;
+
+    if (master->debug_level)
+        EC_DBG("ioctl(inode = %x, filp = %x, cmd = %u, arg = %u)\n",
+                (u32) inode, (u32) filp, (u32) cmd, (u32) arg);
+
+    switch (cmd) {
+        case EC_IOCTL_SLAVE_COUNT:
+            {
+                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;
+            }
+
+        case EC_IOCTL_SLAVE_INFO:
+            {
+                struct ec_ioctl_slave_info *infos, *info;
+                unsigned int slave_count = master->slave_count;
+                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;
+            }
+
+        default:
+            return -ENOIOCTLCMD;
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/cdev.h	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT master character device.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_CDEV_H__
+#define __EC_CDEV_H__
+
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#include "globals.h"
+#include "../include/ecrt.h"
+
+/*****************************************************************************/
+
+/** EtherCAT master character device.
+*/
+typedef struct {
+    ec_master_t *master; /**< Master owning the device. */
+    struct cdev cdev; /**< Character device. */
+} ec_cdev_t;
+
+/*****************************************************************************/
+
+int ec_cdev_init(ec_cdev_t *, ec_master_t *, dev_t);
+void ec_cdev_clear(ec_cdev_t *);
+
+int ec_cdev_request(ec_cdev_t *, uint32_t, uint32_t);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/ioctl.h	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT master character device IOCTL commands.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_IOCTL_H__
+#define __EC_IOCTL_H__
+
+/*****************************************************************************/
+
+enum {
+    EC_IOCTL_SLAVE_COUNT = 0,
+    EC_IOCTL_SLAVE_INFO,
+};
+
+/*****************************************************************************/
+
+#define EC_IOCTL_SLAVE_INFO_DESC_SIZE 243
+
+struct ec_ioctl_slave_info {
+    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];
+};
+
+/*****************************************************************************/
+
+#endif
--- a/master/master.c	Thu May 29 09:53:10 2008 +0000
+++ b/master/master.c	Thu May 29 15:11:26 2008 +0000
@@ -105,7 +105,8 @@
         struct kobject *module_kobj, /**< kobject of the master module */
         unsigned int index, /**< master index */
         const uint8_t *main_mac, /**< MAC address of main device */
-        const uint8_t *backup_mac /**< MAC address of backup device */
+        const uint8_t *backup_mac, /**< MAC address of backup device */
+        dev_t device_number /**< Character device number. */
         )
 {
     unsigned int i;
@@ -178,9 +179,13 @@
     init_MUTEX(&master->sdo_sem);
     init_waitqueue_head(&master->sdo_queue);
 
+    // init character device
+    if (ec_cdev_init(&master->cdev, master, device_number))
+        goto out_return;
+
     // init devices
     if (ec_device_init(&master->main_device, master))
-        goto out_return;
+        goto out_cdev;
 
     if (ec_device_init(&master->backup_device, master))
         goto out_clear_main;
@@ -222,6 +227,8 @@
     ec_device_clear(&master->backup_device);
 out_clear_main:
     ec_device_clear(&master->main_device);
+out_cdev:
+    ec_cdev_clear(&master->cdev);
 out_return:
     return -1;
 }
@@ -248,6 +255,7 @@
     ec_datagram_clear(&master->fsm_datagram);
     ec_device_clear(&master->backup_device);
     ec_device_clear(&master->main_device);
+    ec_cdev_clear(&master->cdev);
 
     // destroy self
     kobject_del(&master->kobj);
--- a/master/master.h	Thu May 29 09:53:10 2008 +0000
+++ b/master/master.h	Thu May 29 15:11:26 2008 +0000
@@ -50,6 +50,7 @@
 #include "device.h"
 #include "domain.h"
 #include "fsm_master.h"
+#include "cdev.h"
 
 /*****************************************************************************/
 
@@ -84,6 +85,8 @@
     unsigned int index; /**< master index */
     unsigned int reserved; /**< non-zero, if the master is reserved for RT */
 
+    ec_cdev_t cdev; /**< Master character device. */
+
     ec_device_t main_device; /**< EtherCAT device */
     const uint8_t *main_mac; /**< MAC address of main device */
     ec_device_t backup_device; /**< EtherCAT backup device */
@@ -166,7 +169,7 @@
 
 // master creation/deletion
 int ec_master_init(ec_master_t *, struct kobject *, unsigned int,
-        const uint8_t *, const uint8_t *);
+        const uint8_t *, const uint8_t *, dev_t);
 void ec_master_clear(ec_master_t *);
 
 // mode transitions
--- a/master/module.c	Thu May 29 09:53:10 2008 +0000
+++ b/master/module.c	Thu May 29 15:11:26 2008 +0000
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 
 #include "globals.h"
 #include "master.h"
@@ -68,6 +69,8 @@
 static unsigned int master_count; /**< Number of masters. */
 static unsigned int backup_count; /**< Number of backup devices. */
 
+static dev_t device_number; /**< Device number for cdevs. */
+
 static uint8_t macs[MAX_MASTERS][2][ETH_ALEN]; /**< MAC addresses. */
 
 char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */
@@ -92,7 +95,7 @@
 
 /** Module initialization.
  *
- * Initializes \a ec_master_count masters.
+ * Initializes \a master_count masters.
  * \return 0 on success, else < 0
  */
 int __init ec_init_module(void)
@@ -119,6 +122,12 @@
         goto out_put;
     }
     
+    if (alloc_chrdev_region(&device_number, 0, master_count, "EtherCAT")) {
+        EC_ERR("Failed to obtain device number(s)!\n");
+        ret = -EBUSY;
+        goto out_del;
+    }
+
     // zero MAC addresses
     memset(macs, 0x00, sizeof(uint8_t) * MAX_MASTERS * 2 * ETH_ALEN);
 
@@ -126,12 +135,12 @@
     for (i = 0; i < master_count; i++) {
         if (ec_mac_parse(macs[i][0], main_devices[i], 0)) {
             ret = -EINVAL;
-            goto out_del;
+            goto out_cdev;
         }
         
         if (i < backup_count && ec_mac_parse(macs[i][1], backup_devices[i], 1)) {
             ret = -EINVAL;
-            goto out_del;
+            goto out_cdev;
         }
     }
     
@@ -140,12 +149,13 @@
                         GFP_KERNEL))) {
             EC_ERR("Failed to allocate memory for EtherCAT masters.\n");
             ret = -ENOMEM;
-            goto out_del;
+            goto out_cdev;
         }
     }
     
     for (i = 0; i < master_count; i++) {
-        if (ec_master_init(&masters[i], &kobj, i, macs[i][0], macs[i][1])) {
+        if (ec_master_init(&masters[i], &kobj, i, macs[i][0], macs[i][1],
+                device_number)) {
             ret = -EIO;
             goto out_free_masters;
         }
@@ -158,6 +168,8 @@
 out_free_masters:
     for (i--; i >= 0; i--) ec_master_clear(&masters[i]);
     kfree(masters);
+out_cdev:
+    unregister_chrdev_region(device_number, master_count);
 out_del:
     kobject_del(&kobj);
 out_put:
@@ -180,6 +192,8 @@
     }
     if (master_count)
         kfree(masters);
+
+    unregister_chrdev_region(device_number, master_count);
     
     kobject_del(&kobj);
     kobject_put(&kobj);
--- a/script/init.d/ethercat	Thu May 29 09:53:10 2008 +0000
+++ b/script/init.d/ethercat	Thu May 29 15:11:26 2008 +0000
@@ -49,6 +49,7 @@
 
 #------------------------------------------------------------------------------
 
+CDEV='EtherCAT'
 MODPROBE=/sbin/modprobe
 RMMOD=/sbin/rmmod
 MODINFO=/sbin/modinfo
@@ -172,6 +173,7 @@
 
         MASTER_INDEX=$(expr ${MASTER_INDEX} + 1)
     done
+    MASTER_INDICES=`seq 0 $((${MASTER_INDEX} - 1))`
 
     # load master module
     if ! ${MODPROBE} ${MODPROBE_FLAGS} ec_master \
@@ -179,6 +181,17 @@
         exit_fail
     fi
 
+    # remove stale device nodes
+    rm -f /dev/${CDEV}*
+
+    # get dynamic major number
+    MAJOR=$(awk "\$2==\"EtherCAT\" {print \$1}" /proc/devices)
+
+    # create character devices
+    for i in ${MASTER_INDICES}; do
+        mknod /dev/${CDEV}${i} c ${MAJOR} ${i}
+    done
+
     # check for modules to replace
     for MODULE in ${DEVICE_MODULES}; do
         ECMODULE=ec_${MODULE}
@@ -213,6 +226,9 @@
         fi;
     done
 
+    # remove device nodes
+    rm -f /dev/${CDEV}*
+
     sleep 1
 
     # reload previous modules
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/Makefile.am	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,42 @@
+#------------------------------------------------------------------------------
+#
+#  $Id$
+#
+#  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+#
+#  This file is part of the IgH EtherCAT Master.
+#
+#  The IgH EtherCAT Master is free software; you can redistribute it
+#  and/or modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2 of the
+#  License, or (at your option) any later version.
+#
+#  The IgH EtherCAT Master is distributed in the hope that it will be
+#  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with the IgH EtherCAT Master; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#  The right to use EtherCAT Technology is granted and comes free of
+#  charge under condition of compatibility of product made by
+#  Licensee. People intending to distribute/sell products based on the
+#  code, have to sign an agreement to guarantee that products using
+#  software based on IgH EtherCAT master stay compatible with the actual
+#  EtherCAT specification (which are released themselves as an open
+#  standard) as the (only) precondition to have the right to use EtherCAT
+#  Technology, IP and trade marks.
+#
+#------------------------------------------------------------------------------
+
+bin_PROGRAMS = ethercat
+
+ethercat_SOURCES = \
+    Master.cpp Master.h \
+    main.cpp
+
+ethercat_CFLAGS = -I../master
+
+#------------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/Master.cpp	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,140 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+using namespace std;
+
+#include "Master.h"
+#include "../master/ioctl.h"
+
+/****************************************************************************/
+
+Master::Master()
+{
+    index = 0;
+    fd = -1;
+}
+
+/****************************************************************************/
+
+Master::~Master()
+{
+    close();
+}
+
+/****************************************************************************/
+
+void Master::open(unsigned int index)
+{
+    stringstream deviceName;
+    
+    Master::index = index;
+
+    deviceName << "/dev/EtherCAT" << index;
+    
+    if ((fd = ::open(deviceName.str().c_str(), O_RDONLY)) == -1) {
+        stringstream err;
+        err << "Failed to open master device " << deviceName.str() << ": "
+            << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
+void Master::close()
+{
+    if (fd == -1)
+        return;
+
+    ::close(fd);
+}
+
+/****************************************************************************/
+
+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;
+    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;
+            aliasIndex = 0;
+        }
+        if (lastAlias) {
+            cout << setw(10) << "#" << lastAlias << ":" << aliasIndex;
+        }
+
+        cout << "  " << slaveState(info->state) << "  ";
+
+        if (strlen(info->description)) {
+            cout << info->description;
+        } else {
+            cout << "0x" << hex << setfill('0') << info->vendor_id
+                << ":0x" << info->product_code;
+        }
+
+        cout << endl;
+    }
+
+    delete [] infos;
+}
+
+/****************************************************************************/
+
+string Master::slaveState(uint8_t state) const
+{
+    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/tools/Master.h	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#ifndef __EC_MASTER_H__
+#define __EC_MASTER_H__
+
+#include <stdexcept>
+using namespace std;
+
+/****************************************************************************/
+
+class MasterException:
+    public runtime_error
+{
+    public:
+        /** Constructor with std::string parameter. */
+        MasterException(
+                const string &s /**< Message. */
+                ): runtime_error(s) {}
+
+        /** Constructor with const char pointer parameter. */
+        MasterException(
+                const char *s /**< Message. */
+                ): runtime_error(s) {}
+};
+
+/****************************************************************************/
+
+class Master
+{
+    public:
+        Master();
+        ~Master();
+
+        void open(unsigned int);
+        void close();
+
+        unsigned int slaveCount();
+        void listSlaves();
+
+    protected:
+        string slaveState(uint8_t) const;
+        
+    private:
+        unsigned int index;
+        int fd;
+};
+
+/****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/main.cpp	Thu May 29 15:11:26 2008 +0000
@@ -0,0 +1,117 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ ****************************************************************************/
+
+#include <getopt.h>
+
+#include <iostream>
+#include <string>
+using namespace std;
+
+#include "Master.h"
+
+/*****************************************************************************/
+
+#define DEFAULT_MASTER 0
+#define DEFAULT_COMMAND "slaves"
+#define DEFAULT_SLAVESPEC ""
+
+static unsigned int masterIndex = DEFAULT_MASTER;
+static string slaveSpec = DEFAULT_SLAVESPEC;
+static string command = DEFAULT_COMMAND;
+
+/*****************************************************************************/
+
+void printUsage()
+{
+    cerr
+        << "Usage: ethercat <COMMAND> [OPTIONS]" << endl
+		<< "Commands:" << endl
+        << "  list (ls, slaves)  List all slaves (former 'lsec')." << endl
+		<< "Global options:" << endl
+        << "  --master  -m <master>  Index of the master to use. Default: "
+		<< DEFAULT_MASTER	<< endl
+        << "  --slave   -s <slave>   Slave specification. Default: All "
+        "slaves." << endl
+        << "  --help    -h           Show this help." << endl;
+}
+
+/*****************************************************************************/
+
+void getOptions(int argc, char **argv)
+{
+    int c, argCount, optionIndex, number;
+	char *remainder;
+
+    static struct option longOptions[] = {
+        //name,    has_arg,           flag, val
+        {"master", required_argument, NULL, 'm'},
+        {"slave",  required_argument, NULL, 's'},
+        {"help",   no_argument,       NULL, 'h'},
+        {}
+    };
+
+    do {
+        c = getopt_long(argc, argv, "m:s:h", longOptions, &optionIndex);
+
+        switch (c) {
+            case 'm':
+                number = strtoul(optarg, &remainder, 0);
+                if (remainder == optarg || *remainder || number < 0) {
+                    cerr << "Invalid master number " << optarg << "!" << endl;
+                    printUsage();
+                    exit(1);
+                }
+				masterIndex = number;
+                break;
+
+            case 's':
+				slaveSpec = optarg;
+                break;
+
+            case 'h':
+            case '?':
+                printUsage();
+                exit(0);
+
+            default:
+                break;
+        }
+    }
+    while (c != -1);
+
+	argCount = argc - optind;
+
+	if (!argCount) {
+        cerr << "Please specify a command!" << endl;
+		printUsage();
+        exit(1);
+	}
+
+    command = argv[optind];
+}
+
+/****************************************************************************/
+
+int main(int argc, char **argv)
+{
+    Master master;
+    
+	getOptions(argc, argv);
+
+    master.open(masterIndex);
+
+    if (command == "list" || command == "ls" || command == "slaves") {
+        master.listSlaves();
+    } else {
+        cerr << "Unknown command " << command << "!" << endl;
+        printUsage();
+        exit(1);
+    }
+
+	return 0;
+}
+
+/****************************************************************************/