Merge branch 'next-patches-from-gavins-patchset' into 'master'

More patches from Gavin Lamberts patchset

See merge request etherlab.org/ethercat!80
This commit is contained in:
Florian Pose 2023-08-29 14:40:45 +00:00
commit 775b93de5b
23 changed files with 627 additions and 133 deletions

View File

@ -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([

View File

@ -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

View File

@ -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
#------------------------------------------------------------------------------

62
master/dict_request.c Normal file
View File

@ -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 */
/*****************************************************************************/

60
master/dict_request.h Normal file
View File

@ -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 <linux/list.h>
#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

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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.
@ -1135,6 +1139,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) {

View File

@ -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.

View File

@ -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. */

View File

@ -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 *);
/*****************************************************************************/
@ -774,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;
@ -979,7 +998,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 +1069,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);
}

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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;

View File

@ -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.

View File

@ -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.
@ -1404,25 +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;
}
}
}
}
@ -1628,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
@ -1654,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++;
@ -1895,12 +1905,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;
}
}
}
@ -2418,6 +2432,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
*****************************************************************************/

View File

@ -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
/*****************************************************************************/

View File

@ -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);
@ -176,6 +177,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;
}
@ -271,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) {

View File

@ -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. */
@ -268,6 +269,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. */
};
/*****************************************************************************/

View File

@ -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++) {

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;}