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.
This commit is contained in:
Knud Baastrup 2014-08-21 15:11:28 +02:00
parent 1124a8b359
commit ba27819221
18 changed files with 415 additions and 5 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

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

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

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

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

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

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

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