--- a/Makefile.am Wed Apr 23 17:06:15 2014 +0200
+++ b/Makefile.am Fri Apr 25 16:42:36 2014 +0200
@@ -30,11 +30,14 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = \
- devices \
include \
- master \
script
+if ENABLE_KERNEL
+SUBDIRS += devices
+SUBDIRS += master
+endif
+
if BUILD_TOOL
SUBDIRS += tool
endif
--- a/NEWS Wed Apr 23 17:06:15 2014 +0200
+++ b/NEWS Fri Apr 25 16:42:36 2014 +0200
@@ -6,7 +6,11 @@
-------------------------------------------------------------------------------
-Changes since 1.5.1:
+Changes since 1.5.2:
+
+* Fixed FoE timeout calculation bug.
+
+Changes in 1.5.2:
* API extensions (find the complete description in include/ecrt.h)
* Added redundancy features; enable using --with-devices.
--- a/configure.ac Wed Apr 23 17:06:15 2014 +0200
+++ b/configure.ac Fri Apr 25 16:42:36 2014 +0200
@@ -57,9 +57,42 @@
AC_PROG_LIBTOOL
#------------------------------------------------------------------------------
+# Kernel modules
+#------------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to build kernel modules])
+
+AC_ARG_ENABLE([kernel],
+ AS_HELP_STRING([--enable-kernel],
+ [Enable building kernel modules]),
+ [
+ case "${enableval}" in
+ yes) enablekernel=1
+ ;;
+ no) enablekernel=0
+ ;;
+ *) AC_MSG_ERROR([Invalid value for --enable-generic])
+ ;;
+ esac
+ ],
+ [enablekernel=1]
+)
+
+if test "x$enablekernel" = "x1"; then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+AM_CONDITIONAL(ENABLE_KERNEL, test "x$enablekernel" = "x1")
+AC_SUBST(ENABLE_KERNEL,[$enablekernel])
+
+#------------------------------------------------------------------------------
# Linux sources
#------------------------------------------------------------------------------
+if test "x$enablekernel" = "x1"; then
+
AC_ARG_WITH([linux-dir],
AC_HELP_STRING(
[--with-linux-dir=<DIR>],
@@ -116,6 +149,8 @@
AC_SUBST(LINUX_SOURCE_DIR,[$sourcedir])
AC_MSG_RESULT([$LINUX_SOURCE_DIR (Kernel $linuxversion)])
+fi
+
#------------------------------------------------------------------------------
# Linux module installation subdirectory
#------------------------------------------------------------------------------
@@ -150,7 +185,7 @@
;;
esac
],
- [enablegeneric=1]
+ [enablegeneric=$enablekernel]
)
AM_CONDITIONAL(ENABLE_GENERIC, test "x$enablegeneric" = "x1")
@@ -173,7 +208,7 @@
;;
esac
],
- [enable8139too=1]
+ [enable8139too=$enablekernel]
)
AM_CONDITIONAL(ENABLE_8139TOO, test "x$enable8139too" = "x1")
@@ -970,6 +1005,35 @@
fi
#------------------------------------------------------------------------------
+# syslog output in realtime context
+#------------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to syslog in realtime context])
+
+AC_ARG_ENABLE([rt-syslog],
+ AS_HELP_STRING([--enable-rt-syslog],
+ [Enable RT syslog (default: yes)]),
+ [
+ case "${enableval}" in
+ yes) rtsyslog=1
+ ;;
+ no) rtsyslog=0
+ ;;
+ *) AC_MSG_ERROR([Invalid value for --enable-rt-syslog])
+ ;;
+ esac
+ ],
+ [rtsyslog=1]
+)
+
+if test "x${rtsyslog}" = "x1"; then
+ AC_DEFINE([EC_RT_SYSLOG], [1], [Output to syslog in RT context])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+#------------------------------------------------------------------------------
AC_CONFIG_FILES([
Doxyfile
--- a/devices/e100-3.4-ethercat.c Wed Apr 23 17:06:15 2014 +0200
+++ b/devices/e100-3.4-ethercat.c Fri Apr 25 16:42:36 2014 +0200
@@ -2122,7 +2122,9 @@
// No need to detect link status as
// long as frames are received: Reset watchdog.
- nic->ec_watchdog_jiffies = jiffies;
+ if (ecdev_get_link(nic->ecdev)) {
+ nic->ec_watchdog_jiffies = jiffies;
+ }
} else {
netif_receive_skb(skb);
}
--- a/devices/r8169-3.4-ethercat.c Wed Apr 23 17:06:15 2014 +0200
+++ b/devices/r8169-3.4-ethercat.c Fri Apr 25 16:42:36 2014 +0200
@@ -1,9 +1,9 @@
/*
-* r8169.c: RealTek 8169/8168/8101 ethernet driver.
-*
-* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
-* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
-* Copyright (c) a lot of people too. Please respect their work.
+ * r8169.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
@@ -31,6 +31,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+
#include "../globals.h"
#include "ecdev.h"
@@ -744,9 +745,6 @@
struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
-
- ec_device_t *ecdev;
- unsigned long ec_watchdog_jiffies;
u32 opts1_mask;
struct rtl_fw {
@@ -762,6 +760,9 @@
} phy_action;
} *rtl_fw;
#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
+
+ ec_device_t *ecdev;
+ unsigned long ec_watchdog_jiffies;
};
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -5548,7 +5549,7 @@
status = rtl_get_events(tp) & tp->event_slow;
rtl_ack_events(tp, status);
- if (unlikely(!tp->ecdev && status & RxFIFOOver)) {
+ if (unlikely(!tp->ecdev && (status & RxFIFOOver))) {
switch (tp->mac_version) {
/* Work around for rx fifo overflow */
case RTL_GIGA_MAC_VER_11:
@@ -5560,7 +5561,7 @@
}
}
- if (unlikely(!tp->ecdev && status & SYSErr))
+ if (unlikely(!tp->ecdev && (status & SYSErr)))
rtl8169_pcierr_interrupt(dev);
if (status & LinkChg)
@@ -5781,7 +5782,7 @@
rtl_request_firmware(tp);
if (!tp->ecdev) {
- retval = request_irq(dev->irq, rtl8169_interrupt,
+ retval = request_irq(pdev->irq, rtl8169_interrupt,
(tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
dev->name, dev);
if (retval < 0)
--- a/documentation/ethercat_doc.tex Wed Apr 23 17:06:15 2014 +0200
+++ b/documentation/ethercat_doc.tex Fri Apr 25 16:42:36 2014 +0200
@@ -1239,6 +1239,25 @@
realtime context.
\end{itemize}
+\paragraph{Device Activation} In order to send and receive frames through a
+socket, the Ethernet device linked to that socket has to be activated,
+otherwise all frames will be rejected. Activation has to take place before the
+master module is loaded and can happen in several ways:
+
+\begin{itemize}
+
+\item Ad-hoc, using the command \lstinline+ip link set dev ethX up+ (or the
+older \lstinline+ifconfig ethX up+),
+
+\item Configured, depending on the distribution, for example using
+\lstinline+ifcfg+ files (\lstinline+/etc/sysconfig/network/ifcfg-ethX+) in
+openSUSE and others. This is the better choice, if the EtherCAT master shall
+start at system boot time. Since the Ethernet device shall only be activated,
+but no IP address etc.\ shall be assigned, it is enough to use
+\lstinline+STARTMODE=auto+ as configuration.
+
+\end{itemize}
+
%------------------------------------------------------------------------------
\section{Providing Ethernet Devices}
--- a/examples/user/main.c Wed Apr 23 17:06:15 2014 +0200
+++ b/examples/user/main.c Fri Apr 25 16:42:36 2014 +0200
@@ -1,6 +1,6 @@
/*****************************************************************************
*
- * $Id: main.c,v 6a6dec6fc806 2012/09/19 17:46:58 fp $
+ * $Id$
*
* Copyright (C) 2007-2009 Florian Pose, Ingenieurgemeinschaft IgH
*
--- a/master/datagram_pair.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/datagram_pair.c Fri Apr 25 16:42:36 2014 +0200
@@ -185,7 +185,9 @@
dev_idx++) {
ec_datagram_t *datagram = &pair->datagrams[dev_idx];
+#ifdef EC_RT_SYSLOG
ec_datagram_output_stats(datagram);
+#endif
if (datagram->state == EC_DATAGRAM_RECEIVED) {
pair_wc += datagram->working_counter;
--- a/master/device.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/device.c Fri Apr 25 16:42:36 2014 +0200
@@ -663,7 +663,7 @@
ec_device_debug_ring_append(device, RX, ec_data, ec_size);
#endif
- ec_master_receive_datagrams(device->master, ec_data, ec_size);
+ ec_master_receive_datagrams(device->master, device, ec_data, ec_size);
}
/*****************************************************************************/
--- a/master/domain.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/domain.c Fri Apr 25 16:42:36 2014 +0200
@@ -466,7 +466,10 @@
ec_fmmu_config_t, list);
unsigned int redundancy;
#endif
- unsigned int dev_idx, wc_change;
+ unsigned int dev_idx;
+#ifdef EC_RT_SYSLOG
+ unsigned int wc_change;
+#endif
#if DEBUG_REDUNDANCY
EC_MASTER_DBG(domain->master, 1, "domain %u process\n", domain->index);
@@ -569,6 +572,7 @@
redundancy = redundant_wc > 0;
if (redundancy != domain->redundancy_active) {
+#ifdef EC_RT_SYSLOG
if (redundancy) {
EC_MASTER_WARN(domain->master,
"Domain %u: Redundant link in use!\n",
@@ -578,23 +582,29 @@
"Domain %u: Redundant link unused again.\n",
domain->index);
}
+#endif
domain->redundancy_active = redundancy;
}
#else
domain->redundancy_active = 0;
#endif
+#ifdef EC_RT_SYSLOG
wc_change = 0;
+#endif
wc_total = 0;
for (dev_idx = EC_DEVICE_MAIN;
dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
if (wc_sum[dev_idx] != domain->working_counter[dev_idx]) {
+#ifdef EC_RT_SYSLOG
wc_change = 1;
+#endif
domain->working_counter[dev_idx] = wc_sum[dev_idx];
}
wc_total += wc_sum[dev_idx];
}
+#ifdef EC_RT_SYSLOG
if (wc_change) {
domain->working_counter_changes++;
}
@@ -630,6 +640,7 @@
domain->working_counter_changes = 0;
}
+#endif
}
/*****************************************************************************/
--- a/master/fsm_foe.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/fsm_foe.c Fri Apr 25 16:42:36 2014 +0200
@@ -3,6 +3,7 @@
* $Id$
*
* Copyright (C) 2008 Olav Zarges, imc Messsysteme GmbH
+ * 2013 Florian Pose <fp@igh-essen.com>
*
* This file is part of the IgH EtherCAT Master.
*
@@ -27,10 +28,9 @@
*
*****************************************************************************/
-/**
- \file
- EtherCAT FoE state machines.
-*/
+/** \file
+ * EtherCAT FoE state machines.
+ */
/*****************************************************************************/
@@ -209,7 +209,7 @@
)
{
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_error()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
}
@@ -223,7 +223,7 @@
)
{
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_end\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
}
@@ -321,7 +321,7 @@
fsm->tx_last_packet = 0;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_write_start()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) {
@@ -350,7 +350,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_ack_check()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -370,8 +370,8 @@
if (!ec_slave_mbox_check(fsm->datagram)) {
// slave did not put anything in the mailbox yet
- unsigned long diff_ms =
- (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
+ unsigned long diff_ms = (fsm->datagram->jiffies_received -
+ fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
@@ -405,7 +405,7 @@
size_t rec_size;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_ack_read()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -482,7 +482,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_foe_state_sent_wrq()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -523,7 +523,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_state_data_sent()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -620,7 +620,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_foe_state_rrq_sent()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -662,7 +662,7 @@
fsm->rx_last_packet = 0;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_read_start()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) {
@@ -691,7 +691,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_state_data_check()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -709,9 +709,8 @@
}
if (!ec_slave_mbox_check(fsm->datagram)) {
- unsigned long diff_ms =
- (fsm->datagram->jiffies_received - fsm->jiffies_start) *
- 1000 / HZ;
+ unsigned long diff_ms = (fsm->datagram->jiffies_received -
+ fsm->jiffies_start) * 1000 / HZ;
if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
@@ -728,7 +727,6 @@
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_foe_state_data_read;
-
}
/*****************************************************************************/
@@ -746,7 +744,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_fsm_foe_state_data_read()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -832,7 +830,7 @@
// either it was the last packet or a new packet will fit into the
// delivered buffer
#ifdef DEBUG_FOE
- printk ("last_packet=true\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "last_packet=true\n");
#endif
if (ec_foe_prepare_send_ack(fsm, datagram)) {
ec_foe_set_rx_error(fsm, FOE_RX_DATA_ACK_ERROR);
@@ -844,13 +842,12 @@
else {
// no more data fits into the delivered buffer
// ... wait for new read request
- printk ("ERROR: data doesn't fit in receive buffer\n");
- printk (" rx_buffer_size = %d\n", fsm->rx_buffer_size);
- printk (" rx_buffer_offset= %d\n", fsm->rx_buffer_offset);
- printk (" rec_size = %zd\n", rec_size);
- printk (" rx_mailbox_size = %d\n",
- slave->configured_rx_mailbox_size);
- printk (" rx_last_packet = %d\n", fsm->rx_last_packet);
+ EC_SLAVE_ERR(slave, "Data do not fit in receive buffer!\n");
+ printk(" rx_buffer_size = %d\n", fsm->rx_buffer_size);
+ printk("rx_buffer_offset = %d\n", fsm->rx_buffer_offset);
+ printk(" rec_size = %zd\n", rec_size);
+ printk(" rx_mailbox_size = %d\n", slave->configured_rx_mailbox_size);
+ printk(" rx_last_packet = %d\n", fsm->rx_last_packet);
fsm->request->result = FOE_READY;
}
}
@@ -867,7 +864,7 @@
ec_slave_t *slave = fsm->slave;
#ifdef DEBUG_FOE
- printk("ec_foe_state_sent_ack()\n");
+ EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
#endif
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
--- a/master/fsm_master.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/fsm_master.c Fri Apr 25 16:42:36 2014 +0200
@@ -198,7 +198,47 @@
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
+ ec_master_t *master = fsm->master;
+
fsm->idle = 1;
+
+ // check for emergency requests
+ if (!list_empty(&master->emerg_reg_requests)) {
+ ec_reg_request_t *request;
+
+ // get first request
+ request = list_entry(master->emerg_reg_requests.next,
+ ec_reg_request_t, list);
+ list_del_init(&request->list); // dequeue
+ request->state = EC_INT_REQUEST_BUSY;
+
+ if (request->transfer_size > fsm->datagram->mem_size) {
+ EC_MASTER_ERR(master, "Emergency request data too large!\n");
+ request->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&master->request_queue);
+ fsm->state(fsm); // continue
+ return;
+ }
+
+ if (request->dir != EC_DIR_OUTPUT) {
+ EC_MASTER_ERR(master, "Emergency requests must be"
+ " write requests!\n");
+ request->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&master->request_queue);
+ fsm->state(fsm); // continue
+ return;
+ }
+
+ EC_MASTER_DBG(master, 1, "Writing emergency register request...\n");
+ ec_datagram_apwr(fsm->datagram, request->ring_position,
+ request->address, request->transfer_size);
+ memcpy(fsm->datagram->data, request->data, request->transfer_size);
+ fsm->datagram->device_index = EC_DEVICE_MAIN;
+ request->state = EC_INT_REQUEST_SUCCESS;
+ wake_up_all(&master->request_queue);
+ return;
+ }
+
ec_datagram_brd(fsm->datagram, 0x0130, 2);
ec_datagram_zero(fsm->datagram);
fsm->datagram->device_index = fsm->dev_idx;
--- a/master/ioctl.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/ioctl.c Fri Apr 25 16:42:36 2014 +0200
@@ -1144,16 +1144,23 @@
return -EINTR;
}
- if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) {
- up(&master->master_sem);
- ec_reg_request_clear(&request);
- EC_MASTER_ERR(master, "Slave %u does not exist!\n",
- io.slave_position);
- return -EINVAL;
- }
-
- // schedule request.
- list_add_tail(&request.list, &slave->reg_requests);
+ if (io.emergency) {
+ request.ring_position = io.slave_position;
+ // schedule request.
+ list_add_tail(&request.list, &master->emerg_reg_requests);
+ }
+ else {
+ if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) {
+ up(&master->master_sem);
+ ec_reg_request_clear(&request);
+ EC_MASTER_ERR(master, "Slave %u does not exist!\n",
+ io.slave_position);
+ return -EINVAL;
+ }
+
+ // schedule request.
+ list_add_tail(&request.list, &slave->reg_requests);
+ }
up(&master->master_sem);
--- a/master/ioctl.h Wed Apr 23 17:06:15 2014 +0200
+++ b/master/ioctl.h Fri Apr 25 16:42:36 2014 +0200
@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
-#define EC_IOCTL_VERSION_MAGIC 27
+#define EC_IOCTL_VERSION_MAGIC 28
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -419,6 +419,7 @@
typedef struct {
// inputs
uint16_t slave_position;
+ uint8_t emergency;
uint16_t address;
size_t size;
uint8_t *data;
--- a/master/master.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/master.c Fri Apr 25 16:42:36 2014 +0200
@@ -60,6 +60,10 @@
*/
#define DEBUG_INJECT 0
+/** Always output corrupted frames.
+ */
+#define FORCE_OUTPUT_CORRUPTED 0
+
#ifdef EC_HAVE_CYCLES
/** Frame timeout in cycles.
@@ -232,6 +236,7 @@
master->app_cb_data = NULL;
INIT_LIST_HEAD(&master->sii_requests);
+ INIT_LIST_HEAD(&master->emerg_reg_requests);
init_waitqueue_head(&master->request_queue);
@@ -847,9 +852,13 @@
> ext_injection_timeout_jiffies)
#endif
{
+#if defined EC_RT_SYSLOG || DEBUG_INJECT
unsigned int time_us;
+#endif
datagram->state = EC_DATAGRAM_ERROR;
+
+#if defined EC_RT_SYSLOG || DEBUG_INJECT
#ifdef EC_HAVE_CYCLES
time_us = (unsigned int)
((cycles_now - datagram->cycles_sent) * 1000LL)
@@ -862,6 +871,7 @@
" external datagram %s size=%zu,"
" max_queue_size=%zu\n", time_us, datagram->name,
datagram->data_size, master->max_queue_size);
+#endif
}
else {
#if DEBUG_INJECT
@@ -939,8 +949,10 @@
list_for_each_entry(queued_datagram, &master->datagram_queue, queue) {
if (queued_datagram == datagram) {
datagram->skip_count++;
+#ifdef EC_RT_SYSLOG
EC_MASTER_DBG(master, 1,
"Datagram %p already queued (skipping).\n", datagram);
+#endif
datagram->state = EC_DATAGRAM_QUEUED;
return;
}
@@ -1106,10 +1118,12 @@
*
* \return 0 in case of success, else < 0
*/
-void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
- const uint8_t *frame_data, /**< frame data */
- size_t size /**< size of the received data */
- )
+void ec_master_receive_datagrams(
+ ec_master_t *master, /**< EtherCAT master */
+ ec_device_t *device, /**< EtherCAT device */
+ const uint8_t *frame_data, /**< frame data */
+ size_t size /**< size of the received data */
+ )
{
size_t frame_size, data_size;
uint8_t datagram_type, datagram_index;
@@ -1118,14 +1132,16 @@
ec_datagram_t *datagram;
if (unlikely(size < EC_FRAME_HEADER_SIZE)) {
- if (master->debug_level) {
+ if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
EC_MASTER_DBG(master, 0, "Corrupted frame received"
- " (size %zu < %u byte):\n",
- size, EC_FRAME_HEADER_SIZE);
+ " on %s (size %zu < %u byte):\n",
+ device->dev->name, size, EC_FRAME_HEADER_SIZE);
ec_print_data(frame_data, size);
}
master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
ec_master_output_stats(master);
+#endif
return;
}
@@ -1136,14 +1152,17 @@
cur_data += EC_FRAME_HEADER_SIZE;
if (unlikely(frame_size > size)) {
- if (master->debug_level) {
+ if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
EC_MASTER_DBG(master, 0, "Corrupted frame received"
- " (invalid frame size %zu for "
- "received size %zu):\n", frame_size, size);
+ " on %s (invalid frame size %zu for "
+ "received size %zu):\n", device->dev->name,
+ frame_size, size);
ec_print_data(frame_data, size);
}
master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
ec_master_output_stats(master);
+#endif
return;
}
@@ -1158,13 +1177,16 @@
if (unlikely(cur_data - frame_data
+ data_size + EC_DATAGRAM_FOOTER_SIZE > size)) {
- if (master->debug_level) {
+ if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
EC_MASTER_DBG(master, 0, "Corrupted frame received"
- " (invalid data size %zu):\n", data_size);
+ " on %s (invalid data size %zu):\n",
+ device->dev->name, data_size);
ec_print_data(frame_data, size);
}
master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
ec_master_output_stats(master);
+#endif
return;
}
@@ -1183,7 +1205,9 @@
// no matching datagram was found
if (!matched) {
master->stats.unmatched++;
+#ifdef EC_RT_SYSLOG
ec_master_output_stats(master);
+#endif
if (unlikely(master->debug_level > 0)) {
EC_MASTER_DBG(master, 0, "UNMATCHED datagram:\n");
@@ -2476,6 +2500,8 @@
list_del_init(&datagram->queue);
datagram->state = EC_DATAGRAM_TIMED_OUT;
master->stats.timeouts++;
+
+#ifdef EC_RT_SYSLOG
ec_master_output_stats(master);
if (unlikely(master->debug_level > 0)) {
@@ -2493,6 +2519,7 @@
" index %02X waited %u us.\n",
datagram, datagram->index, time_us);
}
+#endif /* RT_SYSLOG */
}
}
}
--- a/master/master.h Wed Apr 23 17:06:15 2014 +0200
+++ b/master/master.h Fri Apr 25 16:42:36 2014 +0200
@@ -305,6 +305,8 @@
void *app_cb_data; /**< Application callback data. */
struct list_head sii_requests; /**< SII write requests. */
+ struct list_head emerg_reg_requests; /**< Emergency register access
+ requests. */
wait_queue_head_t request_queue; /**< Wait queue for external requests
from user space. */
@@ -341,7 +343,8 @@
#endif
// datagram IO
-void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
+void ec_master_receive_datagrams(ec_master_t *, ec_device_t *,
+ const uint8_t *, size_t);
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
--- a/master/reg_request.c Wed Apr 23 17:06:15 2014 +0200
+++ b/master/reg_request.c Fri Apr 25 16:42:36 2014 +0200
@@ -62,6 +62,7 @@
reg->address = 0;
reg->transfer_size = 0;
reg->state = EC_INT_REQUEST_INIT;
+ reg->ring_position = 0;
return 0;
}
--- a/master/reg_request.h Wed Apr 23 17:06:15 2014 +0200
+++ b/master/reg_request.h Fri Apr 25 16:42:36 2014 +0200
@@ -54,6 +54,7 @@
uint16_t address; /**< Register address. */
size_t transfer_size; /**< Size of the data to transfer. */
ec_internal_request_state_t state; /**< Request state. */
+ uint16_t ring_position; /**< Ring position for emergency requests. */
};
/*****************************************************************************/
--- a/script/ethercat.conf Wed Apr 23 17:06:15 2014 +0200
+++ b/script/ethercat.conf Fri Apr 25 16:42:36 2014 +0200
@@ -4,10 +4,12 @@
#
# $Id$
#
+# vim: spelllang=en spell tw=78
+#
#------------------------------------------------------------------------------
#
-# Master devices.
+# Main Ethernet devices.
#
# The MASTER<X>_DEVICE variable specifies the Ethernet device for a master
# with index 'X'.
@@ -26,6 +28,15 @@
#MASTER1_DEVICE=""
#
+# Backup Ethernet devices
+#
+# The MASTER<X>_BACKUP variables specify the devices used for redundancy. They
+# behaves nearly the same as the MASTER<X>_DEVICE variable, except that it
+# does not interpret the ff:ff:ff:ff:ff:ff address.
+#
+#MASTER0_BACKUP=""
+
+#
# Ethernet driver modules to use for EtherCAT operation.
#
# Specify a non-empty list of Ethernet drivers, that shall be used for EtherCAT
@@ -42,6 +53,10 @@
# Note: The e100, e1000, e1000e and r8169 drivers are not built by default.
# Enable them with the --enable-<driver> configure switches.
#
+# Attention: When using the generic driver, the corresponding Ethernet device
+# has to be activated (with OS methods, for example 'ip link set ethX up'),
+# before the master is started, otherwise all frames will time out.
+#
DEVICE_MODULES=""
#
--- a/script/ethercat.service.in Wed Apr 23 17:06:15 2014 +0200
+++ b/script/ethercat.service.in Fri Apr 25 16:42:36 2014 +0200
@@ -1,10 +1,24 @@
#
-# EtherCAT Master Kernel Modules
+# EtherCAT master kernel modules
#
[Unit]
Description=EtherCAT Master Kernel Modules
+#
+# Uncomment this, if the generic Ethernet driver is used. It assures, that the
+# network interfaces are configured, before the master starts.
+#
+#Requires=network.service # Stop master, if network is stopped
+#After=network.service # Start master, after network is ready
+
+#
+# Uncomment this, if a native Ethernet driver is used. It assures, that the
+# network interfaces are configured, after the Ethernet drivers have been
+# replaced. Otherwise, the networking configuration tools could be confused.
+#
+#Before=network.service
+
[Service]
Type=oneshot
RemainAfterExit=yes
--- a/script/sysconfig/ethercat Wed Apr 23 17:06:15 2014 +0200
+++ b/script/sysconfig/ethercat Fri Apr 25 16:42:36 2014 +0200
@@ -53,6 +53,10 @@
# Note: The e100, e1000, e1000e and r8169 drivers are not built by default.
# Enable them with the --enable-<driver> configure switches.
#
+# Attention: When using the generic driver, the corresponding Ethernet device
+# has to be activated (with OS methods, for example 'ip link set ethX up'),
+# before the master is started, otherwise all frames will time out.
+#
DEVICE_MODULES=""
#
--- a/tool/Command.cpp Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/Command.cpp Fri Apr 25 16:42:36 2014 +0200
@@ -150,7 +150,9 @@
Command::Command(const string &name, const string &briefDesc):
name(name),
briefDesc(briefDesc),
- verbosity(Normal)
+ verbosity(Normal),
+ emergency(false),
+ force(false)
{
}
@@ -204,6 +206,13 @@
/*****************************************************************************/
+void Command::setEmergency(bool e)
+{
+ emergency = e;
+};
+
+/*****************************************************************************/
+
void Command::setForce(bool f)
{
force = f;
@@ -489,6 +498,19 @@
/****************************************************************************/
+int Command::emergencySlave() const
+{
+ unsigned int ret;
+
+ stringstream str;
+ str << positions;
+ str >> ret;
+
+ return ret;
+}
+
+/****************************************************************************/
+
string Command::alStateString(uint8_t state)
{
string ret;
--- a/tool/Command.h Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/Command.h Fri Apr 25 16:42:36 2014 +0200
@@ -107,6 +107,9 @@
void setDataType(const string &);
const string &getDataType() const;
+ void setEmergency(bool);
+ bool getEmergency() const;
+
void setForce(bool);
bool getForce() const;
@@ -140,6 +143,7 @@
ConfigList selectedConfigs(MasterDevice &);
typedef list<ec_ioctl_domain_t> DomainList;
DomainList selectedDomains(MasterDevice &, const ec_ioctl_master_t &);
+ int emergencySlave() const;
static string alStateString(uint8_t);
@@ -152,6 +156,7 @@
string positions;
string domains;
string dataType;
+ bool emergency;
bool force;
string outputFile;
string skin;
@@ -189,6 +194,13 @@
/****************************************************************************/
+inline bool Command::getEmergency() const
+{
+ return emergency;
+}
+
+/****************************************************************************/
+
inline bool Command::getForce() const
{
return force;
--- a/tool/CommandRegRead.cpp Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/CommandRegRead.cpp Fri Apr 25 16:42:36 2014 +0200
@@ -149,6 +149,7 @@
throwSingleSlaveRequired(slaves.size());
}
io.slave_position = slaves.front().position;
+ io.emergency = false;
io.data = new uint8_t[io.size];
--- a/tool/CommandRegWrite.cpp Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/CommandRegWrite.cpp Fri Apr 25 16:42:36 2014 +0200
@@ -68,10 +68,12 @@
<< typeInfo()
<< endl
<< "Command-specific options:" << endl
- << " --alias -a <alias>" << endl
- << " --position -p <pos> Slave selection. See the help of" << endl
- << " the 'slaves' command." << endl
- << " --type -t <type> Data type (see above)." << endl
+ << " --alias -a <alias>" << endl
+ << " --position -p <pos> Slave selection. See the help of"
+ << endl
+ << " the 'slaves' command." << endl
+ << " --type -t <type> Data type (see above)." << endl
+ << " --emergency -e Send as emergency request." << endl
<< endl
<< numericInfo();
@@ -85,7 +87,6 @@
stringstream strOffset, err;
ec_ioctl_slave_reg_t io;
ifstream file;
- SlaveList slaves;
if (args.size() != 2) {
err << "'" << getName() << "' takes exactly two arguments!";
@@ -158,12 +159,19 @@
throw e;
}
- slaves = selectedSlaves(m);
- if (slaves.size() != 1) {
- delete [] io.data;
- throwSingleSlaveRequired(slaves.size());
- }
- io.slave_position = slaves.front().position;
+ if (getEmergency()) {
+ io.slave_position = emergencySlave();
+ io.emergency = true;
+ }
+ else {
+ SlaveList slaves = selectedSlaves(m);
+ if (slaves.size() != 1) {
+ delete [] io.data;
+ throwSingleSlaveRequired(slaves.size());
+ }
+ io.slave_position = slaves.front().position;
+ io.emergency = false;
+ }
// send data to master
try {
--- a/tool/main.cpp Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/main.cpp Fri Apr 25 16:42:36 2014 +0200
@@ -83,6 +83,7 @@
string dataTypeStr;
Command::Verbosity verbosity = Command::Normal;
bool force = false;
+bool emergency = false;
bool helpRequested = false;
string outputFile;
string skin;
@@ -149,6 +150,7 @@
{"type", required_argument, NULL, 't'},
{"output-file", required_argument, NULL, 'o'},
{"skin", required_argument, NULL, 's'},
+ {"emergency", no_argument, NULL, 'e'},
{"force", no_argument, NULL, 'f'},
{"quiet", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
@@ -157,7 +159,7 @@
};
do {
- c = getopt_long(argc, argv, "m:a:p:d:t:o:s:fqvh", longOptions, NULL);
+ c = getopt_long(argc, argv, "m:a:p:d:t:o:s:efqvh", longOptions, NULL);
switch (c) {
case 'm':
@@ -188,6 +190,10 @@
skin = optarg;
break;
+ case 'e':
+ emergency = true;
+ break;
+
case 'f':
force = true;
break;
@@ -315,6 +321,7 @@
cmd->setDataType(dataTypeStr);
cmd->setOutputFile(outputFile);
cmd->setSkin(skin);
+ cmd->setEmergency(emergency);
cmd->setForce(force);
cmd->execute(commandArgs);
} catch (InvalidUsageException &e) {