ethercat eoe command.
authorFlorian Pose <fp@igh-essen.com>
Fri, 26 Jun 2009 09:46:57 +0000
changeset 1485 5ddc3a455059
parent 1484 1c9151455b65
child 1486 dac749e74956
ethercat eoe command.
NEWS
documentation/Makefile
documentation/ethercat_doc.tex
master/cdev.c
master/datagram.h
master/ethernet.c
master/ethernet.h
master/globals.h
master/ioctl.h
master/master.c
master/master.h
tool/CommandEoe.cpp
tool/CommandEoe.h
tool/Makefile.am
tool/MasterDevice.cpp
tool/MasterDevice.h
tool/main.cpp
--- a/NEWS	Fri Jun 26 08:00:47 2009 +0000
+++ b/NEWS	Fri Jun 26 09:46:57 2009 +0000
@@ -45,6 +45,7 @@
   (thanks to E. Burgstaller).
 * Module symbol versions file for ec_master.ko is installed to
   prefix/modules/ec_master.symvers.
+* Added 'ethercat eoe' command to display Ethernet over EtherCAT statistics.
 
 Changes in 1.4.0:
 
--- a/documentation/Makefile	Fri Jun 26 08:00:47 2009 +0000
+++ b/documentation/Makefile	Fri Jun 26 09:46:57 2009 +0000
@@ -17,6 +17,7 @@
 	debug \
 	domains \
 	download \
+	eoe \
 	foe_read \
 	foe_write \
 	graph \
--- a/documentation/ethercat_doc.tex	Fri Jun 26 08:00:47 2009 +0000
+++ b/documentation/ethercat_doc.tex	Fri Jun 26 09:46:57 2009 +0000
@@ -2115,6 +2115,12 @@
 
 %------------------------------------------------------------------------------
 
+\subsection{EoE Statistics}
+
+\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_eoe}
+
+%------------------------------------------------------------------------------
+
 \subsection{File-Access over EtherCAT}
 
 \lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_foe_read}
--- a/master/cdev.c	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/cdev.c	Fri Jun 26 09:46:57 2009 +0000
@@ -42,6 +42,7 @@
 #include "master.h"
 #include "slave_config.h"
 #include "voe_handler.h"
+#include "ethernet.h"
 #include "ioctl.h"
 
 /** Set to 1 to enable ioctl() command debugging.
@@ -170,6 +171,7 @@
     data.slave_count = master->slave_count;
     data.config_count = ec_master_config_count(master);
     data.domain_count = ec_master_domain_count(master);
+    data.eoe_handler_count = ec_master_eoe_handler_count(master);
     data.phase = (uint8_t) master->phase;
     data.scan_busy = master->scan_busy;
     up(&master->master_sem);
@@ -1439,6 +1441,53 @@
 
 /*****************************************************************************/
 
