Added interface to read/write register contents; re-worked register requests.
This commit is contained in:
parent
139168474d
commit
4773e88bf6
|
|
@ -52,6 +52,10 @@
|
|||
* ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
|
||||
* ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
|
||||
* the defines EC_HAVE_EMERGENCY and EC_COE_EMERGENCY_MSG_SIZE.
|
||||
* - Added interface for direct EtherCAT register access: Added data type
|
||||
* ec_reg_request_t and methods ecrt_slave_config_create_reg_request(),
|
||||
* ecrt_reg_request_data(), ecrt_reg_request_state(),
|
||||
* ecrt_reg_request_write() and ecrt_reg_request_read().
|
||||
*
|
||||
* Changes in version 1.5:
|
||||
*
|
||||
|
|
@ -207,6 +211,9 @@ typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_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. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state.
|
||||
|
|
@ -1375,6 +1382,20 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler(
|
|||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Create a register request to exchange EtherCAT register contents during
|
||||
* realtime operation.
|
||||
*
|
||||
* This interface should not be used to take over master functionality,
|
||||
* instead it is intended for debugging and monitoring reasons.
|
||||
*
|
||||
* The created register request object is freed automatically when the master
|
||||
* is released.
|
||||
*/
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Outputs the state of the slave configuration.
|
||||
*
|
||||
* Stores the state information in the given \a state structure. The state
|
||||
|
|
@ -1745,6 +1766,75 @@ ec_request_state_t ecrt_voe_handler_execute(
|
|||
ec_voe_handler_t *voe /**< VoE handler. */
|
||||
);
|
||||
|
||||
/*****************************************************************************
|
||||
* Register request methods.
|
||||
****************************************************************************/
|
||||
|
||||
/** Access to the register request's data.
|
||||
*
|
||||
* This function returns a pointer to the request's internal 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_reg_request_data(reg_request)));
|
||||
* \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_reg_request().
|
||||
* \code
|
||||
* EC_WRITE_U16(ecrt_reg_request_data(reg_request), 0xFFFF);
|
||||
* \endcode
|
||||
*
|
||||
* \return Pointer to the internal memory.
|
||||
*/
|
||||
uint8_t *ecrt_reg_request_data(
|
||||
ec_reg_request_t *req /**< Register request. */
|
||||
);
|
||||
|
||||
/** Get the current state of the register request.
|
||||
*
|
||||
* \return Request state.
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
ec_request_state_t ecrt_reg_request_state(
|
||||
const ec_reg_request_t *req /**< Register request. */
|
||||
);
|
||||
#else
|
||||
ec_request_state_t ecrt_reg_request_state(
|
||||
ec_reg_request_t *req /**< Register request. */
|
||||
);
|
||||
#endif
|
||||
|
||||
/** Schedule an register write operation.
|
||||
*
|
||||
* \attention This method may not be called while ecrt_reg_request_state()
|
||||
* returns EC_REQUEST_BUSY.
|
||||
*
|
||||
* \attention The \a size parameter is truncated to the size given at request
|
||||
* creation.
|
||||
*/
|
||||
void ecrt_reg_request_write(
|
||||
ec_reg_request_t *req, /**< Register request. */
|
||||
uint16_t address, /**< Register address. */
|
||||
size_t size /**< Size to write. */
|
||||
);
|
||||
|
||||
/** Schedule a register read operation.
|
||||
*
|
||||
* \attention This method may not be called while ecrt_reg_request_state()
|
||||
* returns EC_REQUEST_BUSY.
|
||||
*
|
||||
* \attention The \a size parameter is truncated to the size given at request
|
||||
* creation.
|
||||
*/
|
||||
void ecrt_reg_request_read(
|
||||
ec_reg_request_t *req, /**< Register request. */
|
||||
uint16_t address, /**< Register address. */
|
||||
size_t size /**< Size to write. */
|
||||
);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ libethercat_la_SOURCES = \
|
|||
common.c \
|
||||
domain.c \
|
||||
master.c \
|
||||
reg_request.c \
|
||||
sdo_request.c \
|
||||
slave_config.c \
|
||||
voe_handler.c
|
||||
|
|
@ -43,6 +44,7 @@ libethercat_la_SOURCES = \
|
|||
noinst_HEADERS = \
|
||||
domain.h \
|
||||
master.h \
|
||||
reg_request.h \
|
||||
sdo_request.h \
|
||||
slave_config.h \
|
||||
voe_handler.h
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
|||
sc->alias = alias;
|
||||
sc->position = position;
|
||||
sc->first_sdo_request = NULL;
|
||||
sc->first_reg_request = NULL;
|
||||
sc->first_voe_handler = NULL;
|
||||
|
||||
ec_master_add_slave_config(master, sc);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 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
|
||||
* EtherCAT register request functions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ioctl.h"
|
||||
#include "reg_request.h"
|
||||
#include "slave_config.h"
|
||||
#include "master.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_reg_request_clear(ec_reg_request_t *reg)
|
||||
{
|
||||
if (reg->data) {
|
||||
free(reg->data);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface.
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_reg_request_data(ec_reg_request_t *reg)
|
||||
{
|
||||
return reg->data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_request_state_t ecrt_reg_request_state(ec_reg_request_t *reg)
|
||||
{
|
||||
ec_ioctl_reg_request_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = reg->config->index;
|
||||
io.request_index = reg->index;
|
||||
|
||||
ret = ioctl(reg->config->master->fd, EC_IOCTL_REG_REQUEST_STATE, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get register request state: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return EC_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (io.new_data) { // new data waiting to be copied
|
||||
|
||||
io.data = reg->data;
|
||||
io.mem_size = reg->mem_size;
|
||||
|
||||
ret = ioctl(reg->config->master->fd,
|
||||
EC_IOCTL_REG_REQUEST_DATA, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get register data: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return EC_REQUEST_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return io.state;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_reg_request_write(ec_reg_request_t *reg, uint16_t address,
|
||||
size_t size)
|
||||
{
|
||||
ec_ioctl_reg_request_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = reg->config->index;
|
||||
io.request_index = reg->index;
|
||||
io.data = reg->data;
|
||||
io.address = address;
|
||||
io.transfer_size = size;
|
||||
|
||||
ret = ioctl(reg->config->master->fd, EC_IOCTL_REG_REQUEST_WRITE, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to command an register write operation: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_reg_request_read(ec_reg_request_t *reg, uint16_t address,
|
||||
size_t size)
|
||||
{
|
||||
ec_ioctl_reg_request_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = reg->config->index;
|
||||
io.request_index = reg->index;
|
||||
io.address = address;
|
||||
io.transfer_size = size;
|
||||
|
||||
ret = ioctl(reg->config->master->fd, EC_IOCTL_REG_REQUEST_READ, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to command an register read operation: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 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_reg_request {
|
||||
ec_reg_request_t *next; /**< List header. */
|
||||
ec_slave_config_t *config; /**< Parent slave configuration. */
|
||||
unsigned int index; /**< Request index (identifier). */
|
||||
uint8_t *data; /**< Data memory. */
|
||||
size_t mem_size; /**< Size of \a data. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_reg_request_clear(ec_reg_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "slave_config.h"
|
||||
#include "domain.h"
|
||||
#include "sdo_request.h"
|
||||
#include "reg_request.h"
|
||||
#include "voe_handler.h"
|
||||
#include "master.h"
|
||||
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
void ec_slave_config_clear(ec_slave_config_t *sc)
|
||||
{
|
||||
ec_sdo_request_t *r, *next_r;
|
||||
ec_reg_request_t *e, *next_e;
|
||||
ec_voe_handler_t *v, *next_v;
|
||||
|
||||
r = sc->first_sdo_request;
|
||||
|
|
@ -54,6 +56,12 @@ void ec_slave_config_clear(ec_slave_config_t *sc)
|
|||
r = next_r;
|
||||
}
|
||||
|
||||
e = sc->first_reg_request;
|
||||
while (e) {
|
||||
next_e = e->next;
|
||||
ec_reg_request_clear(e);
|
||||
e = next_e;
|
||||
}
|
||||
|
||||
v = sc->first_voe_handler;
|
||||
while (v) {
|
||||
|
|
@ -551,6 +559,71 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_slave_config_add_reg_request(ec_slave_config_t *sc,
|
||||
ec_reg_request_t *reg)
|
||||
{
|
||||
if (sc->first_reg_request) {
|
||||
ec_reg_request_t *r = sc->first_reg_request;
|
||||
while (r->next) {
|
||||
r = r->next;
|
||||
}
|
||||
r->next = reg;
|
||||
} else {
|
||||
sc->first_reg_request = reg;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request(ec_slave_config_t *sc,
|
||||
size_t size)
|
||||
{
|
||||
ec_ioctl_reg_request_t io;
|
||||
ec_reg_request_t *reg;
|
||||
int ret;
|
||||
|
||||
reg = malloc(sizeof(ec_reg_request_t));
|
||||
if (!reg) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
reg->data = malloc(size);
|
||||
if (!reg->data) {
|
||||
fprintf(stderr, "Failed to allocate %u bytes of register data"
|
||||
" memory.\n", size);
|
||||
free(reg);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
reg->data = NULL;
|
||||
}
|
||||
|
||||
io.config_index = sc->index;
|
||||
io.mem_size = size;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_REQUEST, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to create register request: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
ec_reg_request_clear(reg);
|
||||
free(reg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reg->next = NULL;
|
||||
reg->config = sc;
|
||||
reg->index = io.request_index;
|
||||
reg->mem_size = size;
|
||||
|
||||
ec_slave_config_add_reg_request(sc, reg);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_slave_config_add_voe_handler(ec_slave_config_t *sc,
|
||||
ec_voe_handler_t *voe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master userspace library.
|
||||
*
|
||||
|
|
@ -39,6 +39,7 @@ struct ec_slave_config {
|
|||
uint16_t alias;
|
||||
uint16_t position;
|
||||
ec_sdo_request_t *first_sdo_request;
|
||||
ec_reg_request_t *first_reg_request;
|
||||
ec_voe_handler_t *first_voe_handler;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ ec_master-objs := \
|
|||
pdo.o \
|
||||
pdo_entry.o \
|
||||
pdo_list.o \
|
||||
reg_request.o \
|
||||
sdo.o \
|
||||
sdo_entry.o \
|
||||
sdo_request.o \
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ noinst_HEADERS = \
|
|||
pdo.c pdo.h \
|
||||
pdo_entry.c pdo_entry.h \
|
||||
pdo_list.c pdo_list.h \
|
||||
reg_request.c reg_request.h \
|
||||
rtdm-ioctl.c \
|
||||
rtdm.c rtdm.h \
|
||||
sdo.c sdo.h \
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -65,7 +65,6 @@ void ec_fsm_master_state_dc_write_offset(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_reg_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 *);
|
||||
|
|
@ -404,62 +403,6 @@ int ec_fsm_master_action_process_sii(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Check for pending register requests and process one.
|
||||
*
|
||||
* \return non-zero, if a register request is processed.
|
||||
*/
|
||||
int ec_fsm_master_action_process_register(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = fsm->master;
|
||||
ec_reg_request_t *request;
|
||||
|
||||
// search the first request to be processed
|
||||
while (!list_empty(&master->reg_requests)) {
|
||||
|
||||
// get first request
|
||||
request = list_entry(master->reg_requests.next,
|
||||
ec_reg_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
request->state = EC_INT_REQUEST_BUSY;
|
||||
|
||||
// found pending request; process it!
|
||||
EC_SLAVE_DBG(request->slave, 1, "Processing register request, "
|
||||
"offset 0x%04x, length %zu...\n",
|
||||
request->offset, request->length);
|
||||
|
||||
if (request->length > fsm->datagram->mem_size) {
|
||||
EC_MASTER_ERR(master, "Request length (%zu) exceeds maximum "
|
||||
"datagram size (%zu)!\n", request->length,
|
||||
fsm->datagram->mem_size);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->reg_queue);
|
||||
continue;
|
||||
}
|
||||
|
||||
fsm->reg_request = request;
|
||||
|
||||
if (request->dir == EC_DIR_INPUT) {
|
||||
ec_datagram_fprd(fsm->datagram, request->slave->station_address,
|
||||
request->offset, request->length);
|
||||
ec_datagram_zero(fsm->datagram);
|
||||
} else {
|
||||
ec_datagram_fpwr(fsm->datagram, request->slave->station_address,
|
||||
request->offset, request->length);
|
||||
memcpy(fsm->datagram->data, request->data, request->length);
|
||||
}
|
||||
fsm->datagram->device_index = request->slave->device_index;
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_master_state_reg_request;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Check for pending SDO requests and process one.
|
||||
*
|
||||
* \return non-zero, if an SDO request is processed.
|
||||
|
|
@ -509,7 +452,6 @@ int ec_fsm_master_action_process_sdo(
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master action: IDLE.
|
||||
|
|
@ -563,12 +505,9 @@ void ec_fsm_master_action_idle(
|
|||
}
|
||||
|
||||
// check for pending SII write operations.
|
||||
if (ec_fsm_master_action_process_sii(fsm))
|
||||
if (ec_fsm_master_action_process_sii(fsm)) {
|
||||
return; // SII write request found
|
||||
|
||||
// check for pending register requests.
|
||||
if (ec_fsm_master_action_process_register(fsm))
|
||||
return; // register request processing
|
||||
}
|
||||
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
|
@ -1276,62 +1215,9 @@ 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))
|
||||
return; // processing another request
|
||||
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: REG REQUEST.
|
||||
*/
|
||||
void ec_fsm_master_state_reg_request(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = fsm->master;
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_reg_request_t *request = fsm->reg_request;
|
||||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
EC_MASTER_ERR(master, "Failed to receive register"
|
||||
" request datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->reg_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter == 1) {
|
||||
if (request->dir == EC_DIR_INPUT) { // read request
|
||||
if (request->data)
|
||||
kfree(request->data);
|
||||
request->data = kmalloc(request->length, GFP_KERNEL);
|
||||
if (!request->data) {
|
||||
EC_MASTER_ERR(master, "Failed to allocate %zu bytes"
|
||||
" of memory for register data.\n", request->length);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->reg_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
}
|
||||
memcpy(request->data, datagram->data, request->length);
|
||||
}
|
||||
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
EC_SLAVE_DBG(request->slave, 1, "Register request successful.\n");
|
||||
} else {
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_MASTER_ERR(master, "Register request failed.\n");
|
||||
}
|
||||
|
||||
wake_up(&master->reg_queue);
|
||||
|
||||
// check for another register request
|
||||
if (ec_fsm_master_action_process_register(fsm))
|
||||
if (ec_fsm_master_action_process_sdo(fsm)) {
|
||||
return; // processing another request
|
||||
}
|
||||
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -61,20 +61,6 @@ typedef struct {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Register request.
|
||||
*/
|
||||
typedef struct {
|
||||
struct list_head list; /**< List head. */
|
||||
ec_slave_t *slave; /**< EtherCAT slave. */
|
||||
ec_direction_t dir; /**< Direction. */
|
||||
uint16_t offset; /**< Register address. */
|
||||
size_t length; /**< Number of bytes. */
|
||||
uint8_t *data; /**< Data to write / memory for read data. */
|
||||
ec_internal_request_state_t state; /**< State of the request. */
|
||||
} ec_reg_request_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave/SDO request record for master's SDO request list.
|
||||
*/
|
||||
typedef struct {
|
||||
|
|
@ -132,7 +118,6 @@ 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_reg_request_t *reg_request; /**< Register request to process. */
|
||||
|
||||
ec_fsm_coe_t fsm_coe; /**< CoE state machine */
|
||||
ec_fsm_pdo_t fsm_pdo; /**< PDO configuration state machine. */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "mailbox.h"
|
||||
#include "slave_config.h"
|
||||
|
||||
#include "fsm_slave.h"
|
||||
|
||||
|
|
@ -45,6 +46,8 @@ void ec_fsm_slave_state_idle(ec_fsm_slave_t *);
|
|||
void ec_fsm_slave_state_ready(ec_fsm_slave_t *);
|
||||
int ec_fsm_slave_action_process_sdo(ec_fsm_slave_t *);
|
||||
void ec_fsm_slave_state_sdo_request(ec_fsm_slave_t *);
|
||||
int ec_fsm_slave_action_process_reg(ec_fsm_slave_t *);
|
||||
void ec_fsm_slave_state_reg_request(ec_fsm_slave_t *);
|
||||
int ec_fsm_slave_action_process_foe(ec_fsm_slave_t *);
|
||||
void ec_fsm_slave_state_foe_request(ec_fsm_slave_t *);
|
||||
int ec_fsm_slave_action_process_soe(ec_fsm_slave_t *);
|
||||
|
|
@ -137,7 +140,6 @@ void ec_fsm_slave_state_idle(
|
|||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave state: READY.
|
||||
|
|
@ -151,6 +153,11 @@ void ec_fsm_slave_state_ready(
|
|||
return;
|
||||
}
|
||||
|
||||
// Check for pending external register requests
|
||||
if (ec_fsm_slave_action_process_reg(fsm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for pending FoE requests
|
||||
if (ec_fsm_slave_action_process_foe(fsm)) {
|
||||
return;
|
||||
|
|
@ -176,7 +183,8 @@ int ec_fsm_slave_action_process_sdo(
|
|||
ec_master_sdo_request_t *request, *next;
|
||||
|
||||
// search the first external request to be processed
|
||||
list_for_each_entry_safe(request, next, &slave->slave_sdo_requests, list) {
|
||||
list_for_each_entry_safe(request, next,
|
||||
&slave->slave_sdo_requests, list) {
|
||||
|
||||
list_del_init(&request->list); // dequeue
|
||||
if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
|
||||
|
|
@ -229,6 +237,7 @@ void ec_fsm_slave_state_sdo_request(
|
|||
ec_master_queue_external_datagram(fsm->slave->master, fsm->datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
|
||||
EC_SLAVE_ERR(slave, "Failed to process SDO request.\n");
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
|
|
@ -250,6 +259,114 @@ void ec_fsm_slave_state_sdo_request(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Check for pending register requests and process one.
|
||||
*
|
||||
* \return non-zero, if a register request is processed.
|
||||
*/
|
||||
int ec_fsm_slave_action_process_reg(
|
||||
ec_fsm_slave_t *fsm /**< Slave state machine. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_reg_request_t *reg, *next;
|
||||
|
||||
fsm->reg_request = NULL;
|
||||
|
||||
if (slave->config) {
|
||||
// search the first internal register request to be processed
|
||||
list_for_each_entry(reg, &slave->config->reg_requests, list) {
|
||||
if (reg->state == EC_INT_REQUEST_QUEUED) {
|
||||
fsm->reg_request = reg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fsm->reg_request) {
|
||||
// search the first external request to be processed
|
||||
list_for_each_entry_safe(reg, next, &slave->reg_requests, list) {
|
||||
list_del_init(®->list); // dequeue
|
||||
fsm->reg_request = reg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fsm->reg_request) { // no register request to process
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
|
||||
EC_SLAVE_WARN(slave, "Aborting register request,"
|
||||
" slave has error flag set.\n");
|
||||
reg->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->reg_queue);
|
||||
fsm->state = ec_fsm_slave_state_idle;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Found pending register request. Execute it!
|
||||
EC_SLAVE_DBG(slave, 1, "Processing register request...\n");
|
||||
|
||||
reg->state = EC_INT_REQUEST_BUSY;
|
||||
|
||||
// Start register access
|
||||
if (reg->dir == EC_DIR_INPUT) {
|
||||
ec_datagram_fprd(fsm->datagram, slave->station_address,
|
||||
reg->address, reg->transfer_size);
|
||||
ec_datagram_zero(fsm->datagram);
|
||||
} else {
|
||||
ec_datagram_fpwr(fsm->datagram, slave->station_address,
|
||||
reg->address, reg->transfer_size);
|
||||
memcpy(fsm->datagram->data, reg->data, reg->transfer_size);
|
||||
}
|
||||
fsm->datagram->device_index = slave->device_index;
|
||||
ec_master_queue_external_datagram(slave->master, fsm->datagram);
|
||||
fsm->state = ec_fsm_slave_state_reg_request;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave state: Register request.
|
||||
*/
|
||||
void ec_fsm_slave_state_reg_request(
|
||||
ec_fsm_slave_t *fsm /**< Slave state machine. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_reg_request_t *reg = fsm->reg_request;
|
||||
|
||||
if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
EC_SLAVE_ERR(slave, "Failed to receive register"
|
||||
" request datagram: ");
|
||||
ec_datagram_print_state(fsm->datagram);
|
||||
reg->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->reg_queue);
|
||||
fsm->state = ec_fsm_slave_state_ready;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fsm->datagram->working_counter == 1) {
|
||||
if (reg->dir == EC_DIR_INPUT) { // read request
|
||||
memcpy(reg->data, fsm->datagram->data, reg->transfer_size);
|
||||
}
|
||||
|
||||
reg->state = EC_INT_REQUEST_SUCCESS;
|
||||
EC_SLAVE_DBG(slave, 1, "Register request successful.\n");
|
||||
} else {
|
||||
reg->state = EC_INT_REQUEST_FAILURE;
|
||||
ec_datagram_print_state(fsm->datagram);
|
||||
EC_SLAVE_ERR(slave, "Register request failed"
|
||||
" (working counter is %u).\n",
|
||||
fsm->datagram->working_counter);
|
||||
}
|
||||
|
||||
wake_up(&slave->reg_queue);
|
||||
fsm->state = ec_fsm_slave_state_ready;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Check for pending FoE requests and process one.
|
||||
*
|
||||
* \return non-zero, if an FoE request is processed.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -29,20 +29,24 @@
|
|||
|
||||
/**
|
||||
\file
|
||||
EtherCAT slave request (SDO) state machine.
|
||||
EtherCAT slave request state machine.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __EC_FSM_SLAVE_H__
|
||||
#define __EC_FSM_SLAVE_H__
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "sdo_request.h"
|
||||
#include "reg_request.h"
|
||||
#include "fsm_coe.h"
|
||||
#include "fsm_foe.h"
|
||||
#include "fsm_soe.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct ec_fsm_slave ec_fsm_slave_t; /**< \see ec_fsm_slave */
|
||||
|
||||
/** Finite state machine of an EtherCAT slave.
|
||||
|
|
@ -53,6 +57,7 @@ struct ec_fsm_slave {
|
|||
|
||||
void (*state)(ec_fsm_slave_t *); /**< master state function */
|
||||
ec_sdo_request_t *sdo_request; /**< SDO request to process. */
|
||||
ec_reg_request_t *reg_request; /**< Register request to process. */
|
||||
ec_foe_request_t *foe_request; /**< FoE request to process. */
|
||||
off_t foe_index; /**< index to FoE write request data */
|
||||
ec_soe_request_t *soe_request; /**< SoE request to process. */
|
||||
|
|
|
|||
402
master/ioctl.c
402
master/ioctl.c
|
|
@ -977,51 +977,48 @@ static int ec_ioctl_slave_reg_read(
|
|||
void *arg /**< ioctl() argument. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_slave_reg_t data;
|
||||
ec_ioctl_slave_reg_t io;
|
||||
ec_slave_t *slave;
|
||||
uint8_t *contents;
|
||||
ec_reg_request_t request;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!data.length)
|
||||
if (!io.size) {
|
||||
return 0;
|
||||
|
||||
if (!(contents = kmalloc(data.length, GFP_KERNEL))) {
|
||||
EC_MASTER_ERR(master, "Failed to allocate %u bytes"
|
||||
" for register data.\n", data.length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (down_interruptible(&master->master_sem))
|
||||
return -EINTR;
|
||||
|
||||
if (!(slave = ec_master_find_slave(
|
||||
master, 0, data.slave_position))) {
|
||||
up(&master->master_sem);
|
||||
EC_MASTER_ERR(master, "Slave %u does not exist!\n",
|
||||
data.slave_position);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// init register request
|
||||
INIT_LIST_HEAD(&request.list);
|
||||
request.slave = slave;
|
||||
request.dir = EC_DIR_INPUT;
|
||||
request.data = contents;
|
||||
request.offset = data.offset;
|
||||
request.length = data.length;
|
||||
request.state = EC_INT_REQUEST_QUEUED;
|
||||
ret = ec_reg_request_init(&request, io.size);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ecrt_reg_request_read(&request, io.address, io.size);
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
ec_reg_request_clear(&request);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(slave = ec_master_find_slave(
|
||||
master, 0, io.slave_position))) {
|
||||
up(&master->master_sem);
|
||||
ec_reg_request_clear(&request);
|
||||
EC_MASTER_ERR(master, "Slave %u does not exist!\n",
|
||||
io.slave_position);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// schedule request.
|
||||
list_add_tail(&request.list, &master->reg_requests);
|
||||
list_add_tail(&request.list, &slave->reg_requests);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->reg_queue,
|
||||
if (wait_event_interruptible(slave->reg_queue,
|
||||
request.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
|
|
@ -1029,20 +1026,21 @@ static int ec_ioctl_slave_reg_read(
|
|||
// abort request
|
||||
list_del(&request.list);
|
||||
up(&master->master_sem);
|
||||
kfree(contents);
|
||||
ec_reg_request_clear(&request);
|
||||
return -EINTR;
|
||||
}
|
||||
up(&master->master_sem);
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
wait_event(slave->reg_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
if (request.state == EC_INT_REQUEST_SUCCESS) {
|
||||
if (copy_to_user((void __user *) data.data, contents, data.length))
|
||||
if (copy_to_user((void __user *) io.data, request.data, io.size)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
kfree(contents);
|
||||
ec_reg_request_clear(&request);
|
||||
|
||||
return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
|
@ -1056,57 +1054,53 @@ static int ec_ioctl_slave_reg_write(
|
|||
void *arg /**< ioctl() argument. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_slave_reg_t data;
|
||||
ec_ioctl_slave_reg_t io;
|
||||
ec_slave_t *slave;
|
||||
uint8_t *contents;
|
||||
ec_reg_request_t request;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!data.length)
|
||||
if (!io.size) {
|
||||
return 0;
|
||||
|
||||
if (!(contents = kmalloc(data.length, GFP_KERNEL))) {
|
||||
EC_MASTER_ERR(master, "Failed to allocate %u bytes"
|
||||
" for register data.\n", data.length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(contents, (void __user *) data.data, data.length)) {
|
||||
kfree(contents);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (down_interruptible(&master->master_sem))
|
||||
return -EINTR;
|
||||
|
||||
if (!(slave = ec_master_find_slave(
|
||||
master, 0, data.slave_position))) {
|
||||
up(&master->master_sem);
|
||||
EC_MASTER_ERR(master, "Slave %u does not exist!\n",
|
||||
data.slave_position);
|
||||
kfree(contents);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// init register request
|
||||
INIT_LIST_HEAD(&request.list);
|
||||
request.slave = slave;
|
||||
request.dir = EC_DIR_OUTPUT;
|
||||
request.data = contents;
|
||||
request.offset = data.offset;
|
||||
request.length = data.length;
|
||||
request.state = EC_INT_REQUEST_QUEUED;
|
||||
ret = ec_reg_request_init(&request, io.size);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (copy_from_user(request.data, (void __user *) io.data, io.size)) {
|
||||
ec_reg_request_clear(&request);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ecrt_reg_request_write(&request, io.address, io.size);
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
ec_reg_request_clear(&request);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(slave = ec_master_find_slave(
|
||||
master, 0, io.slave_position))) {
|
||||
up(&master->master_sem);
|
||||
ec_reg_request_clear(&request);
|
||||
EC_MASTER_ERR(master, "Slave %u does not exist!\n",
|
||||
io.slave_position);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// schedule request.
|
||||
list_add_tail(&request.list, &master->reg_requests);
|
||||
list_add_tail(&request.list, &slave->reg_requests);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->reg_queue,
|
||||
if (wait_event_interruptible(slave->reg_queue,
|
||||
request.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
|
|
@ -1114,16 +1108,16 @@ static int ec_ioctl_slave_reg_write(
|
|||
// abort request
|
||||
list_del(&request.list);
|
||||
up(&master->master_sem);
|
||||
kfree(contents);
|
||||
ec_reg_request_clear(&request);
|
||||
return -EINTR;
|
||||
}
|
||||
up(&master->master_sem);
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
wait_event(slave->reg_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
kfree(contents);
|
||||
ec_reg_request_clear(&request);
|
||||
|
||||
return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
|
@ -1608,7 +1602,7 @@ static int ec_ioctl_activate(
|
|||
|
||||
/* Set the memory as external process data memory for the
|
||||
* domains.
|
||||
*/
|
||||
*/
|
||||
offset = 0;
|
||||
list_for_each_entry(domain, &master->domains, list) {
|
||||
ecrt_domain_external_memory(domain,
|
||||
|
|
@ -1617,10 +1611,10 @@ static int ec_ioctl_activate(
|
|||
}
|
||||
|
||||
#ifdef EC_IOCTL_RTDM
|
||||
/* RTDM uses a different approach for memory-mapping, which has to be
|
||||
* initiated by the kernel.
|
||||
*/
|
||||
ret = ec_rtdm_mmap(ctx, &io.process_data);
|
||||
/* RTDM uses a different approach for memory-mapping, which has to be
|
||||
* initiated by the kernel.
|
||||
*/
|
||||
ret = ec_rtdm_mmap(ctx, &io.process_data);
|
||||
if (ret < 0) {
|
||||
EC_MASTER_ERR(master, "Failed to map process data"
|
||||
" memory to user space (code %i).\n", ret);
|
||||
|
|
@ -2488,6 +2482,58 @@ static int ec_ioctl_sc_create_sdo_request(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Create a register request.
|
||||
*/
|
||||
static int ec_ioctl_sc_create_reg_request(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_reg_request_t io;
|
||||
ec_slave_config_t *sc;
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
io.request_index = 0;
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
sc = ec_master_get_config(master, io.config_index);
|
||||
if (!sc) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
list_for_each_entry(reg, &sc->reg_requests, list) {
|
||||
io.request_index++;
|
||||
}
|
||||
|
||||
up(&master->master_sem); /** \fixme sc could be invalidated */
|
||||
|
||||
reg = ecrt_slave_config_create_reg_request_err(sc, io.mem_size);
|
||||
if (IS_ERR(reg)) {
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Create a VoE handler.
|
||||
*/
|
||||
static int ec_ioctl_sc_create_voe_handler(
|
||||
|
|
@ -2979,6 +3025,181 @@ static int ec_ioctl_sdo_request_data(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Read register data.
|
||||
*/
|
||||
static int ec_ioctl_reg_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_reg_request_t io;
|
||||
ec_slave_config_t *sc;
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (io.mem_size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor reg will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) io.data, ecrt_reg_request_data(reg),
|
||||
min(reg->mem_size, io.mem_size))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Gets an register request's state.
|
||||
*/
|
||||
static int ec_ioctl_reg_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_reg_request_t io;
|
||||
ec_slave_config_t *sc;
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor reg will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
io.state = ecrt_reg_request_state(reg);
|
||||
io.new_data = io.state == EC_REQUEST_SUCCESS && reg->dir == EC_DIR_INPUT;
|
||||
|
||||
if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Starts an register write operation.
|
||||
*/
|
||||
static int ec_ioctl_reg_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_reg_request_t io;
|
||||
ec_slave_config_t *sc;
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor reg will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (io.transfer_size > reg->mem_size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
if (copy_from_user(reg->data, (void __user *) io.data,
|
||||
io.transfer_size)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ecrt_reg_request_write(reg, io.address, io.transfer_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Starts an register read operation.
|
||||
*/
|
||||
static int ec_ioctl_reg_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_reg_request_t io;
|
||||
ec_slave_config_t *sc;
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* no locking of master_sem needed, because neither sc nor reg will not be
|
||||
* deleted in the meantime. */
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (io.transfer_size > reg->mem_size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
ecrt_reg_request_read(reg, io.address, io.transfer_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sets the VoE send header.
|
||||
*/
|
||||
static int ec_ioctl_voe_send_header(
|
||||
|
|
@ -3548,7 +3769,7 @@ static int ec_ioctl_slave_soe_write(
|
|||
/** Called when an ioctl() command is issued.
|
||||
*/
|
||||
long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
||||
unsigned int cmd, void *arg)
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
#if DEBUG_LATENCY
|
||||
cycles_t a = get_cycles(), b;
|
||||
|
|
@ -3876,6 +4097,13 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
|||
}
|
||||
ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_REG_REQUEST:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_create_reg_request(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_VOE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
|
|
@ -3947,6 +4175,26 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
|||
case EC_IOCTL_SDO_REQUEST_DATA:
|
||||
ret = ec_ioctl_sdo_request_data(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REG_REQUEST_DATA:
|
||||
ret = ec_ioctl_reg_request_data(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REG_REQUEST_STATE:
|
||||
ret = ec_ioctl_reg_request_state(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REG_REQUEST_WRITE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_reg_request_write(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REG_REQUEST_READ:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_reg_request_read(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_VOE_SEND_HEADER:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
*
|
||||
* Increment this when changing the ioctl interface!
|
||||
*/
|
||||
#define EC_IOCTL_VERSION_MAGIC 21
|
||||
#define EC_IOCTL_VERSION_MAGIC 22
|
||||
|
||||
// Command-line tool
|
||||
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
|
||||
|
|
@ -122,27 +122,32 @@
|
|||
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x38, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x3b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x3c, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x3d, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3e)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x3f)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x40)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x41, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x42, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x43, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x44, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x45, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x46, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x47, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x48, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x49, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x4a, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x4b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x4c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x4d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x4e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x4f, size_t)
|
||||
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3b, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x3c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x3d, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x3e, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3f)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x40)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x41)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x42, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x43, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x44, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x45, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x46, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x47, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x48, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x49, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4a, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4b, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x4c, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x4d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x4e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x4f, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x50, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x51, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x52, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x53, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x54, size_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -409,8 +414,8 @@ typedef struct {
|
|||
typedef struct {
|
||||
// inputs
|
||||
uint16_t slave_position;
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
uint16_t address;
|
||||
size_t size;
|
||||
uint8_t *data;
|
||||
} ec_ioctl_slave_reg_t;
|
||||
|
||||
|
|
@ -683,6 +688,22 @@ typedef struct {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
size_t mem_size;
|
||||
|
||||
// inputs/outputs
|
||||
uint32_t request_index;
|
||||
uint8_t *data;
|
||||
ec_request_state_t state;
|
||||
uint8_t new_data;
|
||||
uint16_t address;
|
||||
size_t transfer_size;
|
||||
} ec_ioctl_reg_request_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
|
|
|
|||
|
|
@ -208,9 +208,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
INIT_LIST_HEAD(&master->sii_requests);
|
||||
init_waitqueue_head(&master->sii_queue);
|
||||
|
||||
INIT_LIST_HEAD(&master->reg_requests);
|
||||
init_waitqueue_head(&master->reg_queue);
|
||||
|
||||
// init devices
|
||||
ret = ec_device_init(&master->devices[EC_DEVICE_MAIN], master);
|
||||
if (ret < 0)
|
||||
|
|
@ -429,16 +426,6 @@ void ec_master_clear_slaves(ec_master_t *master)
|
|||
wake_up(&master->sii_queue);
|
||||
}
|
||||
|
||||
while (!list_empty(&master->reg_requests)) {
|
||||
ec_reg_request_t *request =
|
||||
list_entry(master->reg_requests.next, ec_reg_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
EC_MASTER_WARN(master, "Discarding register request, slave %u"
|
||||
" about to be deleted.\n", request->slave->ring_position);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->reg_queue);
|
||||
}
|
||||
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
|
|
@ -874,8 +861,8 @@ void ec_master_queue_datagram(
|
|||
list_for_each_entry(queued_datagram, &master->datagram_queue, queue) {
|
||||
if (queued_datagram == datagram) {
|
||||
datagram->skip_count++;
|
||||
EC_MASTER_DBG(master, 1, "Skipping re-initialized datagram %p.\n",
|
||||
datagram);
|
||||
EC_MASTER_DBG(master, 1,
|
||||
"Datagram %p already queued (skipping).\n", datagram);
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,9 +276,6 @@ struct ec_master {
|
|||
struct list_head sii_requests; /**< SII write requests. */
|
||||
wait_queue_head_t sii_queue; /**< Wait queue for SII
|
||||
write requests from user space. */
|
||||
|
||||
struct list_head reg_requests; /**< Register requests. */
|
||||
wait_queue_head_t reg_queue; /**< Wait queue for register requests. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 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
|
||||
* Register request functions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "reg_request.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_reg_request_clear_data(ec_reg_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Register request constructor.
|
||||
*/
|
||||
int ec_reg_request_init(
|
||||
ec_reg_request_t *reg, /**< Register request. */
|
||||
size_t size /**< Memory size. */
|
||||
)
|
||||
{
|
||||
if (!(reg->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate %zu bytes of register memory.\n", size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(®->list);
|
||||
reg->mem_size = size;
|
||||
memset(reg->data, 0x00, size);
|
||||
reg->dir = EC_DIR_INVALID;
|
||||
reg->address = 0;
|
||||
reg->transfer_size = 0;
|
||||
reg->state = EC_INT_REQUEST_INIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Register request destructor.
|
||||
*/
|
||||
void ec_reg_request_clear(
|
||||
ec_reg_request_t *reg /**< Register request. */
|
||||
)
|
||||
{
|
||||
if (reg->data) {
|
||||
kfree(reg->data);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface.
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_reg_request_data(ec_reg_request_t *reg)
|
||||
{
|
||||
return reg->data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_request_state_t ecrt_reg_request_state(const ec_reg_request_t *reg)
|
||||
{
|
||||
return ec_request_state_translation_table[reg->state];
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_reg_request_write(ec_reg_request_t *reg, uint16_t address,
|
||||
size_t size)
|
||||
{
|
||||
reg->dir = EC_DIR_OUTPUT;
|
||||
reg->address = address;
|
||||
reg->transfer_size = min(size, reg->mem_size);
|
||||
reg->state = EC_INT_REQUEST_QUEUED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_reg_request_read(ec_reg_request_t *reg, uint16_t address,
|
||||
size_t size)
|
||||
{
|
||||
reg->dir = EC_DIR_INPUT;
|
||||
reg->address = address;
|
||||
reg->transfer_size = min(size, reg->mem_size);
|
||||
reg->state = EC_INT_REQUEST_QUEUED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_reg_request_data);
|
||||
EXPORT_SYMBOL(ecrt_reg_request_state);
|
||||
EXPORT_SYMBOL(ecrt_reg_request_write);
|
||||
EXPORT_SYMBOL(ecrt_reg_request_read);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 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 register request structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __EC_REG_REQUEST_H__
|
||||
#define __EC_REG_REQUEST_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Register request.
|
||||
*/
|
||||
struct ec_reg_request {
|
||||
struct list_head list; /**< List item. */
|
||||
size_t mem_size; /**< Size of data memory. */
|
||||
uint8_t *data; /**< Pointer to data memory. */
|
||||
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to the
|
||||
slave, EC_DIR_INPUT means reading from the slave. */
|
||||
uint16_t address; /**< Register address. */
|
||||
size_t transfer_size; /*< Size of the data to transfer. */
|
||||
ec_internal_request_state_t state; /**< Request state. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_reg_request_init(ec_reg_request_t *, size_t);
|
||||
void ec_reg_request_clear(ec_reg_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -155,6 +155,9 @@ void ec_slave_init(
|
|||
INIT_LIST_HEAD(&slave->slave_sdo_requests);
|
||||
init_waitqueue_head(&slave->sdo_queue);
|
||||
|
||||
INIT_LIST_HEAD(&slave->reg_requests);
|
||||
init_waitqueue_head(&slave->reg_queue);
|
||||
|
||||
INIT_LIST_HEAD(&slave->foe_requests);
|
||||
init_waitqueue_head(&slave->foe_queue);
|
||||
|
||||
|
|
@ -202,6 +205,16 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
|
|||
wake_up(&slave->sdo_queue);
|
||||
}
|
||||
|
||||
while (!list_empty(&slave->reg_requests)) {
|
||||
ec_reg_request_t *reg =
|
||||
list_entry(slave->reg_requests.next, ec_reg_request_t, list);
|
||||
list_del_init(®->list); // dequeue
|
||||
EC_SLAVE_WARN(slave, "Discarding register request,"
|
||||
" slave about to be deleted.\n");
|
||||
reg->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&slave->reg_queue);
|
||||
}
|
||||
|
||||
while (!list_empty(&slave->foe_requests)) {
|
||||
ec_master_foe_request_t *request =
|
||||
list_entry(slave->foe_requests.next,
|
||||
|
|
@ -224,8 +237,9 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
|
|||
wake_up(&slave->soe_queue);
|
||||
}
|
||||
|
||||
if (slave->config)
|
||||
if (slave->config) {
|
||||
ec_slave_config_detach(slave->config);
|
||||
}
|
||||
|
||||
// free all SDOs
|
||||
list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
|
||||
|
|
@ -251,8 +265,10 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */)
|
|||
kfree(pdo);
|
||||
}
|
||||
|
||||
if (slave->sii_words)
|
||||
if (slave->sii_words) {
|
||||
kfree(slave->sii_words);
|
||||
}
|
||||
|
||||
ec_fsm_slave_clear(&slave->fsm);
|
||||
ec_datagram_clear(&slave->fsm_datagram);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -227,6 +227,9 @@ struct ec_slave
|
|||
struct list_head slave_sdo_requests; /**< SDO access requests. */
|
||||
wait_queue_head_t sdo_queue; /**< Wait queue for SDO access requests
|
||||
from user space. */
|
||||
struct list_head reg_requests; /**< Register access requests. */
|
||||
wait_queue_head_t reg_queue; /**< Wait queue for register access requests
|
||||
from user space. */
|
||||
struct list_head foe_requests; /**< FoE write requests. */
|
||||
wait_queue_head_t foe_queue; /**< Wait queue for FoE requests from user
|
||||
space. */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -86,6 +86,7 @@ void ec_slave_config_init(
|
|||
|
||||
INIT_LIST_HEAD(&sc->sdo_configs);
|
||||
INIT_LIST_HEAD(&sc->sdo_requests);
|
||||
INIT_LIST_HEAD(&sc->reg_requests);
|
||||
INIT_LIST_HEAD(&sc->voe_handlers);
|
||||
INIT_LIST_HEAD(&sc->soe_configs);
|
||||
|
||||
|
|
@ -105,6 +106,7 @@ void ec_slave_config_clear(
|
|||
unsigned int i;
|
||||
ec_sdo_request_t *req, *next_req;
|
||||
ec_voe_handler_t *voe, *next_voe;
|
||||
ec_reg_request_t *reg, *next_reg;
|
||||
ec_soe_request_t *soe, *next_soe;
|
||||
|
||||
ec_slave_config_detach(sc);
|
||||
|
|
@ -127,6 +129,13 @@ void ec_slave_config_clear(
|
|||
kfree(req);
|
||||
}
|
||||
|
||||
// free all register requests
|
||||
list_for_each_entry_safe(reg, next_reg, &sc->reg_requests, list) {
|
||||
list_del(®->list);
|
||||
ec_reg_request_clear(reg);
|
||||
kfree(reg);
|
||||
}
|
||||
|
||||
// free all VoE handlers
|
||||
list_for_each_entry_safe(voe, next_voe, &sc->voe_handlers, list) {
|
||||
list_del(&voe->list);
|
||||
|
|
@ -429,7 +438,7 @@ const ec_soe_request_t *ec_slave_config_get_idn_by_pos_const(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a VoE handler via its position in the list.
|
||||
/** Finds a CoE handler via its position in the list.
|
||||
*/
|
||||
ec_sdo_request_t *ec_slave_config_find_sdo_request(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
|
|
@ -449,6 +458,26 @@ ec_sdo_request_t *ec_slave_config_find_sdo_request(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a register handler via its position in the list.
|
||||
*/
|
||||
ec_reg_request_t *ec_slave_config_find_reg_request(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
unsigned int pos /**< Position in the list. */
|
||||
)
|
||||
{
|
||||
ec_reg_request_t *reg;
|
||||
|
||||
list_for_each_entry(reg, &sc->reg_requests, list) {
|
||||
if (pos--)
|
||||
continue;
|
||||
return reg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Finds a VoE handler via its position in the list.
|
||||
*/
|
||||
ec_voe_handler_t *ec_slave_config_find_voe_handler(
|
||||
|
|
@ -965,6 +994,49 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_reg_request(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request_err(
|
||||
ec_slave_config_t *sc, size_t size)
|
||||
{
|
||||
ec_reg_request_t *reg;
|
||||
int ret;
|
||||
|
||||
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, size = %zu)\n",
|
||||
__func__, sc, size);
|
||||
|
||||
if (!(reg = (ec_reg_request_t *)
|
||||
kmalloc(sizeof(ec_reg_request_t), GFP_KERNEL))) {
|
||||
EC_CONFIG_ERR(sc, "Failed to allocate register request memory!\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = ec_reg_request_init(reg, size);
|
||||
if (ret) {
|
||||
kfree(reg);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
list_add_tail(®->list, &sc->reg_requests);
|
||||
up(&sc->master->master_sem);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request(
|
||||
ec_slave_config_t *sc, size_t size)
|
||||
{
|
||||
ec_reg_request_t *reg =
|
||||
ecrt_slave_config_create_reg_request_err(sc, size);
|
||||
return IS_ERR(reg) ? NULL : reg;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_voe_handler(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
|
|
@ -1101,6 +1173,7 @@ 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_voe_handler);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_reg_request);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_state);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_idn);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -141,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 voe_handlers; /**< List of VoE handlers. */
|
||||
struct list_head reg_requests; /**< List of register requests. */
|
||||
struct list_head soe_configs; /**< List of SoE configurations. */
|
||||
|
||||
ec_coe_emerg_ring_t emerg_ring; /**< CoE emergency ring buffer. */
|
||||
|
|
@ -165,6 +166,8 @@ const ec_soe_request_t *ec_slave_config_get_idn_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_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 *,
|
||||
unsigned int);
|
||||
|
||||
|
|
@ -172,6 +175,8 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
|
|||
ec_slave_config_t *, uint16_t, uint8_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(
|
||||
ec_slave_config_t *, size_t);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -48,20 +48,20 @@ string CommandRegRead::helpString(const string &binaryBaseName) const
|
|||
stringstream str;
|
||||
|
||||
str << binaryBaseName << " " << getName()
|
||||
<< " [OPTIONS] <OFFSET> [LENGTH]" << endl
|
||||
<< " [OPTIONS] <ADDRESS> [SIZE]" << endl
|
||||
<< endl
|
||||
<< getBriefDescription() << endl
|
||||
<< endl
|
||||
<< "This command requires a single slave to be selected." << endl
|
||||
<< endl
|
||||
<< "Arguments:" << endl
|
||||
<< " OFFSET is the register address. Must" << endl
|
||||
<< " be an unsigned 16 bit number." << endl
|
||||
<< " LENGTH is the number of bytes to read and must also be" << endl
|
||||
<< " an unsigned 16 bit number. OFFSET plus LENGTH" << endl
|
||||
<< " may not exceed 64k. The length is ignored (and" << endl
|
||||
<< " can be omitted), if a selected data type" << endl
|
||||
<< " implies a length." << endl
|
||||
<< " ADDRESS is the register address. Must" << endl
|
||||
<< " be an unsigned 16 bit number." << endl
|
||||
<< " SIZE is the number of bytes to read and must also be" << endl
|
||||
<< " an unsigned 16 bit number. ADDRESS plus SIZE" << endl
|
||||
<< " may not exceed 64k. The size is ignored (and" << endl
|
||||
<< " can be omitted), if a selected data type" << endl
|
||||
<< " implies a size." << endl
|
||||
<< endl
|
||||
<< typeInfo()
|
||||
<< endl
|
||||
|
|
@ -81,7 +81,7 @@ string CommandRegRead::helpString(const string &binaryBaseName) const
|
|||
void CommandRegRead::execute(const StringVector &args)
|
||||
{
|
||||
SlaveList slaves;
|
||||
ec_ioctl_slave_reg_t data;
|
||||
ec_ioctl_slave_reg_t io;
|
||||
stringstream strOffset, err;
|
||||
const DataType *dataType = NULL;
|
||||
|
||||
|
|
@ -93,9 +93,9 @@ void CommandRegRead::execute(const StringVector &args)
|
|||
strOffset << args[0];
|
||||
strOffset
|
||||
>> resetiosflags(ios::basefield) // guess base from prefix
|
||||
>> data.offset;
|
||||
>> io.address;
|
||||
if (strOffset.fail()) {
|
||||
err << "Invalid offset '" << args[0] << "'!";
|
||||
err << "Invalid address '" << args[0] << "'!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
|
|
@ -104,18 +104,18 @@ void CommandRegRead::execute(const StringVector &args)
|
|||
strLength << args[1];
|
||||
strLength
|
||||
>> resetiosflags(ios::basefield) // guess base from prefix
|
||||
>> data.length;
|
||||
>> io.size;
|
||||
if (strLength.fail()) {
|
||||
err << "Invalid length '" << args[1] << "'!";
|
||||
err << "Invalid size '" << args[1] << "'!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
if (!data.length) {
|
||||
if (!io.size) {
|
||||
err << "Length may not be zero!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
} else { // no length argument given
|
||||
data.length = 0;
|
||||
} else { // no size argument given
|
||||
io.size = 0;
|
||||
}
|
||||
|
||||
if (!getDataType().empty()) {
|
||||
|
|
@ -125,19 +125,19 @@ void CommandRegRead::execute(const StringVector &args)
|
|||
}
|
||||
|
||||
if (dataType->byteSize) {
|
||||
// override length argument
|
||||
data.length = dataType->byteSize;
|
||||
// override size argument
|
||||
io.size = dataType->byteSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.length) {
|
||||
err << "The length argument is mandatory, if no datatype is " << endl
|
||||
<< "specified, or the datatype does not imply a length!";
|
||||
if (!io.size) {
|
||||
err << "The size argument is mandatory, if no datatype is " << endl
|
||||
<< "specified, or the datatype does not imply a size!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
if ((uint32_t) data.offset + data.length > 0xffff) {
|
||||
err << "Offset and length exceeding 64k!";
|
||||
if ((uint32_t) io.address + io.size > 0xffff) {
|
||||
err << "Address and size exceeding 64k!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
|
|
@ -148,25 +148,25 @@ void CommandRegRead::execute(const StringVector &args)
|
|||
if (slaves.size() != 1) {
|
||||
throwSingleSlaveRequired(slaves.size());
|
||||
}
|
||||
data.slave_position = slaves.front().position;
|
||||
io.slave_position = slaves.front().position;
|
||||
|
||||
data.data = new uint8_t[data.length];
|
||||
io.data = new uint8_t[io.size];
|
||||
|
||||
try {
|
||||
m.readReg(&data);
|
||||
m.readReg(&io);
|
||||
} catch (MasterDeviceException &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
outputData(cout, dataType, data.data, data.length);
|
||||
outputData(cout, dataType, io.data, io.size);
|
||||
} catch (SizeException &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throwCommandException(e.what());
|
||||
}
|
||||
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
|
|
@ -57,7 +57,7 @@ string CommandRegWrite::helpString(const string &binaryBaseName) const
|
|||
<< "This command requires a single slave to be selected." << endl
|
||||
<< endl
|
||||
<< "Arguments:" << endl
|
||||
<< " OFFSET is the register address to write to." << endl
|
||||
<< " ADDRESS is the register address to write to." << endl
|
||||
<< " DATA depends on whether a datatype was specified" << endl
|
||||
<< " with the --type option: If not, DATA must be" << endl
|
||||
<< " either a path to a file with data to write," << endl
|
||||
|
|
@ -83,7 +83,7 @@ string CommandRegWrite::helpString(const string &binaryBaseName) const
|
|||
void CommandRegWrite::execute(const StringVector &args)
|
||||
{
|
||||
stringstream strOffset, err;
|
||||
ec_ioctl_slave_reg_t data;
|
||||
ec_ioctl_slave_reg_t io;
|
||||
ifstream file;
|
||||
SlaveList slaves;
|
||||
|
||||
|
|
@ -95,22 +95,22 @@ void CommandRegWrite::execute(const StringVector &args)
|
|||
strOffset << args[0];
|
||||
strOffset
|
||||
>> resetiosflags(ios::basefield) // guess base from prefix
|
||||
>> data.offset;
|
||||
>> io.address;
|
||||
if (strOffset.fail()) {
|
||||
err << "Invalid offset '" << args[0] << "'!";
|
||||
err << "Invalid address '" << args[0] << "'!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
if (getDataType().empty()) {
|
||||
if (args[1] == "-") {
|
||||
loadRegData(&data, cin);
|
||||
loadRegData(&io, cin);
|
||||
} else {
|
||||
file.open(args[1].c_str(), ifstream::in | ifstream::binary);
|
||||
if (file.fail()) {
|
||||
err << "Failed to open '" << args[1] << "'!";
|
||||
throwCommandException(err);
|
||||
}
|
||||
loadRegData(&data, file);
|
||||
loadRegData(&io, file);
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -123,30 +123,30 @@ void CommandRegWrite::execute(const StringVector &args)
|
|||
}
|
||||
|
||||
if (dataType->byteSize) {
|
||||
data.length = dataType->byteSize;
|
||||
io.size = dataType->byteSize;
|
||||
} else {
|
||||
data.length = 1024; // FIXME
|
||||
io.size = 1024; // FIXME
|
||||
}
|
||||
|
||||
data.data = new uint8_t[data.length];
|
||||
io.data = new uint8_t[io.size];
|
||||
|
||||
try {
|
||||
data.length = interpretAsType(
|
||||
dataType, args[1], data.data, data.length);
|
||||
io.size = interpretAsType(
|
||||
dataType, args[1], io.data, io.size);
|
||||
} catch (SizeException &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throwCommandException(e.what());
|
||||
} catch (ios::failure &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
err << "Invalid value argument '" << args[1]
|
||||
<< "' for type '" << dataType->name << "'!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
}
|
||||
|
||||
if ((uint32_t) data.offset + data.length > 0xffff) {
|
||||
err << "Offset and length exceeding 64k!";
|
||||
delete [] data.data;
|
||||
if ((uint32_t) io.address + io.size > 0xffff) {
|
||||
err << "Address and size exceeding 64k!";
|
||||
delete [] io.data;
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
|
|
@ -154,22 +154,22 @@ void CommandRegWrite::execute(const StringVector &args)
|
|||
try {
|
||||
m.open(MasterDevice::ReadWrite);
|
||||
} catch (MasterDeviceException &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throw e;
|
||||
}
|
||||
|
||||
slaves = selectedSlaves(m);
|
||||
if (slaves.size() != 1) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throwSingleSlaveRequired(slaves.size());
|
||||
}
|
||||
data.slave_position = slaves.front().position;
|
||||
io.slave_position = slaves.front().position;
|
||||
|
||||
// send data to master
|
||||
try {
|
||||
m.writeReg(&data);
|
||||
m.writeReg(&io);
|
||||
} catch (MasterDeviceException &e) {
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
|
@ -177,13 +177,13 @@ void CommandRegWrite::execute(const StringVector &args)
|
|||
cerr << "Register writing finished." << endl;
|
||||
}
|
||||
|
||||
delete [] data.data;
|
||||
delete [] io.data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void CommandRegWrite::loadRegData(
|
||||
ec_ioctl_slave_reg_t *data,
|
||||
ec_ioctl_slave_reg_t *io,
|
||||
const istream &in
|
||||
)
|
||||
{
|
||||
|
|
@ -201,11 +201,11 @@ void CommandRegWrite::loadRegData(
|
|||
err << "Invalid data size " << contents.size() << "!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
data->length = contents.size();
|
||||
io->size = contents.size();
|
||||
|
||||
// allocate buffer and read file into buffer
|
||||
data->data = new uint8_t[data->length];
|
||||
contents.copy((char *) data->data, contents.size());
|
||||
io->data = new uint8_t[io->size];
|
||||
contents.copy((char *) io->data, contents.size());
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
Loading…
Reference in New Issue