# HG changeset patch # User Florian Pose # Date 1398436956 -7200 # Node ID 674fcdccc0f365d9db0ae991aae28658f12bae17 # Parent fca12d7035d1d408ea8dbbc5200f3e59cf68073a# Parent 18c226b66533bb07a544b8410a6e401cdd77550e merge diff -r 18c226b66533 -r 674fcdccc0f3 Makefile.am --- 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 diff -r 18c226b66533 -r 674fcdccc0f3 NEWS --- 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. diff -r 18c226b66533 -r 674fcdccc0f3 configure.ac --- 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=], @@ -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 diff -r 18c226b66533 -r 674fcdccc0f3 devices/e100-3.4-ethercat.c --- 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); } diff -r 18c226b66533 -r 674fcdccc0f3 devices/r8169-3.4-ethercat.c --- 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 -* Copyright (c) 2003 - 2007 Francois Romieu -* Copyright (c) a lot of people too. Please respect their work. + * r8169.c: RealTek 8169/8168/8101 ethernet driver. + * + * Copyright (c) 2002 ShuChen + * Copyright (c) 2003 - 2007 Francois Romieu + * Copyright (c) a lot of people too. Please respect their work. * * See MAINTAINERS file for support contact information. */ @@ -31,6 +31,7 @@ #include #include + #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 "); @@ -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) diff -r 18c226b66533 -r 674fcdccc0f3 documentation/ethercat_doc.tex --- 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} diff -r 18c226b66533 -r 674fcdccc0f3 examples/user/main.c --- 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 * diff -r 18c226b66533 -r 674fcdccc0f3 master/datagram_pair.c --- 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; diff -r 18c226b66533 -r 674fcdccc0f3 master/device.c --- 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); } /*****************************************************************************/ diff -r 18c226b66533 -r 674fcdccc0f3 master/domain.c --- 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 } /*****************************************************************************/ diff -r 18c226b66533 -r 674fcdccc0f3 master/fsm_foe.c --- 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 * * 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) { diff -r 18c226b66533 -r 674fcdccc0f3 master/fsm_master.c --- 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; diff -r 18c226b66533 -r 674fcdccc0f3 master/ioctl.c --- 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); diff -r 18c226b66533 -r 674fcdccc0f3 master/ioctl.h --- 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; diff -r 18c226b66533 -r 674fcdccc0f3 master/master.c --- 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 */ } } } diff -r 18c226b66533 -r 674fcdccc0f3 master/master.h --- 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 *); diff -r 18c226b66533 -r 674fcdccc0f3 master/reg_request.c --- 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; } diff -r 18c226b66533 -r 674fcdccc0f3 master/reg_request.h --- 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. */ }; /*****************************************************************************/ diff -r 18c226b66533 -r 674fcdccc0f3 script/ethercat.conf --- 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_DEVICE variable specifies the Ethernet device for a master # with index 'X'. @@ -26,6 +28,15 @@ #MASTER1_DEVICE="" # +# Backup Ethernet devices +# +# The MASTER_BACKUP variables specify the devices used for redundancy. They +# behaves nearly the same as the MASTER_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- 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="" # diff -r 18c226b66533 -r 674fcdccc0f3 script/ethercat.service.in --- 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 diff -r 18c226b66533 -r 674fcdccc0f3 script/sysconfig/ethercat --- 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- 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="" # diff -r 18c226b66533 -r 674fcdccc0f3 tool/Command.cpp --- 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; diff -r 18c226b66533 -r 674fcdccc0f3 tool/Command.h --- 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 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; diff -r 18c226b66533 -r 674fcdccc0f3 tool/CommandRegRead.cpp --- 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]; diff -r 18c226b66533 -r 674fcdccc0f3 tool/CommandRegWrite.cpp --- 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 " << endl - << " --position -p Slave selection. See the help of" << endl - << " the 'slaves' command." << endl - << " --type -t Data type (see above)." << endl + << " --alias -a " << endl + << " --position -p Slave selection. See the help of" + << endl + << " the 'slaves' command." << endl + << " --type -t 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 { diff -r 18c226b66533 -r 674fcdccc0f3 tool/main.cpp --- 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) {