mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-06 11:51:45 +08:00
Merge branch 'soe-handler' into 'stable-1.5'
New API for transferring SoE IDNs based on slave configurations (SoE requests) See merge request etherlab.org/ethercat!64
This commit is contained in:
142
include/ecrt.h
142
include/ecrt.h
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master userspace library.
|
||||
*
|
||||
@@ -43,6 +41,13 @@
|
||||
*
|
||||
* - Added the ecrt_slave_config_flag() method and the EC_HAVE_FLAGS
|
||||
* definition to check for its existence.
|
||||
* - Added SoE IDN requests, including the datatype ec_soe_request_t and the
|
||||
* methods ecrt_slave_config_create_soe_request(),
|
||||
* ecrt_soe_request_object(), ecrt_soe_request_timeout(),
|
||||
* ecrt_soe_request_data(), ecrt_soe_request_data_size(),
|
||||
* ecrt_soe_request_state(), ecrt_soe_request_write() and
|
||||
* ecrt_soe_request_read(). Use the EC_HAVE_SOE_REQUESTS to check, if the
|
||||
* functionality is available.
|
||||
*
|
||||
* Changes in version 1.5.2:
|
||||
*
|
||||
@@ -52,7 +57,7 @@
|
||||
* - Added the EC_HAVE_REDUNDANCY define, to check, if the interface contains
|
||||
* redundancy features.
|
||||
* - Added ecrt_sdo_request_index() to change SDO index and subindex after
|
||||
* handler creation.
|
||||
* request creation.
|
||||
* - Added interface for retrieving CoE emergency messages, i. e.
|
||||
* ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
|
||||
* ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
|
||||
@@ -200,6 +205,14 @@
|
||||
*/
|
||||
#define EC_HAVE_FLAGS
|
||||
|
||||
/** Defined if the methods ecrt_slave_config_create_soe_request(),
|
||||
* ecrt_soe_request_object(), ecrt_soe_request_timeout(),
|
||||
* ecrt_soe_request_data(), ecrt_soe_request_data_size(),
|
||||
* ecrt_soe_request_state(), ecrt_soe_request_write() and
|
||||
* ecrt_soe_request_read() and the datatype ec_soe_request_t are available.
|
||||
*/
|
||||
#define EC_HAVE_SOE_REQUESTS
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** End of list marker.
|
||||
@@ -254,11 +267,14 @@ typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
|
||||
struct ec_sdo_request;
|
||||
typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */
|
||||
|
||||
struct ec_soe_request;
|
||||
typedef struct ec_soe_request ec_soe_request_t; /**< \see ec_soe_request. */
|
||||
|
||||
struct ec_voe_handler;
|
||||
typedef struct ec_voe_handler ec_voe_handler_t; /**< \see ec_voe_handler. */
|
||||
|
||||
struct ec_reg_request;
|
||||
typedef struct ec_reg_request ec_reg_request_t; /**< \see ec_sdo_request. */
|
||||
typedef struct ec_reg_request ec_reg_request_t; /**< \see ec_reg_request. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -1559,6 +1575,23 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
|
||||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Create an SoE request to exchange SoE IDNs during realtime operation.
|
||||
*
|
||||
* The created SoE request object is freed automatically when the master is
|
||||
* released.
|
||||
*
|
||||
* This method has to be called in non-realtime context before
|
||||
* ecrt_master_activate().
|
||||
*
|
||||
* \return New SoE request, or NULL on error.
|
||||
*/
|
||||
ec_soe_request_t *ecrt_slave_config_create_soe_request(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint8_t drive_no, /**< Drive number. */
|
||||
uint16_t idn, /**< Sercos ID-Number. */
|
||||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Create an VoE handler to exchange vendor-specific data during realtime
|
||||
* operation.
|
||||
*
|
||||
@@ -1877,6 +1910,105 @@ void ecrt_sdo_request_read(
|
||||
ec_sdo_request_t *req /**< SDO request. */
|
||||
);
|
||||
|
||||
/*****************************************************************************
|
||||
* SoE request methods.
|
||||
****************************************************************************/
|
||||
|
||||
/** Set the request's drive and Sercos ID numbers.
|
||||
*
|
||||
* \attention If the drive number and/or IDN is changed while
|
||||
* ecrt_soe_request_state() returns EC_REQUEST_BUSY, this may lead to
|
||||
* unexpected results.
|
||||
*/
|
||||
void ecrt_soe_request_idn(
|
||||
ec_soe_request_t *req, /**< IDN request. */
|
||||
uint8_t drive_no, /**< SDO index. */
|
||||
uint16_t idn /**< SoE IDN. */
|
||||
);
|
||||
|
||||
/** Set the timeout for an SoE request.
|
||||
*
|
||||
* If the request cannot be processed in the specified time, if will be marked
|
||||
* as failed.
|
||||
*
|
||||
* The timeout is permanently stored in the request object and is valid until
|
||||
* the next call of this method.
|
||||
*/
|
||||
void ecrt_soe_request_timeout(
|
||||
ec_soe_request_t *req, /**< SoE request. */
|
||||
uint32_t timeout /**< Timeout in milliseconds. Zero means no
|
||||
timeout. */
|
||||
);
|
||||
|
||||
/** Access to the SoE request's data.
|
||||
*
|
||||
* This function returns a pointer to the request's internal IDN data memory.
|
||||
*
|
||||
* - After a read operation was successful, integer data can be evaluated
|
||||
* using the EC_READ_*() macros as usual. Example:
|
||||
* \code
|
||||
* uint16_t value = EC_READ_U16(ecrt_soe_request_data(idn_req)));
|
||||
* \endcode
|
||||
* - If a write operation shall be triggered, the data have to be written to
|
||||
* the internal memory. Use the EC_WRITE_*() macros, if you are writing
|
||||
* integer data. Be sure, that the data fit into the memory. The memory size
|
||||
* is a parameter of ecrt_slave_config_create_soe_request().
|
||||
* \code
|
||||
* EC_WRITE_U16(ecrt_soe_request_data(idn_req), 0xFFFF);
|
||||
* \endcode
|
||||
*
|
||||
* \attention The return value can be invalidated during a read operation,
|
||||
* because the internal IDN data memory could be re-allocated if the read IDN
|
||||
* data do not fit inside.
|
||||
*
|
||||
* \return Pointer to the internal IDN data memory.
|
||||
*/
|
||||
uint8_t *ecrt_soe_request_data(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
);
|
||||
|
||||
/** Returns the current IDN data size.
|
||||
*
|
||||
* When the SoE request is created, the data size is set to the size of the
|
||||
* reserved memory. After a read operation the size is set to the size of the
|
||||
* read data. The size is not modified in any other situation.
|
||||
*
|
||||
* \return IDN data size in bytes.
|
||||
*/
|
||||
size_t ecrt_soe_request_data_size(
|
||||
const ec_soe_request_t *req /**< SoE request. */
|
||||
);
|
||||
|
||||
/** Get the current state of the SoE request.
|
||||
*
|
||||
* \return Request state.
|
||||
*/
|
||||
ec_request_state_t ecrt_soe_request_state(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
);
|
||||
|
||||
/** Schedule an SoE IDN write operation.
|
||||
*
|
||||
* \attention This method may not be called while ecrt_soe_request_state()
|
||||
* returns EC_REQUEST_BUSY.
|
||||
*/
|
||||
void ecrt_soe_request_write(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
);
|
||||
|
||||
/** Schedule an SoE IDN read operation.
|
||||
*
|
||||
* \attention This method may not be called while ecrt_soe_request_state()
|
||||
* returns EC_REQUEST_BUSY.
|
||||
*
|
||||
* \attention After calling this function, the return value of
|
||||
* ecrt_soe_request_data() must be considered as invalid while
|
||||
* ecrt_soe_request_state() returns EC_REQUEST_BUSY.
|
||||
*/
|
||||
void ecrt_soe_request_read(
|
||||
ec_soe_request_t *req /**< SoE request. */
|
||||
);
|
||||
|
||||
/*****************************************************************************
|
||||
* VoE handler methods.
|
||||
****************************************************************************/
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
# Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
#
|
||||
# This file is part of the IgH EtherCAT master userspace library.
|
||||
#
|
||||
@@ -39,6 +37,7 @@ libethercat_la_SOURCES = \
|
||||
reg_request.c \
|
||||
sdo_request.c \
|
||||
slave_config.c \
|
||||
soe_request.c \
|
||||
voe_handler.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
@@ -48,6 +47,7 @@ noinst_HEADERS = \
|
||||
reg_request.h \
|
||||
sdo_request.h \
|
||||
slave_config.h \
|
||||
soe_request.h \
|
||||
voe_handler.h
|
||||
|
||||
libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir)
|
||||
@@ -70,8 +70,10 @@ libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir)
|
||||
# 1:0.0
|
||||
# ecrt_master_sync_reference_clock_to() added.
|
||||
# 2:0:1
|
||||
# SoE requests added
|
||||
# 3:0:2
|
||||
#
|
||||
libethercat_la_LDFLAGS = -version-info 2:0:1
|
||||
libethercat_la_LDFLAGS = -version-info 3:0:2
|
||||
|
||||
pkgconfig_DATA = libethercat.pc
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "slave_config.h"
|
||||
#include "domain.h"
|
||||
#include "sdo_request.h"
|
||||
#include "soe_request.h"
|
||||
#include "reg_request.h"
|
||||
#include "voe_handler.h"
|
||||
#include "master.h"
|
||||
@@ -44,6 +45,7 @@
|
||||
void ec_slave_config_clear(ec_slave_config_t *sc)
|
||||
{
|
||||
ec_sdo_request_t *r, *next_r;
|
||||
ec_soe_request_t *s, *next_s;
|
||||
ec_reg_request_t *e, *next_e;
|
||||
ec_voe_handler_t *v, *next_v;
|
||||
|
||||
@@ -56,6 +58,15 @@ void ec_slave_config_clear(ec_slave_config_t *sc)
|
||||
}
|
||||
sc->first_sdo_request = NULL;
|
||||
|
||||
s = sc->first_soe_request;
|
||||
while (r) {
|
||||
next_s = s->next;
|
||||
ec_soe_request_clear(s);
|
||||
free(s);
|
||||
s = next_s;
|
||||
}
|
||||
sc->first_soe_request = NULL;
|
||||
|
||||
e = sc->first_reg_request;
|
||||
while (e) {
|
||||
next_e = e->next;
|
||||
@@ -607,6 +618,76 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_slave_config_add_soe_request(ec_slave_config_t *sc,
|
||||
ec_soe_request_t *req)
|
||||
{
|
||||
if (sc->first_soe_request) {
|
||||
ec_soe_request_t *r = sc->first_soe_request;
|
||||
while (r->next) {
|
||||
r = r->next;
|
||||
}
|
||||
r->next = req;
|
||||
} else {
|
||||
sc->first_soe_request = req;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_soe_request_t *ecrt_slave_config_create_soe_request(ec_slave_config_t *sc,
|
||||
uint8_t drive_no, uint16_t idn, size_t size)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_soe_request_t *req;
|
||||
int ret;
|
||||
|
||||
req = malloc(sizeof(ec_soe_request_t));
|
||||
if (!req) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
req->data = malloc(size);
|
||||
if (!req->data) {
|
||||
fprintf(stderr, "Failed to allocate %zu bytes of SoE data"
|
||||
" memory.\n", size);
|
||||
free(req);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
req->data = NULL;
|
||||
}
|
||||
|
||||
data.config_index = sc->index;
|
||||
data.drive_no = drive_no;
|
||||
data.idn = idn;
|
||||
data.size = size;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SOE_REQUEST, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to create SoE request: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
ec_soe_request_clear(req);
|
||||
free(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->next = NULL;
|
||||
req->config = sc;
|
||||
req->index = data.request_index;
|
||||
req->drive_no = data.drive_no;
|
||||
req->idn = data.idn;
|
||||
req->data_size = size;
|
||||
req->mem_size = size;
|
||||
|
||||
ec_slave_config_add_soe_request(sc, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_slave_config_add_reg_request(ec_slave_config_t *sc,
|
||||
ec_reg_request_t *reg)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master userspace library.
|
||||
*
|
||||
@@ -39,6 +37,7 @@ struct ec_slave_config {
|
||||
uint16_t alias;
|
||||
uint16_t position;
|
||||
ec_sdo_request_t *first_sdo_request;
|
||||
ec_soe_request_t *first_soe_request;
|
||||
ec_reg_request_t *first_reg_request;
|
||||
ec_voe_handler_t *first_voe_handler;
|
||||
};
|
||||
|
||||
182
lib/soe_request.c
Normal file
182
lib/soe_request.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master userspace library.
|
||||
*
|
||||
* The IgH EtherCAT master userspace library is free software; you can
|
||||
* redistribute it and/or modify it under the terms of the GNU Lesser General
|
||||
* Public License as published by the Free Software Foundation; version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the IgH EtherCAT master userspace library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 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 SoE request functions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ioctl.h"
|
||||
#include "soe_request.h"
|
||||
#include "slave_config.h"
|
||||
#include "master.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_soe_request_clear(ec_soe_request_t *req)
|
||||
{
|
||||
if (req->data) {
|
||||
free(req->data);
|
||||
req->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface.
|
||||
****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_idn(ec_soe_request_t *req, uint8_t drive_no,
|
||||
uint16_t idn)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
int ret;
|
||||
|
||||
data.config_index = req->config->index;
|
||||
data.request_index = req->index;
|
||||
data.drive_no = drive_no;
|
||||
data.idn = idn;
|
||||
|
||||
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_IDN, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to set SoE request IDN: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_timeout(ec_soe_request_t *req, uint32_t timeout)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
int ret;
|
||||
|
||||
data.config_index = req->config->index;
|
||||
data.request_index = req->index;
|
||||
data.timeout = timeout;
|
||||
|
||||
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_TIMEOUT, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to set SoE request timeout: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_soe_request_data(ec_soe_request_t *req)
|
||||
{
|
||||
return req->data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
size_t ecrt_soe_request_data_size(const ec_soe_request_t *req)
|
||||
{
|
||||
return req->data_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_request_state_t ecrt_soe_request_state(ec_soe_request_t *req)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
int ret;
|
||||
|
||||
data.config_index = req->config->index;
|
||||
data.request_index = req->index;
|
||||
|
||||
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_STATE, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get SoE request state: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return EC_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (data.size) { // new data waiting to be copied
|
||||
if (req->mem_size < data.size) {
|
||||
fprintf(stderr, "Received %zu bytes do not fit info SoE data"
|
||||
" memory (%zu bytes)!\n", data.size, req->mem_size);
|
||||
return EC_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
data.data = req->data;
|
||||
|
||||
ret = ioctl(req->config->master->fd,
|
||||
EC_IOCTL_SOE_REQUEST_DATA, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get SoE data: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return EC_REQUEST_ERROR;
|
||||
}
|
||||
req->data_size = data.size;
|
||||
}
|
||||
|
||||
return data.state;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_read(ec_soe_request_t *req)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
int ret;
|
||||
|
||||
data.config_index = req->config->index;
|
||||
data.request_index = req->index;
|
||||
|
||||
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_READ, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to command an SoE read operation : %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_write(ec_soe_request_t *req)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
int ret;
|
||||
|
||||
data.config_index = req->config->index;
|
||||
data.request_index = req->index;
|
||||
data.data = req->data;
|
||||
data.size = req->data_size;
|
||||
|
||||
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_WRITE, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to command an SDO write operation : %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
48
lib/soe_request.h
Normal file
48
lib/soe_request.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master userspace library.
|
||||
*
|
||||
* The IgH EtherCAT master userspace library is free software; you can
|
||||
* redistribute it and/or modify it under the terms of the GNU Lesser General
|
||||
* Public License as published by the Free Software Foundation; version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the IgH EtherCAT master userspace library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "include/ecrt.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct ec_soe_request {
|
||||
ec_soe_request_t *next; /**< List header. */
|
||||
ec_slave_config_t *config; /**< Parent slave configuration. */
|
||||
unsigned int index; /**< Request index (identifier). */
|
||||
uint8_t drive_no; /**< SoE drive number. */
|
||||
uint16_t idn; /**< SoE ID number. */
|
||||
uint8_t *data; /**< Pointer to SoE data. */
|
||||
size_t mem_size; /**< Size of SoE data memory. */
|
||||
size_t data_size; /**< Size of SoE data. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_soe_request_clear(ec_soe_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -66,6 +64,7 @@ void ec_fsm_master_state_assign_sii(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_write_sii(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_sdo_request(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_soe_request(ec_fsm_master_t *);
|
||||
|
||||
void ec_fsm_master_enter_clear_addresses(ec_fsm_master_t *);
|
||||
void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *);
|
||||
@@ -83,8 +82,18 @@ void ec_fsm_master_init(
|
||||
fsm->master = master;
|
||||
fsm->datagram = datagram;
|
||||
|
||||
// inits the member variables state, idle, dev_idx, link_state,
|
||||
// slaves_responding, slave_states and rescan_required
|
||||
ec_fsm_master_reset(fsm);
|
||||
|
||||
fsm->retries = 0;
|
||||
fsm->scan_jiffies = 0;
|
||||
fsm->slave = NULL;
|
||||
fsm->sii_request = NULL;
|
||||
fsm->sii_index = 0;
|
||||
fsm->sdo_request = NULL;
|
||||
fsm->soe_request = NULL;
|
||||
|
||||
// init sub-state-machines
|
||||
ec_fsm_coe_init(&fsm->fsm_coe);
|
||||
ec_fsm_soe_init(&fsm->fsm_soe);
|
||||
@@ -492,17 +501,18 @@ int ec_fsm_master_action_process_sii(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Check for pending SDO requests and process one.
|
||||
/** Check for pending internal SDO/SoE requests and process one.
|
||||
*
|
||||
* \return non-zero, if an SDO request is processed.
|
||||
*/
|
||||
int ec_fsm_master_action_process_sdo(
|
||||
int ec_fsm_master_action_process_int_request(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = fsm->master;
|
||||
ec_slave_t *slave;
|
||||
ec_sdo_request_t *req;
|
||||
ec_sdo_request_t *sdo_req;
|
||||
ec_soe_request_t *soe_req;
|
||||
|
||||
// search for internal requests to be processed
|
||||
for (slave = master->slaves;
|
||||
@@ -513,33 +523,61 @@ int ec_fsm_master_action_process_sdo(
|
||||
continue;
|
||||
}
|
||||
|
||||
list_for_each_entry(req, &slave->config->sdo_requests, list) {
|
||||
if (req->state == EC_INT_REQUEST_QUEUED) {
|
||||
list_for_each_entry(sdo_req, &slave->config->sdo_requests, list) {
|
||||
if (sdo_req->state == EC_INT_REQUEST_QUEUED) {
|
||||
|
||||
if (ec_sdo_request_timed_out(req)) {
|
||||
req->state = EC_INT_REQUEST_FAILURE;
|
||||
if (ec_sdo_request_timed_out(sdo_req)) {
|
||||
sdo_req->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_SLAVE_DBG(slave, 1, "Internal SDO request"
|
||||
" timed out.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slave->current_state == EC_SLAVE_STATE_INIT) {
|
||||
req->state = EC_INT_REQUEST_FAILURE;
|
||||
sdo_req->state = EC_INT_REQUEST_FAILURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
req->state = EC_INT_REQUEST_BUSY;
|
||||
sdo_req->state = EC_INT_REQUEST_BUSY;
|
||||
EC_SLAVE_DBG(slave, 1, "Processing internal"
|
||||
" SDO request...\n");
|
||||
fsm->idle = 0;
|
||||
fsm->sdo_request = req;
|
||||
fsm->sdo_request = sdo_req;
|
||||
fsm->slave = slave;
|
||||
fsm->state = ec_fsm_master_state_sdo_request;
|
||||
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, req);
|
||||
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, sdo_req);
|
||||
ec_fsm_coe_exec(&fsm->fsm_coe, fsm->datagram);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(soe_req, &slave->config->soe_requests, list) {
|
||||
if (soe_req->state == EC_INT_REQUEST_QUEUED) {
|
||||
|
||||
if (ec_soe_request_timed_out(soe_req)) {
|
||||
soe_req->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_SLAVE_DBG(slave, 1, "Internal SoE request"
|
||||
" timed out.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slave->current_state == EC_SLAVE_STATE_INIT) {
|
||||
soe_req->state = EC_INT_REQUEST_FAILURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
soe_req->state = EC_INT_REQUEST_BUSY;
|
||||
EC_SLAVE_DBG(slave, 1, "Processing internal"
|
||||
" SoE request...\n");
|
||||
fsm->idle = 0;
|
||||
fsm->soe_request = soe_req;
|
||||
fsm->slave = slave;
|
||||
fsm->state = ec_fsm_master_state_soe_request;
|
||||
ec_fsm_soe_transfer(&fsm->fsm_soe, slave, soe_req);
|
||||
ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -557,8 +595,8 @@ void ec_fsm_master_action_idle(
|
||||
ec_master_t *master = fsm->master;
|
||||
ec_slave_t *slave;
|
||||
|
||||
// Check for pending internal SDO requests
|
||||
if (ec_fsm_master_action_process_sdo(fsm)) {
|
||||
// Check for pending internal SDO or SoE requests
|
||||
if (ec_fsm_master_action_process_int_request(fsm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1357,8 +1395,51 @@ void ec_fsm_master_state_sdo_request(
|
||||
|
||||
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SDO request.\n");
|
||||
|
||||
// check for another SDO request
|
||||
if (ec_fsm_master_action_process_sdo(fsm)) {
|
||||
// check for another SDO/SoE request
|
||||
if (ec_fsm_master_action_process_int_request(fsm)) {
|
||||
return; // processing another request
|
||||
}
|
||||
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: SoE REQUEST.
|
||||
*/
|
||||
void ec_fsm_master_state_soe_request(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_soe_request_t *request = fsm->soe_request;
|
||||
|
||||
if (!request) {
|
||||
// configuration was cleared in the meantime
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ec_fsm_soe_success(&fsm->fsm_soe)) {
|
||||
EC_SLAVE_DBG(fsm->slave, 1,
|
||||
"Failed to process internal SoE request.\n");
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up_all(&fsm->master->request_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
// SoE request finished
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
wake_up_all(&fsm->master->request_queue);
|
||||
|
||||
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SoE request.\n");
|
||||
|
||||
// check for another CoE/SoE request
|
||||
if (ec_fsm_master_action_process_int_request(fsm)) {
|
||||
return; // processing another request
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -88,6 +86,7 @@ struct ec_fsm_master {
|
||||
ec_sii_write_request_t *sii_request; /**< SII write request */
|
||||
off_t sii_index; /**< index to SII write request data */
|
||||
ec_sdo_request_t *sdo_request; /**< SDO request to process. */
|
||||
ec_soe_request_t *soe_request; /**< SoE request to process. */
|
||||
|
||||
ec_fsm_coe_t fsm_coe; /**< CoE state machine */
|
||||
ec_fsm_soe_t fsm_soe; /**< SoE state machine */
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
||||
343
master/ioctl.c
343
master/ioctl.c
@@ -2819,6 +2819,59 @@ static ATTRIBUTES int ec_ioctl_sc_create_sdo_request(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Create an SoE request.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_sc_create_soe_request(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
data.request_index = 0;
|
||||
|
||||
if (down_interruptible(&master->master_sem))
|
||||
return -EINTR;
|
||||
|
||||
sc = ec_master_get_config(master, data.config_index);
|
||||
if (!sc) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
list_for_each_entry(req, &sc->soe_requests, list) {
|
||||
data.request_index++;
|
||||
}
|
||||
|
||||
up(&master->master_sem); /** \todo sc could be invalidated */
|
||||
|
||||
req = ecrt_slave_config_create_soe_request_err(sc, data.drive_no,
|
||||
data.idn, data.size);
|
||||
if (IS_ERR(req)) {
|
||||
return PTR_ERR(req);
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Create a register request.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
@@ -3483,6 +3536,255 @@ static ATTRIBUTES int ec_ioctl_sdo_request_data(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sets an SoE request's drive number and IDN.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_index(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ecrt_soe_request_idn(req, data.drive_no, data.idn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sets an CoE request's timeout.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_timeout(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ecrt_soe_request_timeout(req, data.timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Gets an SoE request's state.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_state(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
data.state = ecrt_soe_request_state(req);
|
||||
if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) {
|
||||
data.size = ecrt_soe_request_data_size(req);
|
||||
}
|
||||
else {
|
||||
data.size = 0;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) arg, &data, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Starts an SoE IDN read operation.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_read(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ecrt_soe_request_read(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Starts an SoE IDN write operation.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_write(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!data.size) {
|
||||
EC_MASTER_ERR(master, "IDN write: Data size may not be zero!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = ec_soe_request_alloc(req, data.size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (copy_from_user(req->data, (void __user *) data.data, data.size))
|
||||
return -EFAULT;
|
||||
|
||||
req->data_size = data.size;
|
||||
ecrt_soe_request_write(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Read SoE IDN data.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_soe_request_data(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_soe_request_t data;
|
||||
ec_slave_config_t *sc;
|
||||
ec_soe_request_t *req;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
|
||||
return -EFAULT;
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor req will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) data.data, ecrt_soe_request_data(req),
|
||||
ecrt_soe_request_data_size(req)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Read register data.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
@@ -4617,6 +4919,13 @@ long EC_IOCTL(
|
||||
}
|
||||
ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_SOE_REQUEST:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_create_soe_request(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_REG_REQUEST:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
@@ -4705,6 +5014,40 @@ long EC_IOCTL(
|
||||
case EC_IOCTL_SDO_REQUEST_DATA:
|
||||
ret = ec_ioctl_sdo_request_data(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_IDN:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_soe_request_index(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_TIMEOUT:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_soe_request_timeout(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_STATE:
|
||||
ret = ec_ioctl_soe_request_state(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_READ:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_soe_request_read(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_WRITE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_soe_request_write(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SOE_REQUEST_DATA:
|
||||
ret = ec_ioctl_soe_request_data(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REG_REQUEST_DATA:
|
||||
ret = ec_ioctl_reg_request_data(master, arg, ctx);
|
||||
break;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
*
|
||||
* Increment this when changing the ioctl interface!
|
||||
*/
|
||||
#define EC_IOCTL_VERSION_MAGIC 32
|
||||
#define EC_IOCTL_VERSION_MAGIC 33
|
||||
|
||||
// Command-line tool
|
||||
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
|
||||
@@ -118,34 +118,41 @@
|
||||
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3d, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3e, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x40, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x41, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x42, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x43, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_SC_FLAG EC_IOW(0x44, ec_ioctl_sc_flag_t)
|
||||
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x45)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x46)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x47)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x48)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x49, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x51, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x52, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x53, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x54, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x55, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x56, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x57, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x58, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x59, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x5a, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5b, size_t)
|
||||
#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x40, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x41, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x42, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x43, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x44, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_SC_FLAG EC_IOW(0x45, ec_ioctl_sc_flag_t)
|
||||
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x46)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x47)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x48)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x49)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4a, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x51, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x52, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x53, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x54, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x55, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x56, ec_ioctl_soe_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x58, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x59, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5a, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x5d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x5f, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x60, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x61, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x62, size_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -728,6 +735,22 @@ typedef struct {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
|
||||
// inputs/outputs
|
||||
uint32_t request_index;
|
||||
uint8_t drive_no;
|
||||
uint16_t idn;
|
||||
size_t size;
|
||||
uint8_t *data;
|
||||
uint32_t timeout;
|
||||
ec_request_state_t state;
|
||||
} ec_ioctl_soe_request_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -61,10 +59,12 @@ void ec_sdo_request_init(
|
||||
req->data = NULL;
|
||||
req->mem_size = 0;
|
||||
req->data_size = 0;
|
||||
req->dir = EC_DIR_INVALID;
|
||||
req->issue_timeout = 0; // no timeout
|
||||
req->response_timeout = EC_SDO_REQUEST_RESPONSE_TIMEOUT;
|
||||
req->dir = EC_DIR_INVALID;
|
||||
req->state = EC_INT_REQUEST_INIT;
|
||||
req->jiffies_start = 0U;
|
||||
req->jiffies_sent = 0U;
|
||||
req->errno = 0;
|
||||
req->abort_code = 0x00000000;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -87,6 +85,7 @@ void ec_slave_config_init(
|
||||
|
||||
INIT_LIST_HEAD(&sc->sdo_configs);
|
||||
INIT_LIST_HEAD(&sc->sdo_requests);
|
||||
INIT_LIST_HEAD(&sc->soe_requests);
|
||||
INIT_LIST_HEAD(&sc->reg_requests);
|
||||
INIT_LIST_HEAD(&sc->voe_handlers);
|
||||
INIT_LIST_HEAD(&sc->soe_configs);
|
||||
@@ -132,6 +131,13 @@ void ec_slave_config_clear(
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
// free all SoE requests
|
||||
list_for_each_entry_safe(soe, next_soe, &sc->soe_requests, list) {
|
||||
list_del(&soe->list);
|
||||
ec_soe_request_clear(soe);
|
||||
kfree(soe);
|
||||
}
|
||||
|
||||
// free all register requests
|
||||
list_for_each_entry_safe(reg, next_reg, &sc->reg_requests, list) {
|
||||
list_del(®->list);
|
||||
@@ -507,7 +513,7 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a CoE handler via its position in the list.
|
||||
/** Finds a CoE SDO request via its position in the list.
|
||||
*
|
||||
* \return Search result, or NULL.
|
||||
*/
|
||||
@@ -529,6 +535,28 @@ ec_sdo_request_t *ec_slave_config_find_sdo_request(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a SoE request via its position in the list.
|
||||
*
|
||||
* \return Search result, or NULL.
|
||||
*/
|
||||
ec_soe_request_t *ec_slave_config_find_soe_request(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
unsigned int pos /**< Position in the list. */
|
||||
)
|
||||
{
|
||||
ec_soe_request_t *req;
|
||||
|
||||
list_for_each_entry(req, &sc->soe_requests, list) {
|
||||
if (pos--)
|
||||
continue;
|
||||
return req;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a register handler via its position in the list.
|
||||
*
|
||||
* \return Search result, or NULL.
|
||||
@@ -1158,6 +1186,58 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_soe_request(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
|
||||
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
|
||||
{
|
||||
ec_soe_request_t *req;
|
||||
int ret;
|
||||
|
||||
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, "
|
||||
"drive_no = 0x%02X, idn = 0x%04X, size = %zu)\n",
|
||||
__func__, sc, drive_no, idn, size);
|
||||
|
||||
if (!(req = (ec_soe_request_t *)
|
||||
kmalloc(sizeof(ec_soe_request_t), GFP_KERNEL))) {
|
||||
EC_CONFIG_ERR(sc, "Failed to allocate IDN request memory!\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ec_soe_request_init(req);
|
||||
ecrt_soe_request_idn(req, drive_no, idn);
|
||||
|
||||
ret = ec_soe_request_alloc(req, size);
|
||||
if (ret < 0) {
|
||||
ec_soe_request_clear(req);
|
||||
kfree(req);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
// prepare data for optional writing
|
||||
memset(req->data, 0x00, size);
|
||||
req->data_size = size;
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
list_add_tail(&req->list, &sc->soe_requests);
|
||||
up(&sc->master->master_sem);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_soe_request_t *ecrt_slave_config_create_soe_request(
|
||||
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
|
||||
{
|
||||
ec_soe_request_t *req = ecrt_slave_config_create_soe_request_err(sc,
|
||||
drive_no, idn, size);
|
||||
return IS_ERR(req) ? NULL : req;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_reg_request(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
@@ -1373,6 +1453,7 @@ EXPORT_SYMBOL(ecrt_slave_config_emerg_pop);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_emerg_clear);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_emerg_overruns);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_soe_request);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_reg_request);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_state);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -143,6 +141,7 @@ struct ec_slave_config {
|
||||
|
||||
struct list_head sdo_configs; /**< List of SDO configurations. */
|
||||
struct list_head sdo_requests; /**< List of SDO requests. */
|
||||
struct list_head soe_requests; /**< List of SoE requests. */
|
||||
struct list_head voe_handlers; /**< List of VoE handlers. */
|
||||
struct list_head reg_requests; /**< List of register requests. */
|
||||
struct list_head soe_configs; /**< List of SoE configurations. */
|
||||
@@ -173,6 +172,8 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
|
||||
const ec_slave_config_t *, unsigned int);
|
||||
ec_sdo_request_t *ec_slave_config_find_sdo_request(ec_slave_config_t *,
|
||||
unsigned int);
|
||||
ec_soe_request_t *ec_slave_config_find_soe_request(ec_slave_config_t *,
|
||||
unsigned int);
|
||||
ec_reg_request_t *ec_slave_config_find_reg_request(ec_slave_config_t *,
|
||||
unsigned int);
|
||||
ec_voe_handler_t *ec_slave_config_find_voe_handler(ec_slave_config_t *,
|
||||
@@ -181,6 +182,8 @@ ec_flag_t *ec_slave_config_find_flag(ec_slave_config_t *, const char *);
|
||||
|
||||
ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
|
||||
ec_slave_config_t *, uint16_t, uint8_t, size_t);
|
||||
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
|
||||
ec_slave_config_t *, uint8_t, uint16_t, size_t);
|
||||
ec_voe_handler_t *ecrt_slave_config_create_voe_handler_err(
|
||||
ec_slave_config_t *, size_t);
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request_err(
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -64,8 +62,10 @@ void ec_soe_request_init(
|
||||
req->data = NULL;
|
||||
req->mem_size = 0;
|
||||
req->data_size = 0;
|
||||
req->issue_timeout = 0; // no timeout
|
||||
req->dir = EC_DIR_INVALID;
|
||||
req->state = EC_INT_REQUEST_INIT;
|
||||
req->jiffies_start = 0U;
|
||||
req->jiffies_sent = 0U;
|
||||
req->error_code = 0x0000;
|
||||
}
|
||||
@@ -236,6 +236,7 @@ void ec_soe_request_read(
|
||||
req->dir = EC_DIR_INPUT;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
req->error_code = 0x0000;
|
||||
req->jiffies_start = jiffies;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -249,6 +250,86 @@ void ec_soe_request_write(
|
||||
req->dir = EC_DIR_OUTPUT;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
req->error_code = 0x0000;
|
||||
req->jiffies_start = jiffies;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Checks, if the timeout was exceeded.
|
||||
*
|
||||
* \return non-zero if the timeout was exceeded, else zero.
|
||||
*/
|
||||
int ec_soe_request_timed_out(const ec_soe_request_t *req /**< SDO request. */)
|
||||
{
|
||||
return req->issue_timeout
|
||||
&& jiffies - req->jiffies_start > HZ * req->issue_timeout / 1000;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface.
|
||||
****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_idn(ec_soe_request_t *req, uint8_t drive_no,
|
||||
uint16_t idn)
|
||||
{
|
||||
req->drive_no = drive_no;
|
||||
req->idn = idn;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_timeout(ec_soe_request_t *req, uint32_t timeout)
|
||||
{
|
||||
req->issue_timeout = timeout;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_soe_request_data(ec_soe_request_t *req)
|
||||
{
|
||||
return req->data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
size_t ecrt_soe_request_data_size(const ec_soe_request_t *req)
|
||||
{
|
||||
return req->data_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_request_state_t ecrt_soe_request_state(ec_soe_request_t *req)
|
||||
{
|
||||
return ec_request_state_translation_table[req->state];
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_read(ec_soe_request_t *req)
|
||||
{
|
||||
ec_soe_request_read(req);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_soe_request_write(ec_soe_request_t *req)
|
||||
{
|
||||
ec_soe_request_write(req);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_soe_request_idn);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_timeout);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_data);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_data_size);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_state);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_read);
|
||||
EXPORT_SYMBOL(ecrt_soe_request_write);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
/** Sercos-over-EtherCAT request.
|
||||
*/
|
||||
typedef struct {
|
||||
struct ec_soe_request {
|
||||
struct list_head list; /**< List item. */
|
||||
uint8_t drive_no; /**< Drive number. */
|
||||
uint16_t idn; /**< Sercos ID-Number. */
|
||||
@@ -53,13 +53,16 @@ typedef struct {
|
||||
uint8_t *data; /**< Pointer to SDO data. */
|
||||
size_t mem_size; /**< Size of SDO data memory. */
|
||||
size_t data_size; /**< Size of SDO data. */
|
||||
uint32_t issue_timeout; /**< Maximum time in ms, the processing of the
|
||||
request may take. */
|
||||
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to the
|
||||
slave, EC_DIR_INPUT means reading from the slave. */
|
||||
ec_internal_request_state_t state; /**< Request state. */
|
||||
unsigned long jiffies_start; /**< Jiffies, when the request was issued. */
|
||||
unsigned long jiffies_sent; /**< Jiffies, when the upload/download
|
||||
request was sent. */
|
||||
uint16_t error_code; /**< SoE error code. */
|
||||
} ec_soe_request_t;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -74,6 +77,7 @@ int ec_soe_request_copy_data(ec_soe_request_t *, const uint8_t *, size_t);
|
||||
int ec_soe_request_append_data(ec_soe_request_t *, const uint8_t *, size_t);
|
||||
void ec_soe_request_read(ec_soe_request_t *);
|
||||
void ec_soe_request_write(ec_soe_request_t *);
|
||||
int ec_soe_request_timed_out(const ec_soe_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user