Added interface to read/write register contents; re-worked register requests.

This commit is contained in:
Florian Pose 2012-11-14 22:12:57 +01:00
parent 139168474d
commit 4773e88bf6
25 changed files with 1220 additions and 325 deletions

View File

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

View File

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

View File

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

138
lib/reg_request.c Normal file
View File

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

47
lib/reg_request.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&reg->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.

View File

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

View File

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

View File

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

View File

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

View File

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

132
master/reg_request.c Normal file
View File

@ -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(&reg->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 */
/*****************************************************************************/

66
master/reg_request.h Normal file
View File

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

View File

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

View File

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

View File

@ -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(&reg->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(&reg->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);

View File

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

View File

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

View File

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