# HG changeset patch # User Florian Pose # Date 1352927577 -3600 # Node ID 2c3ccdde391980f15c3f7d468b6bb25588b16ef4 # Parent 86ebf18a029fe85caccf3cfd0fc473a18b7b2657 Added interface to read/write register contents; re-worked register requests. diff -r 86ebf18a029f -r 2c3ccdde3919 include/ecrt.h --- a/include/ecrt.h Wed Nov 14 22:08:32 2012 +0100 +++ b/include/ecrt.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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 @@ 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_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 diff -r 86ebf18a029f -r 2c3ccdde3919 lib/Makefile.am --- a/lib/Makefile.am Wed Nov 14 22:08:32 2012 +0100 +++ b/lib/Makefile.am Wed Nov 14 22:12:57 2012 +0100 @@ -36,6 +36,7 @@ common.c \ domain.c \ master.c \ + reg_request.c \ sdo_request.c \ slave_config.c \ voe_handler.c @@ -43,6 +44,7 @@ noinst_HEADERS = \ domain.h \ master.h \ + reg_request.h \ sdo_request.h \ slave_config.h \ voe_handler.h diff -r 86ebf18a029f -r 2c3ccdde3919 lib/master.c --- a/lib/master.c Wed Nov 14 22:08:32 2012 +0100 +++ b/lib/master.c Wed Nov 14 22:12:57 2012 +0100 @@ -192,6 +192,7 @@ 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); diff -r 86ebf18a029f -r 2c3ccdde3919 lib/reg_request.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/reg_request.c Wed Nov 14 22:12:57 2012 +0100 @@ -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 + * . + * + * --- + * + * 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 +#include + +#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))); + } +} + +/*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 lib/reg_request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/reg_request.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 + * . + * + * --- + * + * 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 *); + +/*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 lib/slave_config.c --- a/lib/slave_config.c Wed Nov 14 22:08:32 2012 +0100 +++ b/lib/slave_config.c Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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 @@ /*****************************************************************************/ +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) { diff -r 86ebf18a029f -r 2c3ccdde3919 lib/slave_config.h --- a/lib/slave_config.h Wed Nov 14 22:08:32 2012 +0100 +++ b/lib/slave_config.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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; }; diff -r 86ebf18a029f -r 2c3ccdde3919 master/Kbuild.in --- a/master/Kbuild.in Wed Nov 14 22:08:32 2012 +0100 +++ b/master/Kbuild.in Wed Nov 14 22:12:57 2012 +0100 @@ -60,6 +60,7 @@ pdo.o \ pdo_entry.o \ pdo_list.o \ + reg_request.o \ sdo.o \ sdo_entry.o \ sdo_request.o \ diff -r 86ebf18a029f -r 2c3ccdde3919 master/Makefile.am --- a/master/Makefile.am Wed Nov 14 22:08:32 2012 +0100 +++ b/master/Makefile.am Wed Nov 14 22:12:57 2012 +0100 @@ -60,6 +60,7 @@ 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 \ diff -r 86ebf18a029f -r 2c3ccdde3919 master/fsm_master.c --- a/master/fsm_master.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/fsm_master.c Wed Nov 14 22:12:57 2012 +0100 @@ -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_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 @@ /*****************************************************************************/ -/** 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 @@ return 0; } - /*****************************************************************************/ /** Master action: IDLE. @@ -563,12 +505,9 @@ } // 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,64 +1215,11 @@ EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SDO request.\n"); // check for another SDO request - if (ec_fsm_master_action_process_sdo(fsm)) + 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)) - return; // processing another request - - ec_fsm_master_restart(fsm); -} - -/*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 master/fsm_master.h --- a/master/fsm_master.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/fsm_master.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ /*****************************************************************************/ -/** 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 @@ 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. */ diff -r 86ebf18a029f -r 2c3ccdde3919 master/fsm_slave.c --- a/master/fsm_slave.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/fsm_slave.c Wed Nov 14 22:12:57 2012 +0100 @@ -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_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 @@ // do nothing } - /*****************************************************************************/ /** Slave state: READY. @@ -151,6 +153,11 @@ 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 @@ 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 @@ 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 @@ /*****************************************************************************/ +/** 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. diff -r 86ebf18a029f -r 2c3ccdde3919 master/fsm_slave.h --- a/master/fsm_slave.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/fsm_slave.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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. */ diff -r 86ebf18a029f -r 2c3ccdde3919 master/ioctl.c --- a/master/ioctl.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/ioctl.c Wed Nov 14 22:12:57 2012 +0100 @@ -977,51 +977,48 @@ 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; - - if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { - return -EFAULT; - } - - if (!data.length) + int ret; + + if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { + return -EFAULT; + } + + 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)) + } + + // init register request + 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, data.slave_position))) { - up(&master->master_sem); + master, 0, io.slave_position))) { + up(&master->master_sem); + ec_reg_request_clear(&request); EC_MASTER_ERR(master, "Slave %u does not exist!\n", - data.slave_position); + io.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; - // 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 @@ // 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 @@ 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; - - if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { - return -EFAULT; - } - - if (!data.length) + int ret; + + if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { + return -EFAULT; + } + + 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)) + } + + // init register request + 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, data.slave_position))) { - up(&master->master_sem); + master, 0, io.slave_position))) { + up(&master->master_sem); + ec_reg_request_clear(&request); EC_MASTER_ERR(master, "Slave %u does not exist!\n", - data.slave_position); - kfree(contents); + io.slave_position); 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; - // 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 @@ // 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); - - kfree(contents); + wait_event(slave->reg_queue, request.state != EC_INT_REQUEST_BUSY); + + ec_reg_request_clear(&request); return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; } @@ -1608,7 +1602,7 @@ /* 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 @@ } #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 @@ /*****************************************************************************/ +/** 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 @@ /*****************************************************************************/ +/** 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 @@ /** 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 @@ } 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 @@ 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; diff -r 86ebf18a029f -r 2c3ccdde3919 master/ioctl.h --- a/master/ioctl.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/ioctl.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 { // 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; @@ -686,6 +691,22 @@ 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; // inputs/outputs uint32_t voe_index; diff -r 86ebf18a029f -r 2c3ccdde3919 master/master.c --- a/master/master.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/master.c Wed Nov 14 22:12:57 2012 +0100 @@ -208,9 +208,6 @@ 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 @@ 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 @@ 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; } diff -r 86ebf18a029f -r 2c3ccdde3919 master/master.h --- a/master/master.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/master.h Wed Nov 14 22:12:57 2012 +0100 @@ -276,9 +276,6 @@ 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. */ }; /*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 master/reg_request.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/reg_request.c Wed Nov 14 22:12:57 2012 +0100 @@ -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 +#include +#include + +#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 */ + +/*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 master/reg_request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/reg_request.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 + +#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 diff -r 86ebf18a029f -r 2c3ccdde3919 master/slave.c --- a/master/slave.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/slave.c Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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); } diff -r 86ebf18a029f -r 2c3ccdde3919 master/slave.h --- a/master/slave.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/slave.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 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. */ diff -r 86ebf18a029f -r 2c3ccdde3919 master/slave_config.c --- a/master/slave_config.c Wed Nov 14 22:08:32 2012 +0100 +++ b/master/slave_config.c Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ 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 @@ 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 @@ 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 @@ /*****************************************************************************/ -/** 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 @@ /*****************************************************************************/ +/** 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 @@ /*****************************************************************************/ +/** 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_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); diff -r 86ebf18a029f -r 2c3ccdde3919 master/slave_config.h --- a/master/slave_config.h Wed Nov 14 22:08:32 2012 +0100 +++ b/master/slave_config.h Wed Nov 14 22:12:57 2012 +0100 @@ -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 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_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_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); /*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 tool/CommandRegRead.cpp --- a/tool/CommandRegRead.cpp Wed Nov 14 22:08:32 2012 +0100 +++ b/tool/CommandRegRead.cpp Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ stringstream str; str << binaryBaseName << " " << getName() - << " [OPTIONS] [LENGTH]" << endl + << " [OPTIONS]
[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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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; } /*****************************************************************************/ diff -r 86ebf18a029f -r 2c3ccdde3919 tool/CommandRegWrite.cpp --- a/tool/CommandRegWrite.cpp Wed Nov 14 22:08:32 2012 +0100 +++ b/tool/CommandRegWrite.cpp Wed Nov 14 22:12:57 2012 +0100 @@ -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 @@ << "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 @@ 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 @@ 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 @@ } if (dataType->byteSize) { - data.length = dataType->byteSize; + io.size = dataType->byteSize; } else { - data.length = 1024; // FIXME - } - - data.data = new uint8_t[data.length]; + io.size = 1024; // FIXME + } + + 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 @@ 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 @@ 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 @@ 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()); +} + +/*****************************************************************************/