From 74798d52598a34f70a182f317c28242255ee47a6 Mon Sep 17 00:00:00 2001 From: Knud Baastrup Date: Mon, 11 Aug 2014 08:06:36 +0200 Subject: [PATCH 1/7] Applied base-0022-Clear-slave-mailboxes-after-a-re-scan When rescanning a slave (and thus discarding any prior pending FSMs), explicitly clear the slave mailbox, to avoid getting confused by a stale response. --- master/fsm_master.c | 3 ++ master/fsm_slave_scan.c | 49 ++++++++++++++++- master/master.c | 114 +++++++++++++++++++++------------------- master/slave.c | 2 + master/slave.h | 2 + 5 files changed, 114 insertions(+), 56 deletions(-) diff --git a/master/fsm_master.c b/master/fsm_master.c index c1cb5b46..47ddb94d 100644 --- a/master/fsm_master.c +++ b/master/fsm_master.c @@ -1135,6 +1135,9 @@ void ec_fsm_master_state_scan_slave( if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) { return; } + // Assume that the slaves mailbox data is valid even if the slave scanning skipped + // the clear mailbox state, e.g. if the slave refused to enter state INIT. + fsm->slave->valid_mbox_data = 1; #ifdef EC_EOE if (slave->sii.mailbox_protocols & EC_MBOX_EOE) { diff --git a/master/fsm_slave_scan.c b/master/fsm_slave_scan.c index 6637a285..66a7795d 100644 --- a/master/fsm_slave_scan.c +++ b/master/fsm_slave_scan.c @@ -55,6 +55,7 @@ void ec_fsm_slave_scan_state_assign_sii(ec_fsm_slave_scan_t *); #endif void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *); +void ec_fsm_slave_scan_state_mailbox_cleared(ec_fsm_slave_scan_t *); #ifdef EC_REGALIAS void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *); #endif @@ -70,6 +71,7 @@ void ec_fsm_slave_scan_enter_datalink(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *); #endif void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *); +void ec_fsm_slave_scan_enter_clear_mailbox(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *); /*****************************************************************************/ @@ -979,7 +981,7 @@ void ec_fsm_slave_scan_state_preop( return; } - ec_fsm_slave_scan_enter_pdos(fsm); + ec_fsm_slave_scan_enter_clear_mailbox(fsm); } /*****************************************************************************/ @@ -1050,6 +1052,51 @@ void ec_fsm_slave_scan_state_sync( // allocate memory for mailbox response data for supported mailbox protocols ec_mbox_prot_data_prealloc(slave, slave->sii.mailbox_protocols, slave->configured_tx_mailbox_size); + ec_fsm_slave_scan_enter_clear_mailbox(fsm); +} + +/*****************************************************************************/ + +/** Enter slave scan state: Clear Mailbox. + */ +void ec_fsm_slave_scan_enter_clear_mailbox( + ec_fsm_slave_scan_t *fsm /**< slave state machine */ + ) +{ + ec_slave_t *slave = fsm->slave; + + // If there is some old data in the slave's mailbox, read it out and + // discard it. We don't need to check the mailbox first, we just ignore + // an error or empty mailbox response. + ec_datagram_t *datagram = fsm->datagram; + ec_slave_mbox_prepare_fetch(fsm->slave, datagram); + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_slave_scan_state_mailbox_cleared; + + slave->valid_mbox_data = 0; +} + +/*****************************************************************************/ + +/** Slave scan state: Mailbox cleared. + */ +void ec_fsm_slave_scan_state_mailbox_cleared(ec_fsm_slave_scan_t *fsm /**< slave state machine */) +{ + ec_slave_t *slave = fsm->slave; + ec_datagram_t *datagram = fsm->datagram; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + ec_slave_mbox_prepare_fetch(fsm->slave, datagram); + return; + } + + if (unlikely(slave->master->debug_level > 0) + && datagram->state == EC_DATAGRAM_RECEIVED + && datagram->working_counter == 1) + EC_SLAVE_INFO(slave, "Cleared old data from the mailbox\n"); + + slave->valid_mbox_data = 1; + ec_fsm_slave_scan_enter_pdos(fsm); } diff --git a/master/master.c b/master/master.c index 5ba49378..a2a02dc8 100644 --- a/master/master.c +++ b/master/master.c @@ -1286,67 +1286,72 @@ void ec_master_receive_datagrams( if (slave->station_address == datagram_slave_addr) { if (slave->configured_tx_mailbox_offset != 0) { if (datagram_offset_addr == slave->configured_tx_mailbox_offset) { - datagram_mbox_prot = EC_READ_U8(cur_data + 5) & 0x0F; - switch (datagram_mbox_prot) { + if (slave->valid_mbox_data) { + datagram_mbox_prot = EC_READ_U8(cur_data + 5) & 0x0F; + switch (datagram_mbox_prot) { #ifdef EC_EOE - case EC_MBOX_TYPE_EOE: - // check EOE type and store in correct handlers mbox data cache - eoe_type = EC_READ_U8(cur_data + 6) & 0x0F; + case EC_MBOX_TYPE_EOE: + // check EOE type and store in correct handlers mbox data cache + eoe_type = EC_READ_U8(cur_data + 6) & 0x0F; - switch (eoe_type) { + switch (eoe_type) { - case EC_EOE_TYPE_FRAME_FRAG: - // EoE Frame Fragment handler - if ((slave->mbox_eoe_frag_data.data) && (data_size <= slave->mbox_eoe_frag_data.data_size)) { - memcpy(slave->mbox_eoe_frag_data.data, cur_data, data_size); - slave->mbox_eoe_frag_data.payload_size = data_size; - } - break; - case EC_EOE_TYPE_INIT_RES: - // EoE Init / Set IP response handler - if ((slave->mbox_eoe_init_data.data) && (data_size <= slave->mbox_eoe_init_data.data_size)) { - memcpy(slave->mbox_eoe_init_data.data, cur_data, data_size); - slave->mbox_eoe_init_data.payload_size = data_size; - } - break; - default: - EC_MASTER_DBG(master, 1, "Unhandled EoE protocol type from slave: %u Protocol: %u, Type: %x\n", - datagram_slave_addr, datagram_mbox_prot, eoe_type); - // copy instead received data into the datagram memory. - memcpy(datagram->data, cur_data, data_size); - break; - } - break; + case EC_EOE_TYPE_FRAME_FRAG: + // EoE Frame Fragment handler + if ((slave->mbox_eoe_frag_data.data) && (data_size <= slave->mbox_eoe_frag_data.data_size)) { + memcpy(slave->mbox_eoe_frag_data.data, cur_data, data_size); + slave->mbox_eoe_frag_data.payload_size = data_size; + } + break; + case EC_EOE_TYPE_INIT_RES: + // EoE Init / Set IP response handler + if ((slave->mbox_eoe_init_data.data) && (data_size <= slave->mbox_eoe_init_data.data_size)) { + memcpy(slave->mbox_eoe_init_data.data, cur_data, data_size); + slave->mbox_eoe_init_data.payload_size = data_size; + } + break; + default: + EC_MASTER_DBG(master, 1, "Unhandled EoE protocol type from slave: %u Protocol: %u, Type: %x\n", + datagram_slave_addr, datagram_mbox_prot, eoe_type); + // copy instead received data into the datagram memory. + memcpy(datagram->data, cur_data, data_size); + break; + } + break; #endif - case EC_MBOX_TYPE_COE: - if ((slave->mbox_coe_data.data) && (data_size <= slave->mbox_coe_data.data_size)) { - memcpy(slave->mbox_coe_data.data, cur_data, data_size); - slave->mbox_coe_data.payload_size = data_size; + case EC_MBOX_TYPE_COE: + if ((slave->mbox_coe_data.data) && (data_size <= slave->mbox_coe_data.data_size)) { + memcpy(slave->mbox_coe_data.data, cur_data, data_size); + slave->mbox_coe_data.payload_size = data_size; + } + break; + case EC_MBOX_TYPE_FOE: + if ((slave->mbox_foe_data.data) && (data_size <= slave->mbox_foe_data.data_size)) { + memcpy(slave->mbox_foe_data.data, cur_data, data_size); + slave->mbox_foe_data.payload_size = data_size; + } + break; + case EC_MBOX_TYPE_SOE: + if ((slave->mbox_soe_data.data) && (data_size <= slave->mbox_soe_data.data_size)) { + memcpy(slave->mbox_soe_data.data, cur_data, data_size); + slave->mbox_soe_data.payload_size = data_size; + } + break; + case EC_MBOX_TYPE_VOE: + if ((slave->mbox_voe_data.data) && (data_size <= slave->mbox_voe_data.data_size)) { + memcpy(slave->mbox_voe_data.data, cur_data, data_size); + slave->mbox_voe_data.payload_size = data_size; + } + break; + default: + EC_MASTER_DBG(master, 1, "Unknown mailbox protocol from slave: %u Protocol: %u\n", datagram_slave_addr, datagram_mbox_prot); + // copy instead received data into the datagram memory. + memcpy(datagram->data, cur_data, data_size); + break; } - break; - case EC_MBOX_TYPE_FOE: - if ((slave->mbox_foe_data.data) && (data_size <= slave->mbox_foe_data.data_size)) { - memcpy(slave->mbox_foe_data.data, cur_data, data_size); - slave->mbox_foe_data.payload_size = data_size; - } - break; - case EC_MBOX_TYPE_SOE: - if ((slave->mbox_soe_data.data) && (data_size <= slave->mbox_soe_data.data_size)) { - memcpy(slave->mbox_soe_data.data, cur_data, data_size); - slave->mbox_soe_data.payload_size = data_size; - } - break; - case EC_MBOX_TYPE_VOE: - if ((slave->mbox_voe_data.data) && (data_size <= slave->mbox_voe_data.data_size)) { - memcpy(slave->mbox_voe_data.data, cur_data, data_size); - slave->mbox_voe_data.payload_size = data_size; - } - break; - default: - EC_MASTER_DBG(master, 1, "Unknown mailbox protocol from slave: %u Protocol: %u\n", datagram_slave_addr, datagram_mbox_prot); + } else { // copy instead received data into the datagram memory. memcpy(datagram->data, cur_data, data_size); - break; } } else { // copy instead received data into the datagram memory. @@ -1405,7 +1410,6 @@ void ec_master_output_stats(ec_master_t *master /**< EtherCAT master */) { if (unlikely(jiffies - master->stats.output_jiffies >= HZ)) { master->stats.output_jiffies = jiffies; - if (master->stats.timeouts) { EC_MASTER_WARN(master, "%u datagram%s TIMED OUT!\n", master->stats.timeouts, diff --git a/master/slave.c b/master/slave.c index 46c73228..5a61d99d 100644 --- a/master/slave.c +++ b/master/slave.c @@ -176,6 +176,8 @@ void ec_slave_init( ec_mbox_data_init(&slave->mbox_foe_data); ec_mbox_data_init(&slave->mbox_soe_data); ec_mbox_data_init(&slave->mbox_voe_data); + + slave->valid_mbox_data = 0; } diff --git a/master/slave.h b/master/slave.h index 5eb25276..6fe5da5c 100644 --- a/master/slave.h +++ b/master/slave.h @@ -268,6 +268,8 @@ struct ec_slave ec_mbox_data_t mbox_foe_data; /**< Received mailbox data for FoE. */ ec_mbox_data_t mbox_soe_data; /**< Received mailbox data for SoE. */ ec_mbox_data_t mbox_voe_data; /**< Received mailbox data for VoE. */ + + uint8_t valid_mbox_data; /**< Received mailbox data is valid. */ }; /*****************************************************************************/ From 1124a8b35996d567d8b4ea99d9597a1c10a1a544 Mon Sep 17 00:00:00 2001 From: Knud Baastrup Date: Mon, 11 Aug 2014 08:19:38 +0200 Subject: [PATCH 2/7] Applied base-0023-Skip-output-statistics-during-re-scan Skip output statistics during re-scan. No reason to write output statistics in syslog when issuing a slave scanning where UNMATCHED datagrams are expected behavior. --- master/master.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/master/master.c b/master/master.c index a2a02dc8..af28eea5 100644 --- a/master/master.c +++ b/master/master.c @@ -1409,24 +1409,26 @@ void ec_master_receive_datagrams( void ec_master_output_stats(ec_master_t *master /**< EtherCAT master */) { if (unlikely(jiffies - master->stats.output_jiffies >= HZ)) { - master->stats.output_jiffies = jiffies; - if (master->stats.timeouts) { - EC_MASTER_WARN(master, "%u datagram%s TIMED OUT!\n", - master->stats.timeouts, - master->stats.timeouts == 1 ? "" : "s"); - master->stats.timeouts = 0; - } - if (master->stats.corrupted) { - EC_MASTER_WARN(master, "%u frame%s CORRUPTED!\n", - master->stats.corrupted, - master->stats.corrupted == 1 ? "" : "s"); - master->stats.corrupted = 0; - } - if (master->stats.unmatched) { - EC_MASTER_WARN(master, "%u datagram%s UNMATCHED!\n", - master->stats.unmatched, - master->stats.unmatched == 1 ? "" : "s"); - master->stats.unmatched = 0; + if (!master->scan_busy || (master->debug_level > 0)) { + master->stats.output_jiffies = jiffies; + if (master->stats.timeouts) { + EC_MASTER_WARN(master, "%u datagram%s TIMED OUT!\n", + master->stats.timeouts, + master->stats.timeouts == 1 ? "" : "s"); + master->stats.timeouts = 0; + } + if (master->stats.corrupted) { + EC_MASTER_WARN(master, "%u frame%s CORRUPTED!\n", + master->stats.corrupted, + master->stats.corrupted == 1 ? "" : "s"); + master->stats.corrupted = 0; + } + if (master->stats.unmatched) { + EC_MASTER_WARN(master, "%u datagram%s UNMATCHED!\n", + master->stats.unmatched, + master->stats.unmatched == 1 ? "" : "s"); + master->stats.unmatched = 0; + } } } } From ba2781922162eca6c10c7cc72a7b4e52e3359f26 Mon Sep 17 00:00:00 2001 From: Knud Baastrup Date: Thu, 21 Aug 2014 15:11:28 +0200 Subject: [PATCH 3/7] Applied base-0024-Sdo-directory-now-only-fetched-on-request Sdo directory now only fetched on request. The time-consuming SDO directory fetch during slave scan can now be skipped by setting the EC_SKIP_SDO_DICT in globals.h. The directory will now instead be fethed the first time an ethercat sdos command is executed with the ethercat tool. --- configure.ac | 29 ++++++++++ master/Kbuild.in | 3 +- master/Makefile.am | 3 +- master/dict_request.c | 62 +++++++++++++++++++++ master/dict_request.h | 60 ++++++++++++++++++++ master/fsm_master.c | 4 ++ master/fsm_slave.c | 122 +++++++++++++++++++++++++++++++++++++++++ master/fsm_slave.h | 2 + master/ioctl.c | 25 +++++++++ master/ioctl.h | 10 +++- master/master.c | 54 ++++++++++++++++++ master/master.h | 2 + master/slave.c | 10 ++++ master/slave.h | 1 + tool/CommandSdos.cpp | 15 +++++ tool/CommandUpload.cpp | 6 +- tool/MasterDevice.cpp | 11 ++++ tool/MasterDevice.h | 1 + 18 files changed, 415 insertions(+), 5 deletions(-) create mode 100644 master/dict_request.c create mode 100644 master/dict_request.h diff --git a/configure.ac b/configure.ac index a0483210..1d93e77f 100644 --- a/configure.ac +++ b/configure.ac @@ -1185,6 +1185,35 @@ esac AM_CONDITIONAL(HAVE_SYSTEMD, test "x$with_systemdsystemunitdir" != "x") AC_SUBST(systemdsystemunitdir,[$with_systemdsystemunitdir]) +#------------------------------------------------------------------------------ +# Skip SDO dictionary during slave scan +#------------------------------------------------------------------------------ + +AC_MSG_CHECKING([whether to skip SDO dictionary during slave scan]) + +AC_ARG_ENABLE([skip-sdo-dict], + AS_HELP_STRING([--enable-skip-sdo-dict], + [Enable skip SDO dictionary (default: no)]), + [ + case "${enableval}" in + yes) skipsdodict=1 + ;; + no) skipsdodict=0 + ;; + *) AC_MSG_ERROR([Invalid value for --enable-skip-sdo-dict]) + ;; + esac + ], + [skipsdodict=0] +) + +if test "x${skipsdodict}" = "x1"; then + AC_DEFINE([EC_SKIP_SDO_DICT], [1], [Skip SDO dictionary during slave scan]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + #------------------------------------------------------------------------------ AC_CONFIG_FILES([ diff --git a/master/Kbuild.in b/master/Kbuild.in index f2bb094c..507c45e3 100644 --- a/master/Kbuild.in +++ b/master/Kbuild.in @@ -71,7 +71,8 @@ ec_master-objs := \ soe_request.o \ sync.o \ sync_config.o \ - voe_handler.o + voe_handler.o \ + dict_request.o ifeq (@ENABLE_EOE@,1) ec_master-objs += eoe_request.o diff --git a/master/Makefile.am b/master/Makefile.am index 382fab77..32300e7d 100644 --- a/master/Makefile.am +++ b/master/Makefile.am @@ -76,6 +76,7 @@ noinst_HEADERS = \ soe_request.c soe_request.h \ sync.c sync.h \ sync_config.c sync_config.h \ - voe_handler.c voe_handler.h + voe_handler.c voe_handler.h \ + dict_request.c dict_request.h #------------------------------------------------------------------------------ diff --git a/master/dict_request.c b/master/dict_request.c new file mode 100644 index 00000000..b7ee66b7 --- /dev/null +++ b/master/dict_request.c @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2008 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. + * + *****************************************************************************/ + +/** \file + * Canopen over EtherCAT dictionary request functions. + */ + +/*****************************************************************************/ + +#include "dict_request.h" + + +/*****************************************************************************/ + +/** Dictionary request constructor. + */ +void ec_dict_request_init(ec_dict_request_t *req) +{ + req->state = EC_INT_REQUEST_INIT; +} + +/*****************************************************************************/ + +void ec_dict_request_read(ec_dict_request_t *req) +{ + req->state = EC_INT_REQUEST_QUEUED; +} + +/*****************************************************************************/ + +/** \cond */ + + +/** \endcond */ + +/*****************************************************************************/ diff --git a/master/dict_request.h b/master/dict_request.h new file mode 100644 index 00000000..7228cc9b --- /dev/null +++ b/master/dict_request.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2008 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. + * + *****************************************************************************/ + +/** + \file + EtherCAT CANopen dictionary request structure. +*/ + +/*****************************************************************************/ + +#ifndef __EC_DICT_REQUEST_H__ +#define __EC_DICT_REQUEST_H__ + +#include + +#include "globals.h" + +/*****************************************************************************/ + +/** CANopen dictionary request. + */ +typedef struct { + struct list_head list; /**< List item. */ + ec_internal_request_state_t state; /**< SDO request state. */ +} ec_dict_request_t; + +/*****************************************************************************/ + +void ec_dict_request_init(ec_dict_request_t *); +void ec_dict_request_read(ec_dict_request_t *); + +/*****************************************************************************/ + +#endif diff --git a/master/fsm_master.c b/master/fsm_master.c index 47ddb94d..caeb5d53 100644 --- a/master/fsm_master.c +++ b/master/fsm_master.c @@ -584,6 +584,7 @@ void ec_fsm_master_action_idle( for (slave = master->slaves; slave < master->slaves + master->slave_count; slave++) { +#ifndef EC_SKIP_SDO_DICT if (!(slave->sii.mailbox_protocols & EC_MBOX_COE) || (slave->sii.has_general && !slave->sii.coe_details.enable_sdo_info) @@ -596,8 +597,10 @@ void ec_fsm_master_action_idle( || (slave->sii.has_general && !slave->sii.coe_details.enable_sdo_info) ){ +#endif // SDO info not supported. Enable processing of requests ec_fsm_slave_set_ready(&slave->fsm); +#ifndef EC_SKIP_SDO_DICT } continue; } @@ -614,6 +617,7 @@ void ec_fsm_master_action_idle( ec_fsm_coe_exec(&fsm->fsm_coe, fsm->datagram); // execute immediately fsm->datagram->device_index = fsm->slave->device_index; return; +#endif } // check for pending SII write operations. diff --git a/master/fsm_slave.c b/master/fsm_slave.c index ac09aeda..dedd06fb 100644 --- a/master/fsm_slave.c +++ b/master/fsm_slave.c @@ -56,6 +56,8 @@ void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *, ec_datagram_t *); int ec_fsm_slave_action_process_eoe(ec_fsm_slave_t *, ec_datagram_t *); void ec_fsm_slave_state_eoe_request(ec_fsm_slave_t *, ec_datagram_t *); #endif +int ec_fsm_slave_action_process_dict(ec_fsm_slave_t *, ec_datagram_t *); +void ec_fsm_slave_state_dict_request(ec_fsm_slave_t *, ec_datagram_t *); /*****************************************************************************/ @@ -249,6 +251,11 @@ void ec_fsm_slave_state_ready( return; } #endif + + // Check for pending dictionary requests + if (ec_fsm_slave_action_process_dict(fsm, datagram)) { + return; + } } /*****************************************************************************/ @@ -618,6 +625,121 @@ void ec_fsm_slave_state_soe_request( fsm->state = ec_fsm_slave_state_ready; } +/*****************************************************************************/ + +/** Check for pending dictionary requests and process one. + * + * \return non-zero, if a request is processed. + */ +int ec_fsm_slave_action_process_dict( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_dict_request_t *request; + + if (list_empty(&slave->dict_requests)) { + return 0; + } + + // take the first request to be processed + request = list_entry(slave->dict_requests.next, ec_dict_request_t, list); + list_del_init(&request->list); // dequeue + + if (!(slave->sii.mailbox_protocols & EC_MBOX_COE) + || (slave->sii.has_general + && !slave->sii.coe_details.enable_sdo_info)) + { + EC_SLAVE_INFO(slave, "Aborting dictionary request," + " slave does not support SDO Info.\n"); + request->state = EC_INT_REQUEST_SUCCESS; + wake_up_all(&slave->master->request_queue); + fsm->dict_request = NULL; + fsm->state = ec_fsm_slave_state_ready; + return 1; + } + + if (slave->sdo_dictionary_fetched) + { + EC_SLAVE_DBG(slave, 1, "Aborting dictionary request," + " dictionary already uploaded.\n"); + request->state = EC_INT_REQUEST_SUCCESS; + wake_up_all(&slave->master->request_queue); + fsm->dict_request = NULL; + fsm->state = ec_fsm_slave_state_ready; + return 1; + } + + if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { + EC_SLAVE_WARN(slave, "Aborting dictionary request," + " slave has error flag set.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 1; + } + + if (slave->current_state == EC_SLAVE_STATE_INIT) { + EC_SLAVE_WARN(slave, "Aborting dictioanry request, slave is in INIT.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 1; + } + + fsm->dict_request = request; + request->state = EC_INT_REQUEST_BUSY; + + // Found pending dictionary request. Execute it! + EC_SLAVE_DBG(slave, 1, "Processing dictionary request...\n"); + + // Start dictionary transfer + fsm->state = ec_fsm_slave_state_dict_request; + ec_fsm_coe_dictionary(&fsm->fsm_coe, slave); + ec_fsm_coe_exec(&fsm->fsm_coe, datagram); // execute immediately + return 1; +} + +/*****************************************************************************/ + +/** Slave state: DICT_REQUEST. + */ +void ec_fsm_slave_state_dict_request( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_dict_request_t *request = fsm->dict_request; + + if (ec_fsm_coe_exec(&fsm->fsm_coe, datagram)) { + return; + } + + if (!ec_fsm_coe_success(&fsm->fsm_coe)) { + EC_SLAVE_ERR(slave, "Failed to process dictionary request.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->dict_request = NULL; + fsm->state = ec_fsm_slave_state_ready; + return; + } + + EC_SLAVE_DBG(slave, 1, "Finished dictionary request.\n"); + + // Dictionary request finished + slave->sdo_dictionary_fetched = 1; + + // attach pdo names from dictionary + ec_slave_attach_pdo_names(slave); + + request->state = EC_INT_REQUEST_SUCCESS; + wake_up_all(&slave->master->request_queue); + fsm->dict_request = NULL; + fsm->state = ec_fsm_slave_state_ready; +} + /*****************************************************************************/ #ifdef EC_EOE /** Check for pending EoE IP parameter requests and process one. diff --git a/master/fsm_slave.h b/master/fsm_slave.h index acc9ee2e..ae0a63a9 100644 --- a/master/fsm_slave.h +++ b/master/fsm_slave.h @@ -42,6 +42,7 @@ #include "sdo_request.h" #include "reg_request.h" #include "eoe_request.h" +#include "dict_request.h" #include "fsm_coe.h" #include "fsm_foe.h" #include "fsm_soe.h" @@ -69,6 +70,7 @@ struct ec_fsm_slave { #ifdef EC_EOE ec_eoe_request_t *eoe_request; /**< EoE request to process. */ #endif + ec_dict_request_t *dict_request; /**< Dictionary request to process. */ ec_fsm_coe_t fsm_coe; /**< CoE state machine. */ ec_fsm_foe_t fsm_foe; /**< FoE state machine. */ diff --git a/master/ioctl.c b/master/ioctl.c index c3b7896f..a768854e 100755 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -4622,6 +4622,28 @@ static ATTRIBUTES int ec_ioctl_slave_soe_write( return retval; } +/*****************************************************************************/ +/** Upload Dictionary. + * + * \return Zero on success, otherwise a negative error code. + */ +static ATTRIBUTES int ec_ioctl_slave_dict_upload( + ec_master_t *master, /**< EtherCAT master. */ + void *arg /**< ioctl() argument. */ + ) +{ + ec_ioctl_slave_dict_upload_t data; + int ret; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + return -EFAULT; + } + + ret = ec_master_dict_upload(master, data.slave_position); + + return ret; +} + /*****************************************************************************/ /** ioctl() function to use. @@ -5196,6 +5218,9 @@ long EC_IOCTL( } ret = ec_ioctl_set_send_interval(master, arg, ctx); break; + case EC_IOCTL_SLAVE_DICT_UPLOAD: + ret = ec_ioctl_slave_dict_upload(master, arg); + break; default: ret = -ENOTTY; break; diff --git a/master/ioctl.h b/master/ioctl.h index cec73aba..32161715 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -47,7 +47,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 38 +#define EC_IOCTL_VERSION_MAGIC 39 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -86,6 +86,7 @@ #ifdef EC_EOE #define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1f, ec_ioctl_eoe_handler_t) #endif +#define EC_IOCTL_SLAVE_DICT_UPLOAD EC_IOW(0x7f, ec_ioctl_slave_dict_upload_t) // Application interface #define EC_IOCTL_REQUEST EC_IO(0x20) @@ -812,6 +813,13 @@ typedef struct { /*****************************************************************************/ +typedef struct { + // inputs + uint16_t slave_position; +} ec_ioctl_slave_dict_upload_t; + +/*****************************************************************************/ + #ifdef __KERNEL__ /** Context data structure for file handles. diff --git a/master/master.c b/master/master.c index af28eea5..52db0400 100644 --- a/master/master.c +++ b/master/master.c @@ -2424,6 +2424,60 @@ void ec_master_request_op( #endif } +/*****************************************************************************/ + +int ec_master_dict_upload(ec_master_t *master, uint16_t slave_position) +{ + ec_dict_request_t request; + ec_slave_t *slave; + int ret = 0; + + EC_MASTER_DBG(master, 1, "%s(master = 0x%p, slave_position = %u\n", + __func__, master, slave_position); + + ec_dict_request_init(&request); + ec_dict_request_read(&request); + + if (ec_lock_down_interruptible(&master->master_sem)) { + return -EINTR; + } + + if (!(slave = ec_master_find_slave(master, 0, slave_position))) { + ec_lock_up(&master->master_sem); + EC_MASTER_ERR(master, "Slave %u does not exist!\n", slave_position); + return -EINVAL; + } + + EC_SLAVE_DBG(slave, 1, "Scheduling dictionary upload request.\n"); + + // schedule request. + list_add_tail(&request.list, &slave->dict_requests); + + ec_lock_up(&master->master_sem); + + // wait for processing through FSM + if (wait_event_interruptible(master->request_queue, + request.state != EC_INT_REQUEST_QUEUED)) { + // interrupted by signal + ec_lock_down(&master->master_sem); + if (request.state == EC_INT_REQUEST_QUEUED) { + list_del(&request.list); + ec_lock_up(&master->master_sem); + return -EINTR; + } + // request already processing: interrupt not possible. + ec_lock_up(&master->master_sem); + } + + // wait until master FSM has finished processing + wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); + + if (request.state != EC_INT_REQUEST_SUCCESS) { + ret = -EIO; + } + return ret; +} + /****************************************************************************** * Application interface *****************************************************************************/ diff --git a/master/master.h b/master/master.h index 9541df5b..9ecfc8e2 100644 --- a/master/master.h +++ b/master/master.h @@ -384,6 +384,8 @@ void ec_master_request_op(ec_master_t *); void ec_master_internal_send_cb(void *); void ec_master_internal_receive_cb(void *); +int ec_master_dict_upload(ec_master_t *, uint16_t); + extern const unsigned int rate_intervals[EC_RATE_COUNT]; // see master.c /*****************************************************************************/ diff --git a/master/slave.c b/master/slave.c index 5a61d99d..22844a8d 100644 --- a/master/slave.c +++ b/master/slave.c @@ -161,6 +161,7 @@ void ec_slave_init( INIT_LIST_HEAD(&slave->foe_requests); INIT_LIST_HEAD(&slave->soe_requests); INIT_LIST_HEAD(&slave->eoe_requests); + INIT_LIST_HEAD(&slave->dict_requests); // create state machine object ec_fsm_slave_init(&slave->fsm, slave); @@ -273,6 +274,15 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */) request->state = EC_INT_REQUEST_FAILURE; } + while (!list_empty(&slave->dict_requests)) { + ec_dict_request_t *request = + list_entry(slave->dict_requests.next, ec_dict_request_t, list); + list_del_init(&request->list); // dequeue + EC_SLAVE_WARN(slave, "Discarding dictionary request," + " slave about to be deleted.\n"); + request->state = EC_INT_REQUEST_FAILURE; + } + wake_up_all(&slave->master->request_queue); if (slave->config) { diff --git a/master/slave.h b/master/slave.h index 6fe5da5c..5c85a048 100644 --- a/master/slave.h +++ b/master/slave.h @@ -254,6 +254,7 @@ struct ec_slave struct list_head foe_requests; /**< FoE requests. */ struct list_head soe_requests; /**< SoE requests. */ struct list_head eoe_requests; /**< EoE set IP parameter requests. */ + struct list_head dict_requests; /**< Dictionary read requests. */ ec_fsm_slave_t fsm; /**< Slave state machine. */ diff --git a/tool/CommandSdos.cpp b/tool/CommandSdos.cpp index a4d842fc..197def4e 100644 --- a/tool/CommandSdos.cpp +++ b/tool/CommandSdos.cpp @@ -94,6 +94,8 @@ void CommandSdos::execute(const StringVector &args) SlaveList::const_iterator si; bool showHeader, multiMaster; + ec_ioctl_slave_dict_upload_t data; + if (args.size()) { stringstream err; err << "'" << getName() << "' takes no arguments!"; @@ -108,6 +110,19 @@ void CommandSdos::execute(const StringVector &args) MasterDevice m(*mi); m.open(MasterDevice::Read); slaves = selectedSlaves(m); + for (si = slaves.begin(); si != slaves.end(); si++) { + if (si->coe_details.enable_sdo_info) { + data.slave_position = si->position; + try { + m.dictUpload(&data); + } catch (MasterDeviceException &e) { + throw e; + } + } + } + m.close(); + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); showHeader = multiMaster || slaves.size() > 1; for (si = slaves.begin(); si != slaves.end(); si++) { diff --git a/tool/CommandUpload.cpp b/tool/CommandUpload.cpp index 439eeab3..affe52ac 100644 --- a/tool/CommandUpload.cpp +++ b/tool/CommandUpload.cpp @@ -134,13 +134,15 @@ void CommandUpload::execute(const StringVector &args) data.sdo_index, data.sdo_entry_subindex); } catch (MasterDeviceException &e) { err << "Failed to determine SDO entry data type. " - << "Please specify --type."; + << "Please specify --type or fetch directory " + << "with ethercat sdos command."; throwCommandException(err); } if (!(dataType = findDataType(entry.data_type))) { err << "PDO entry has unknown data type 0x" << hex << setfill('0') << setw(4) << entry.data_type << "!" - << " Please specify --type."; + << " Please specify --type or fetch directory " + << "with ethercat sdos command.";; throwCommandException(err); } } diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index d5faa524..b9e2c473 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -536,6 +536,17 @@ void MasterDevice::sdoUpload(ec_ioctl_slave_sdo_upload_t *data) /****************************************************************************/ +void MasterDevice::dictUpload(ec_ioctl_slave_dict_upload_t *data) +{ + if (ioctl(fd, EC_IOCTL_SLAVE_DICT_UPLOAD, data) < 0) { + stringstream err; + err << "Failed to upload dictionary: " << strerror(errno); + throw MasterDeviceException(err); + } +} + +/****************************************************************************/ + void MasterDevice::requestState( uint16_t slavePosition, uint8_t state diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index 0684fc9e..9958a413 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -164,6 +164,7 @@ class MasterDevice #endif void readSoe(ec_ioctl_slave_soe_read_t *); void writeSoe(ec_ioctl_slave_soe_write_t *); + void dictUpload(ec_ioctl_slave_dict_upload_t *); unsigned int getMasterCount() const {return masterCount;} From 1267e45bf887ea7e0619767001ac7ce75be0de37 Mon Sep 17 00:00:00 2001 From: Knud Baastrup Date: Thu, 30 Oct 2014 08:47:27 +0100 Subject: [PATCH 4/7] Applied base-0025-Ignore-mailbox-settings-if-corrupted-sii-file Ignore SII specified mailbox settings if they appear to be from a blank EEPROM. --- master/fsm_slave_scan.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/master/fsm_slave_scan.c b/master/fsm_slave_scan.c index 66a7795d..643419c6 100644 --- a/master/fsm_slave_scan.c +++ b/master/fsm_slave_scan.c @@ -776,6 +776,23 @@ void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm " Disabling mailbox communication."); } + // clear mailbox settings if invalid values due to invalid sii file + if ((slave->sii.boot_rx_mailbox_offset == 0xFFFF) || + (slave->sii.boot_tx_mailbox_offset == 0xFFFF) || + (slave->sii.std_rx_mailbox_offset == 0xFFFF) || + (slave->sii.std_tx_mailbox_offset == 0xFFFF)) { + slave->sii.boot_rx_mailbox_offset = 0; + slave->sii.boot_tx_mailbox_offset = 0; + slave->sii.boot_rx_mailbox_size = 0; + slave->sii.boot_tx_mailbox_size = 0; + slave->sii.std_rx_mailbox_offset = 0; + slave->sii.std_tx_mailbox_offset = 0; + slave->sii.std_rx_mailbox_size = 0; + slave->sii.std_tx_mailbox_size = 0; + slave->sii.mailbox_protocols = 0; + EC_SLAVE_ERR(slave, "Unexpected mailbox offset in SII data.\n"); + } + if (slave->sii_nwords == EC_FIRST_SII_CATEGORY_OFFSET) { // sii does not contain category data fsm->state = ec_fsm_slave_scan_state_end; From ff2e062a08e19149f498bbee0c9feb4f2991a9c6 Mon Sep 17 00:00:00 2001 From: Knud Baastrup Date: Fri, 10 Jul 2015 12:46:37 +0200 Subject: [PATCH 5/7] Applied base-0026-EoE-processing-is-now-only-allowed-in-state-PREOP EoE is disabled in INIT, BOOT, and invalid states to prevent errors. --- master/master.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/master/master.c b/master/master.c index 52db0400..0bf44ddb 100644 --- a/master/master.c +++ b/master/master.c @@ -1901,12 +1901,16 @@ static int ec_master_eoe_thread(void *priv_data) // actual EoE processing sth_to_send = 0; list_for_each_entry(eoe, &master->eoe_handlers, list) { - ec_eoe_run(eoe); - if (eoe->queue_datagram) { - sth_to_send = 1; - } - if (!ec_eoe_is_idle(eoe)) { - all_idle = 0; + if ((eoe->slave->current_state == EC_SLAVE_STATE_PREOP) || + (eoe->slave->current_state == EC_SLAVE_STATE_SAFEOP) || + (eoe->slave->current_state == EC_SLAVE_STATE_OP)) { + ec_eoe_run(eoe); + if (eoe->queue_datagram) { + sth_to_send = 1; + } + if (!ec_eoe_is_idle(eoe)) { + all_idle = 0; + } } } From d3e853514f86cfaa1555415a99e52f72785feccc Mon Sep 17 00:00:00 2001 From: Gavin Lambert Date: Wed, 1 Jun 2016 09:55:24 +0200 Subject: [PATCH 6/7] Applied base-0027-Prevent abandoning the mailbox state machines early Fixup for f943348d - caused deadlock. Fixes the exit condition of the mailbox FSMs -- previously they returned whether they were sending a datagram or not, and the parent assumed that this meant they were done if they didn't want to send a datagram. Since earlier patches can cause idle cycles now, this could cause unexpected early exit, so they now return whether they're complete or not explicitly. --- master/fsm_coe.c | 21 ++++++++++----------- master/fsm_eoe.c | 20 ++++++++++---------- master/fsm_foe.c | 20 ++++++++++---------- master/fsm_soe.c | 20 ++++++++++---------- 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/master/fsm_coe.c b/master/fsm_coe.c index 1d3f4719..f9620c34 100644 --- a/master/fsm_coe.c +++ b/master/fsm_coe.c @@ -230,35 +230,34 @@ void ec_fsm_coe_transfer( /** Executes the current state of the state machine. * - * \return 1 if the datagram was used, else 0. + * \return 1 if the state machine is still in progress, else 0. */ int ec_fsm_coe_exec( ec_fsm_coe_t *fsm, /**< Finite state machine. */ ec_datagram_t *datagram /**< Datagram to use. */ ) { - int datagram_used = 0; - + if (fsm->state == ec_fsm_coe_end || fsm->state == ec_fsm_coe_error) + return 0; if (fsm->datagram && (fsm->datagram->state == EC_DATAGRAM_INIT || fsm->datagram->state == EC_DATAGRAM_QUEUED || fsm->datagram->state == EC_DATAGRAM_SENT)) { // datagram not received yet - return datagram_used; + if (datagram != fsm->datagram) + datagram->state = EC_DATAGRAM_INVALID; + return 1; } fsm->state(fsm, datagram); - datagram_used = - fsm->state != ec_fsm_coe_end && fsm->state != ec_fsm_coe_error; - - if (datagram_used) { - fsm->datagram = datagram; - } else { + if (fsm->state == ec_fsm_coe_end || fsm->state == ec_fsm_coe_error) { fsm->datagram = NULL; + return 0; } - return datagram_used; + fsm->datagram = datagram; + return 1; } /*****************************************************************************/ diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c index d1f3dc23..a4a37ec1 100644 --- a/master/fsm_eoe.c +++ b/master/fsm_eoe.c @@ -101,35 +101,35 @@ void ec_fsm_eoe_set_ip_param( /** Executes the current state of the state machine. * - * \return 1 if the datagram was used, else 0. + * \return 1 if the state machine is still in progress, else 0. */ int ec_fsm_eoe_exec( ec_fsm_eoe_t *fsm, /**< finite state machine */ ec_datagram_t *datagram /**< Datagram to use. */ ) { - int datagram_used = 0; + if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error) + return 0; if (fsm->datagram && (fsm->datagram->state == EC_DATAGRAM_INIT || fsm->datagram->state == EC_DATAGRAM_QUEUED || fsm->datagram->state == EC_DATAGRAM_SENT)) { // datagram not received yet - return datagram_used; + if (datagram != fsm->datagram) + datagram->state = EC_DATAGRAM_INVALID; + return 1; } fsm->state(fsm, datagram); - datagram_used = - fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error; - - if (datagram_used) { - fsm->datagram = datagram; - } else { + if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error) { fsm->datagram = NULL; + return 0; } - return datagram_used; + fsm->datagram = datagram; + return 1; } /*****************************************************************************/ diff --git a/master/fsm_foe.c b/master/fsm_foe.c index debd17c9..1ce7b7aa 100644 --- a/master/fsm_foe.c +++ b/master/fsm_foe.c @@ -123,35 +123,35 @@ void ec_fsm_foe_clear(ec_fsm_foe_t *fsm /**< finite state machine */) /** Executes the current state of the state machine. * - * \return 1, if the datagram was used, else 0. + * \return 1 if the state machine is still in progress, else 0. */ int ec_fsm_foe_exec( ec_fsm_foe_t *fsm, /**< finite state machine */ ec_datagram_t *datagram /**< Datagram to use. */ ) { - int datagram_used = 0; + if (fsm->state == ec_fsm_foe_end || fsm->state == ec_fsm_foe_error) + return 0; if (fsm->datagram && (fsm->datagram->state == EC_DATAGRAM_INIT || fsm->datagram->state == EC_DATAGRAM_QUEUED || fsm->datagram->state == EC_DATAGRAM_SENT)) { // datagram not received yet - return datagram_used; + if (datagram != fsm->datagram) + datagram->state = EC_DATAGRAM_INVALID; + return 1; } fsm->state(fsm, datagram); - datagram_used = - fsm->state != ec_fsm_foe_end && fsm->state != ec_fsm_foe_error; - - if (datagram_used) { - fsm->datagram = datagram; - } else { + if (fsm->state == ec_fsm_foe_end || fsm->state == ec_fsm_foe_error) { fsm->datagram = NULL; + return 0; } - return datagram_used; + fsm->datagram = datagram; + return 1; } /*****************************************************************************/ diff --git a/master/fsm_soe.c b/master/fsm_soe.c index e7cbadff..cd904a72 100644 --- a/master/fsm_soe.c +++ b/master/fsm_soe.c @@ -147,35 +147,35 @@ void ec_fsm_soe_transfer( /** Executes the current state of the state machine. * - * \return 1 if the datagram was used, else 0. + * \return 1 if the state machine is still in progress, else 0. */ int ec_fsm_soe_exec( ec_fsm_soe_t *fsm, /**< finite state machine */ ec_datagram_t *datagram /**< Datagram to use. */ ) { - int datagram_used = 0; + if (fsm->state == ec_fsm_soe_end || fsm->state == ec_fsm_soe_error) + return 0; if (fsm->datagram && (fsm->datagram->state == EC_DATAGRAM_INIT || fsm->datagram->state == EC_DATAGRAM_QUEUED || fsm->datagram->state == EC_DATAGRAM_SENT)) { // datagram not received yet - return datagram_used; + if (datagram != fsm->datagram) + datagram->state = EC_DATAGRAM_INVALID; + return 1; } fsm->state(fsm, datagram); - datagram_used = - fsm->state != ec_fsm_soe_end && fsm->state != ec_fsm_soe_error; - - if (datagram_used) { - fsm->datagram = datagram; - } else { + if (fsm->state == ec_fsm_soe_end || fsm->state == ec_fsm_soe_error) { fsm->datagram = NULL; + return 0; } - return datagram_used; + fsm->datagram = datagram; + return 1; } /*****************************************************************************/ From 2c1597231d0bfba6f8ffcf06dd29147e928eecb9 Mon Sep 17 00:00:00 2001 From: Graeme Foot Date: Tue, 21 May 2019 18:26:31 +1200 Subject: [PATCH 7/7] Applied base-0028-ec_master_exec_slave_fsms-external-datagram-fix Slaves can fail to correctly read their SII information, leading to zero or corrupted SII information. This leads to slaves that remain in PREOP or SAFEOP. This is caused by the cached external (slave) datagrams being cycled through too quickly due to being marked as consumed when they are not. Datagrams can then be lost or incorrectly shared between multiple slaves as the ring returns a datagram that is still in use by a read SII call. This may also occur if multiple services are contending for a slaves mailbox. I have not added checks into ec_master_get_external_datagram() to check that a returned datagram is not currently in use. --- master/master.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/master/master.c b/master/master.c index 0bf44ddb..282f5452 100644 --- a/master/master.c +++ b/master/master.c @@ -1634,13 +1634,15 @@ void ec_master_exec_slave_fsms( fsm->slave->ring_position); #endif if (ec_fsm_slave_exec(fsm, datagram)) { - // FSM consumed datagram + if (datagram->state != EC_DATAGRAM_INVALID) { + // FSM consumed datagram #if DEBUG_INJECT - EC_MASTER_DBG(master, 1, "FSM consumed datagram %s\n", - datagram->name); + EC_MASTER_DBG(master, 1, "FSM consumed datagram %s\n", + datagram->name); #endif - master->ext_ring_idx_fsm = - (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; + master->ext_ring_idx_fsm = + (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; + } } else { // FSM finished @@ -1660,8 +1662,10 @@ void ec_master_exec_slave_fsms( datagram = ec_master_get_external_datagram(master); if (ec_fsm_slave_exec(&master->fsm_slave->fsm, datagram)) { - master->ext_ring_idx_fsm = - (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; + if (datagram->state != EC_DATAGRAM_INVALID) { + master->ext_ring_idx_fsm = + (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; + } list_add_tail(&master->fsm_slave->fsm.list, &master->fsm_exec_list); master->fsm_exec_count++;