+/** Get EoE handler information.
+ */
+int ec_cdev_ioctl_eoe_handler(
+        ec_master_t *master, /**< EtherCAT master. */
+        unsigned long arg /**< ioctl() argument. */
+        )
+{
+    ec_ioctl_eoe_handler_t data;
+	const ec_eoe_t *eoe;
+
+    if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+        return -EFAULT;
+    }
+
+    if (down_interruptible(&master->master_sem))
+        return -EINTR;
+
+    if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) {
+        up(&master->master_sem);
+        EC_ERR("EoE handler %u does not exist!\n", data.eoe_index);
+        return -EINVAL;
+    }
+
+	if (eoe->slave) {
+		data.slave_position = eoe->slave->ring_position;
+	} else {
+		data.slave_position = 0xffff;
+	}
+	snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name);
+    data.open = eoe->opened;
+    data.rx_bytes = eoe->stats.tx_bytes;
+    data.rx_rate = eoe->tx_rate;
+    data.tx_bytes = eoe->stats.rx_bytes;
+    data.tx_rate = eoe->tx_rate;
+    data.tx_queued_frames = eoe->tx_queued_frames;
+    data.tx_queue_size = eoe->tx_queue_size;
+
+    up(&master->master_sem);
+
+    if (copy_to_user((void __user *) arg, &data, sizeof(data)))
+        return -EFAULT;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 /** Request the master from userspace.
  */
 int ec_cdev_ioctl_request(
@@ -3133,6 +3182,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_EOE_HANDLER:
+            return ec_cdev_ioctl_eoe_handler(master, arg);
         case EC_IOCTL_REQUEST:
             if (!(filp->f_mode & FMODE_WRITE))
 				return -EPERM;
--- a/master/datagram.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/datagram.h	Fri Jun 26 09:46:57 2009 +0000
@@ -45,11 +45,6 @@
 
 /*****************************************************************************/
 
-/** Size of the datagram description string. */
-#define EC_DATAGRAM_NAME_SIZE 20
-
-/*****************************************************************************/
-
 /** EtherCAT datagram type.
  */
 typedef enum {
--- a/master/ethernet.c	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/ethernet.c	Fri Jun 26 09:46:57 2009 +0000
@@ -102,6 +102,7 @@
     INIT_LIST_HEAD(&eoe->tx_queue);
     eoe->tx_frame = NULL;
     eoe->tx_queue_active = 0;
+    eoe->tx_queue_size = EC_EOE_TX_QUEUE_SIZE;
     eoe->tx_queued_frames = 0;
     eoe->tx_queue_lock = SPIN_LOCK_UNLOCKED;
     eoe->tx_frame_number = 0xFF;
@@ -308,8 +309,8 @@
 
     // update statistics
     if (jiffies - eoe->rate_jiffies > HZ) {
-        eoe->rx_rate = eoe->rx_counter * 8;
-        eoe->tx_rate = eoe->tx_counter * 8;
+        eoe->rx_rate = eoe->rx_counter;
+        eoe->tx_rate = eoe->tx_counter;
         eoe->rx_counter = 0;
         eoe->tx_counter = 0;
         eoe->rate_jiffies = jiffies;
@@ -574,7 +575,7 @@
     eoe->tx_frame = list_entry(eoe->tx_queue.next, ec_eoe_frame_t, queue);
     list_del(&eoe->tx_frame->queue);
     if (!eoe->tx_queue_active &&
-        eoe->tx_queued_frames == EC_EOE_TX_QUEUE_SIZE / 2) {
+        eoe->tx_queued_frames == eoe->tx_queue_size / 2) {
         netif_wake_queue(eoe->dev);
         eoe->tx_queue_active = 1;
 #if EOE_DEBUG_LEVEL > 0
@@ -722,7 +723,7 @@
     spin_lock_bh(&eoe->tx_queue_lock);
     list_add_tail(&frame->queue, &eoe->tx_queue);
     eoe->tx_queued_frames++;
-    if (eoe->tx_queued_frames == EC_EOE_TX_QUEUE_SIZE) {
+    if (eoe->tx_queued_frames == eoe->tx_queue_size) {
         netif_stop_queue(dev);
         eoe->tx_queue_active = 0;
     }
--- a/master/ethernet.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/ethernet.h	Fri Jun 26 09:46:57 2009 +0000
@@ -34,6 +34,9 @@
 
 /*****************************************************************************/
 
+#ifndef __EC_ETHERNET_H__
+#define __EC_ETHERNET_H__
+
 #include <linux/list.h>
 #include <linux/netdevice.h>
 
@@ -82,6 +85,7 @@
     uint32_t rx_counter; /**< octets received during last second */
     uint32_t rx_rate; /**< receive rate (bps) */
     struct list_head tx_queue; /**< queue for frames to send */
+    unsigned int tx_queue_size; /**< Transmit queue size. */
     unsigned int tx_queue_active; /**< kernel netif queue started */
     unsigned int tx_queued_frames; /**< number of frames in the queue */
     spinlock_t tx_queue_lock; /**< spinlock for the send queue */
@@ -102,3 +106,7 @@
 int ec_eoe_is_open(const ec_eoe_t *);
 
 /*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
--- a/master/globals.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/globals.h	Fri Jun 26 09:46:57 2009 +0000
@@ -105,6 +105,12 @@
 /** Number of DC sync signals. */
 #define EC_SYNC_SIGNAL_COUNT 2
 
+/** Size of the datagram description string.
+ *
+ * This is also used as the maximum lenth of EoE device names.
+ **/
+#define EC_DATAGRAM_NAME_SIZE 20
+
 /** Slave state mask.
  *
  * Apply this mask to a slave state byte to get the slave state without
--- a/master/ioctl.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/ioctl.h	Fri Jun 26 09:46:57 2009 +0000
@@ -77,45 +77,46 @@
 #define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x15, ec_ioctl_config_pdo_t)
 #define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x16, ec_ioctl_config_pdo_entry_t)
 #define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x17, ec_ioctl_config_sdo_t)
+#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x18, ec_ioctl_eoe_handler_t)
 
 // Application interface
-#define EC_IOCTL_REQUEST                EC_IO(0x18)
-#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x19)
-#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x1a, ec_ioctl_config_t)
-#define EC_IOCTL_ACTIVATE              EC_IOR(0x1b, size_t)
-#define EC_IOCTL_SEND                   EC_IO(0x1c)
-#define EC_IOCTL_RECEIVE                EC_IO(0x1d)
-#define EC_IOCTL_MASTER_STATE          EC_IOR(0x1e, ec_master_state_t)
-#define EC_IOCTL_APP_TIME              EC_IOW(0x1f, ec_ioctl_app_time_t)
-#define EC_IOCTL_SYNC_REF               EC_IO(0x20)
-#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x21)
-#define EC_IOCTL_SC_SYNC               EC_IOW(0x22, ec_ioctl_config_t)
-#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x23, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x24, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x25, ec_ioctl_add_pdo_entry_t)
-#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x26, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x27, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_DC                 EC_IOW(0x28, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO                EC_IOW(0x29, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x2a, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x2b, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x2c, ec_ioctl_sc_state_t)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x2d)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x2e)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x2f)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x30, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x31, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x32, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x33, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x34, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x35, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x36, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x37, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x38, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x39, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x3a, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x3b, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x3c, ec_ioctl_voe_t)
+#define EC_IOCTL_REQUEST                EC_IO(0x19)
+#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1a)
+#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x1b, ec_ioctl_config_t)
+#define EC_IOCTL_ACTIVATE              EC_IOR(0x1c, size_t)
+#define EC_IOCTL_SEND                   EC_IO(0x1d)
+#define EC_IOCTL_RECEIVE                EC_IO(0x1e)
+#define EC_IOCTL_MASTER_STATE          EC_IOR(0x1f, ec_master_state_t)
+#define EC_IOCTL_APP_TIME              EC_IOW(0x20, ec_ioctl_app_time_t)
+#define EC_IOCTL_SYNC_REF               EC_IO(0x21)
+#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x22)
+#define EC_IOCTL_SC_SYNC               EC_IOW(0x23, ec_ioctl_config_t)
+#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x24, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x25, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x26, ec_ioctl_add_pdo_entry_t)
+#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x27, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x28, ec_ioctl_reg_pdo_entry_t)
+#define EC_IOCTL_SC_DC                 EC_IOW(0x29, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO                EC_IOW(0x2a, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x2b, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x2c, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x2d, ec_ioctl_sc_state_t)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x2e)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x2f)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x30)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x31, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x32, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x33, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x34, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x35, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x36, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x37, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x38, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x39, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x3a, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x3b, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x3c, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x3d, ec_ioctl_voe_t)
 
 /*****************************************************************************/
 
@@ -127,6 +128,7 @@
     uint32_t slave_count;
     uint32_t config_count;
     uint32_t domain_count;
+    uint32_t eoe_handler_count;
     uint8_t phase;
     uint8_t scan_busy;
     struct {
@@ -442,6 +444,24 @@
 /*****************************************************************************/
 
 typedef struct {
+    // input
+    uint16_t eoe_index;
+
+    // outputs
+	char name[EC_DATAGRAM_NAME_SIZE];
+	uint16_t slave_position;
+	uint8_t open;
+	uint32_t rx_bytes;
+	uint32_t rx_rate;
+	uint32_t tx_bytes;
+	uint32_t tx_rate;
+	uint32_t tx_queued_frames;
+	uint32_t tx_queue_size;
+} ec_ioctl_eoe_handler_t;
+
+/*****************************************************************************/
+
+typedef struct {
     // inputs
     uint32_t config_index;
     uint16_t pdo_index;
--- a/master/master.c	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/master.c	Fri Jun 26 09:46:57 2009 +0000
@@ -1334,6 +1334,50 @@
 
 /*****************************************************************************/
 
+/** Get the number of EoE handlers.
+ *
+ * \return Number of EoE handlers.
+ */
+uint16_t ec_master_eoe_handler_count(
+		const ec_master_t *master /**< EtherCAT master. */
+		)
+{
+	const ec_eoe_t *eoe;
+	unsigned int count = 0;
+
+	list_for_each_entry(eoe, &master->eoe_handlers, list) {
+		count++;
+	}
+
+	return count;
+}
+
+/*****************************************************************************/
+
+/** Get an EoE handler via its position in the list.
+ *
+ * Const version.
+ *
+ * \return EoE handler pointer, or \a NULL if not found.
+ */
+const ec_eoe_t *ec_master_get_eoe_handler_const(
+		const ec_master_t *master, /**< EtherCAT master. */
+		uint16_t index /**< EoE handler index. */
+		)
+{
+	const ec_eoe_t *eoe;
+
+	list_for_each_entry(eoe, &master->eoe_handlers, list) {
+		if (index--)
+			continue;
+		return eoe;
+	}
+
+	return NULL;
+}
+
+/*****************************************************************************/
+
 /** Set the debug level.
  *
  * \retval       0 Success.
--- a/master/master.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/master/master.h	Fri Jun 26 09:46:57 2009 +0000
@@ -51,6 +51,7 @@
 
 #include "device.h"
 #include "domain.h"
+#include "ethernet.h"
 #include "fsm_master.h"
 #include "cdev.h"
 
@@ -229,6 +230,8 @@
 ec_domain_t *ec_master_find_domain(ec_master_t *, unsigned int);
 const ec_domain_t *ec_master_find_domain_const(const ec_master_t *,
         unsigned int);
+uint16_t ec_master_eoe_handler_count(const ec_master_t *);
+const ec_eoe_t *ec_master_get_eoe_handler_const(const ec_master_t *, uint16_t);
 
 int ec_master_debug_level(ec_master_t *, unsigned int);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandEoe.cpp	Fri Jun 26 09:46:57 2009 +0000
@@ -0,0 +1,103 @@
+/*****************************************************************************
+ *
+ *  $Id: CommandSlaves.cpp 1767 2009-05-08 13:35:06Z fp $
+ *
+ *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+#include <list>
+#include <string.h>
+using namespace std;
+
+#include "CommandEoe.h"
+
+/*****************************************************************************/
+
+CommandEoe::CommandEoe():
+    Command("eoe", "Display Ethernet over EtherCAT statictics.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandEoe::helpString() const
+{
+    stringstream str;
+
+    str << getName() << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "The TxRate and RxRate are displayed in Byte/s." << endl
+        << endl;
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandEoe::execute(MasterDevice &m, const StringVector &args)
+{
+    ec_ioctl_master_t master;
+    unsigned int i;
+    ec_ioctl_eoe_handler_t eoe;
+    
+    if (args.size()) {
+        stringstream err;
+        err << "'" << getName() << "' takes no arguments!";
+        throwInvalidUsageException(err);
+    }
+
+    m.open(MasterDevice::Read);
+    m.getMaster(&master);
+
+    cout << "Interface  Slave  State  "
+        << "RxBytes  RxRate  "
+        << "TxBytes  TxRate  TxQueue"
+        << endl;
+
+    for (i = 0; i < master.eoe_handler_count; i++) {
+        stringstream queue;
+
+        m.getEoeHandler(&eoe, i);
+
+        queue << eoe.tx_queued_frames << "/" << eoe.tx_queue_size;
+
+        cout 
+            << setw(9) << eoe.name << "  "
+            << setw(5) << dec << eoe.slave_position << "  "
+            << setw(5) << (eoe.open ? "up" : "down") << "  "
+            << setw(7) << eoe.rx_bytes << "  "
+            << setw(6) << eoe.rx_rate << "  "
+            << setw(7) << eoe.tx_bytes << "  "
+            << setw(6) << eoe.tx_rate << "  "
+            << setw(7) << queue.str()
+            << endl;
+    }
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandEoe.h	Fri Jun 26 09:46:57 2009 +0000
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ *
+ *  $Id: CommandSlaves.h 1667 2009-02-24 12:51:39Z fp $
+ *
+ *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDEOE_H__
+#define __COMMANDEOE_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandEoe:
+    public Command
+{
+    public:
+        CommandEoe();
+
+        string helpString() const;
+        void execute(MasterDevice &, const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
--- a/tool/Makefile.am	Fri Jun 26 08:00:47 2009 +0000
+++ b/tool/Makefile.am	Fri Jun 26 09:46:57 2009 +0000
@@ -41,6 +41,7 @@
 	CommandDebug.cpp \
 	CommandDomains.cpp \
 	CommandDownload.cpp \
+	CommandEoe.cpp \
 	CommandFoeRead.cpp \
 	CommandFoeWrite.cpp \
 	CommandGraph.cpp \
@@ -71,6 +72,7 @@
 	CommandDebug.h \
 	CommandDomains.h \
 	CommandDownload.h \
+	CommandEoe.h \
 	CommandFoeRead.h \
 	CommandFoeWrite.h \
 	CommandGraph.h \
--- a/tool/MasterDevice.cpp	Fri Jun 26 08:00:47 2009 +0000
+++ b/tool/MasterDevice.cpp	Fri Jun 26 09:46:57 2009 +0000
@@ -483,4 +483,20 @@
     }
 }
 
+/****************************************************************************/
+
+void MasterDevice::getEoeHandler(
+        ec_ioctl_eoe_handler_t *eoe,
+        uint16_t eoeHandlerIndex
+        )
+{
+    eoe->eoe_index = eoeHandlerIndex;
+
+    if (ioctl(fd, EC_IOCTL_EOE_HANDLER, eoe)) {
+        stringstream err;
+        err << "Failed to get EoE handler: " << strerror(errno);
+        throw MasterDeviceException(err);
+    }
+}
+
 /*****************************************************************************/
--- a/tool/MasterDevice.h	Fri Jun 26 08:00:47 2009 +0000
+++ b/tool/MasterDevice.h	Fri Jun 26 09:46:57 2009 +0000
@@ -117,6 +117,7 @@
 		void requestState(uint16_t, uint8_t);
 		void readFoe(ec_ioctl_slave_foe_t *);
         void writeFoe(ec_ioctl_slave_foe_t *);
+        void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t);
 
     private:
         unsigned int index;
--- a/tool/main.cpp	Fri Jun 26 08:00:47 2009 +0000
+++ b/tool/main.cpp	Fri Jun 26 09:46:57 2009 +0000
@@ -41,6 +41,7 @@
 #include "CommandDebug.h"
 #include "CommandDomains.h"
 #include "CommandDownload.h"
+#include "CommandEoe.h"
 #include "CommandFoeRead.h"
 #include "CommandFoeWrite.h"
 #include "CommandGraph.h"
@@ -296,6 +297,7 @@
     commandList.push_back(new CommandDebug());
     commandList.push_back(new CommandDomains());
     commandList.push_back(new CommandDownload());
+    commandList.push_back(new CommandEoe());
     commandList.push_back(new CommandFoeRead());
     commandList.push_back(new CommandFoeWrite());
     commandList.push_back(new CommandGraph());