# HG changeset patch # User Florian Pose # Date 1319446167 -7200 # Node ID 5144a4bc6184167ff779306505b669e1d81262a7 # Parent 98e1e773bed0c2ec0b9eab65946b89d12c199d05 Added ecrt_master_sdo_download_complete() for ad-hoc downloading SDOs (also via the command-line tool). diff -r 98e1e773bed0 -r 5144a4bc6184 include/ecrt.h --- a/include/ecrt.h Mon Oct 24 10:47:36 2011 +0200 +++ b/include/ecrt.h Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /****************************************************************************** * - * $Id$ + * $Id: ecrt.h,v ebda087981e1 2011/09/15 13:58:58 fp $ * * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH * @@ -62,8 +62,9 @@ * ecrt_master_get_slave(), ecrt_master_get_sync_manager(), * ecrt_master_get_pdo() and ecrt_master_get_pdo_entry()) to get information * about the currently connected slaves and the PDO entries provided. - * - Added ecrt_master_sdo_download() and ecrt_master_sdo_upload() - * methods to let an application transfer SDOs before activating the master. + * - Added ecrt_master_sdo_download(), ecrt_master_sdo_download_complete() and + * ecrt_master_sdo_upload() methods to let an application transfer SDOs + * before activating the master. * - Changed the meaning of the negative return values of * ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*(). * - Implemented the Vendor-specific over EtherCAT mailbox protocol. See @@ -722,6 +723,25 @@ uint32_t *abort_code /**< Abort code of the SDO download. */ ); +/** Executes an SDO download request to write data to a slave via complete + * access. + * + * This request is processed by the master state machine. This method blocks, + * until the request has been processed and may not be called in realtime + * context. + * + * \retval 0 Success. + * \retval <0 Error code. + */ +int ecrt_master_sdo_download_complete( + ec_master_t *master, /**< EtherCAT master. */ + uint16_t slave_position, /**< Slave position. */ + uint16_t index, /**< Index of the SDO. */ + uint8_t *data, /**< Data buffer to download. */ + size_t data_size, /**< Size of the data buffer. */ + uint32_t *abort_code /**< Abort code of the SDO download. */ + ); + /** Executes an SDO upload request to read data from a slave. * * This request is processed by the master state machine. This method blocks, diff -r 98e1e773bed0 -r 5144a4bc6184 lib/master.c --- a/lib/master.c Mon Oct 24 10:47:36 2011 +0200 +++ b/lib/master.c Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /****************************************************************************** * - * $Id$ + * $Id: master.c,v b544025bd696 2011/05/12 14:45:02 fp $ * * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH * @@ -349,6 +349,34 @@ download.slave_position = slave_position; download.sdo_index = index; download.sdo_entry_subindex = subindex; + download.complete_access = 0; + download.data_size = data_size; + download.data = data; + + if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download) == -1) { + if (errno == EIO && abort_code) { + *abort_code = download.abort_code; + } + fprintf(stderr, "Failed to execute SDO download: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +int ecrt_master_sdo_download_complete(ec_master_t *master, + uint16_t slave_position, uint16_t index, uint8_t *data, + size_t data_size, uint32_t *abort_code) +{ + ec_ioctl_slave_sdo_download_t download; + + download.slave_position = slave_position; + download.sdo_index = index; + download.sdo_entry_subindex = 0; + download.complete_access = 1; download.data_size = data_size; download.data = data; diff -r 98e1e773bed0 -r 5144a4bc6184 master/cdev.c --- a/master/cdev.c Mon Oct 24 10:47:36 2011 +0200 +++ b/master/cdev.c Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /****************************************************************************** * - * $Id$ + * $Id: cdev.c,v ebda087981e1 2011/09/15 13:58:58 fp $ * * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH * @@ -902,9 +902,14 @@ return -EFAULT; } - retval = ecrt_master_sdo_download(master, data.slave_position, - data.sdo_index, data.sdo_entry_subindex, sdo_data, data.data_size, - &data.abort_code); + if (data.complete_access) { + retval = ecrt_master_sdo_download_complete(master, data.slave_position, + data.sdo_index, sdo_data, data.data_size, &data.abort_code); + } else { + retval = ecrt_master_sdo_download(master, data.slave_position, + data.sdo_index, data.sdo_entry_subindex, sdo_data, + data.data_size, &data.abort_code); + } kfree(sdo_data); diff -r 98e1e773bed0 -r 5144a4bc6184 master/ioctl.h --- a/master/ioctl.h Mon Oct 24 10:47:36 2011 +0200 +++ b/master/ioctl.h Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /****************************************************************************** * - * $Id$ + * $Id: ioctl.h,v 8b358effa78b 2011/03/14 10:20:05 ch1010277 $ * * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH * @@ -56,7 +56,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 12 +#define EC_IOCTL_VERSION_MAGIC 13 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -372,6 +372,7 @@ uint16_t slave_position; uint16_t sdo_index; uint8_t sdo_entry_subindex; + uint8_t complete_access; uint32_t data_size; uint8_t *data; diff -r 98e1e773bed0 -r 5144a4bc6184 master/master.c --- a/master/master.c Mon Oct 24 10:47:36 2011 +0200 +++ b/master/master.c Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /****************************************************************************** * - * $Id$ + * $Id: master.c,v afb40fd6018e 2011/09/16 12:10:23 fp $ * * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH * @@ -2482,6 +2482,88 @@ /*****************************************************************************/ +int ecrt_master_sdo_download_complete(ec_master_t *master, + uint16_t slave_position, uint16_t index, uint8_t *data, + size_t data_size, uint32_t *abort_code) +{ + ec_master_sdo_request_t request; + + EC_MASTER_DBG(master, 1, "%s(master = 0x%p," + " slave_position = %u, index = 0x%04X," + " data = 0x%p, data_size = %zu, abort_code = 0x%p)\n", + __func__, master, slave_position, index, data, data_size, + abort_code); + + if (!data_size) { + EC_MASTER_ERR(master, "Zero data size!\n"); + return -EINVAL; + } + + ec_sdo_request_init(&request.req); + ec_sdo_request_address(&request.req, index, 0); + if (ec_sdo_request_alloc(&request.req, data_size)) { + ec_sdo_request_clear(&request.req); + return -ENOMEM; + } + + request.req.complete_access = 1; + memcpy(request.req.data, data, data_size); + request.req.data_size = data_size; + ecrt_sdo_request_write(&request.req); + + if (down_interruptible(&master->master_sem)) + return -EINTR; + + if (!(request.slave = ec_master_find_slave(master, 0, slave_position))) { + up(&master->master_sem); + EC_MASTER_ERR(master, "Slave %u does not exist!\n", slave_position); + ec_sdo_request_clear(&request.req); + return -EINVAL; + } + + EC_SLAVE_DBG(request.slave, 1, "Schedule SDO download request" + " (complete access).\n"); + + // schedule request. + list_add_tail(&request.list, &request.slave->slave_sdo_requests); + + up(&master->master_sem); + + // wait for processing through FSM + if (wait_event_interruptible(request.slave->sdo_queue, + request.req.state != EC_INT_REQUEST_QUEUED)) { + // interrupted by signal + down(&master->master_sem); + if (request.req.state == EC_INT_REQUEST_QUEUED) { + list_del(&request.list); + up(&master->master_sem); + ec_sdo_request_clear(&request.req); + return -EINTR; + } + // request already processing: interrupt not possible. + up(&master->master_sem); + } + + // wait until master FSM has finished processing + wait_event(request.slave->sdo_queue, + request.req.state != EC_INT_REQUEST_BUSY); + + EC_SLAVE_DBG(request.slave, 1, "Finished SDO download request" + " (complete access).\n"); + + *abort_code = request.req.abort_code; + + if (request.req.state == EC_INT_REQUEST_SUCCESS) { + return 0; + } else if (request.req.errno) { + return -request.req.errno; + } else { + return -EIO; + } +} + +/*****************************************************************************/ + int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position, uint16_t index, uint8_t subindex, uint8_t *target, size_t target_size, size_t *result_size, uint32_t *abort_code) @@ -2753,6 +2835,7 @@ EXPORT_SYMBOL(ecrt_master_sync_monitor_queue); EXPORT_SYMBOL(ecrt_master_sync_monitor_process); EXPORT_SYMBOL(ecrt_master_sdo_download); +EXPORT_SYMBOL(ecrt_master_sdo_download_complete); EXPORT_SYMBOL(ecrt_master_sdo_upload); EXPORT_SYMBOL(ecrt_master_write_idn); EXPORT_SYMBOL(ecrt_master_read_idn); diff -r 98e1e773bed0 -r 5144a4bc6184 tool/CommandDownload.cpp --- a/tool/CommandDownload.cpp Mon Oct 24 10:47:36 2011 +0200 +++ b/tool/CommandDownload.cpp Mon Oct 24 10:49:27 2011 +0200 @@ -1,6 +1,6 @@ /***************************************************************************** * - * $Id$ + * $Id: CommandDownload.cpp,v 4f682084c643 2010/10/25 08:12:26 fp $ * * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH * @@ -49,6 +49,7 @@ str << binaryBaseName << " " << getName() << " [OPTIONS] " << endl + << " [OPTIONS] " << endl << endl << getBriefDescription() << endl << endl @@ -60,6 +61,9 @@ << "information service or the SDO is not in the dictionary," << endl << "the --type option is mandatory." << endl << endl + << "The second call (without ) uses the complete" << endl + << "access method." << endl + << endl << typeInfo() << endl << "Arguments:" << endl @@ -68,7 +72,8 @@ << " SUBINDEX is the SDO entry subindex and must be an" << endl << " unsigned 8 bit number." << endl << " VALUE is the value to download and must correspond" << endl - << " to the SDO entry datatype (see above)." << endl + << " to the SDO entry datatype (see above). Use" << endl + << " '-' to read from standard input." << endl << endl << "Command-specific options:" << endl << " --alias -a " << endl @@ -85,16 +90,18 @@ void CommandDownload::execute(const StringVector &args) { - stringstream strIndex, strSubIndex, err; + stringstream strIndex, err; ec_ioctl_slave_sdo_download_t data; - unsigned int number; + unsigned int valueIndex; const DataType *dataType = NULL; SlaveList slaves; - if (args.size() != 3) { - err << "'" << getName() << "' takes 3 arguments!"; + if (args.size() != 2 && args.size() != 3) { + err << "'" << getName() << "' takes 2 or 3 arguments!"; throwInvalidUsageException(err); } + data.complete_access = args.size() == 2; + valueIndex = data.complete_access ? 1 : 2; strIndex << args[0]; strIndex @@ -105,15 +112,22 @@ throwInvalidUsageException(err); } - strSubIndex << args[1]; - strSubIndex - >> resetiosflags(ios::basefield) // guess base from prefix - >> number; - if (strSubIndex.fail() || number > 0xff) { - err << "Invalid SDO subindex '" << args[1] << "'!"; - throwInvalidUsageException(err); - } - data.sdo_entry_subindex = number; + if (data.complete_access) { + data.sdo_entry_subindex = 0; + } else { + stringstream strSubIndex; + unsigned int number; + + strSubIndex << args[1]; + strSubIndex + >> resetiosflags(ios::basefield) // guess base from prefix + >> number; + if (strSubIndex.fail() || number > 0xff) { + err << "Invalid SDO subindex '" << args[1] << "'!"; + throwInvalidUsageException(err); + } + data.sdo_entry_subindex = number; + } MasterDevice m(getSingleMasterIndex()); m.open(MasterDevice::ReadWrite); @@ -147,17 +161,59 @@ } } - if (dataType->byteSize) { - data.data_size = dataType->byteSize; + if (args[valueIndex] == "-") { + ostringstream tmp; + + tmp << cin.rdbuf(); + string const &contents = tmp.str(); + + if (!contents.size()) { + err << "Invalid data size " << contents.size() << "! " + << "Must be non-zero."; + throwCommandException(err); + } + data.data_size = contents.size(); + data.data = new uint8_t[data.data_size + 1]; + + try { + data.data_size = interpretAsType( + dataType, contents, data.data, data.data_size); + } catch (SizeException &e) { + delete [] data.data; + throwCommandException(e.what()); + } catch (ios::failure &e) { + delete [] data.data; + err << "Invalid value argument '" << args[2] + << "' for type '" << dataType->name << "'!"; + throwInvalidUsageException(err); + } + } else { - data.data_size = DefaultBufferSize; - } - - data.data = new uint8_t[data.data_size + 1]; + if (dataType->byteSize) { + data.data_size = dataType->byteSize; + } else { + data.data_size = DefaultBufferSize; + } + + data.data = new uint8_t[data.data_size + 1]; + + try { + data.data_size = interpretAsType( + dataType, args[valueIndex], data.data, data.data_size); + } catch (SizeException &e) { + delete [] data.data; + throwCommandException(e.what()); + } catch (ios::failure &e) { + delete [] data.data; + err << "Invalid value argument '" << args[2] + << "' for type '" << dataType->name << "'!"; + throwInvalidUsageException(err); + } + } try { data.data_size = interpretAsType( - dataType, args[2], data.data, data.data_size); + dataType, args[valueIndex], data.data, data.data_size); } catch (SizeException &e) { delete [] data.data; throwCommandException(e.what());