Added the new ethercat comman-line tool with lsec functionality.
--- 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;
+}
+
+/****************************************************************************/