--- a/include/ecrt.h Mon Oct 24 10:47:36 2011 +0200
+++ b/include/ecrt.h Mon Oct 24 10:49:27 2011 +0200
@@ -64,8 +64,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
@@ -656,6 +657,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,
--- a/lib/master.c Mon Oct 24 10:47:36 2011 +0200
+++ b/lib/master.c Mon Oct 24 10:49:27 2011 +0200
@@ -340,6 +340,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;
--- a/master/cdev.c Mon Oct 24 10:47:36 2011 +0200
+++ b/master/cdev.c Mon Oct 24 10:49:27 2011 +0200
@@ -900,9 +900,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);
--- a/master/ioctl.h Mon Oct 24 10:47:36 2011 +0200
+++ b/master/ioctl.h Mon Oct 24 10:49:27 2011 +0200
@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
-#define EC_IOCTL_VERSION_MAGIC 11
+#define EC_IOCTL_VERSION_MAGIC 12
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -368,6 +368,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;
--- a/master/master.c Mon Oct 24 10:47:36 2011 +0200
+++ b/master/master.c Mon Oct 24 10:49:27 2011 +0200
@@ -2446,6 +2446,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)
@@ -2717,6 +2799,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);
--- a/tool/CommandDownload.cpp Mon Oct 24 10:47:36 2011 +0200
+++ b/tool/CommandDownload.cpp Mon Oct 24 10:49:27 2011 +0200
@@ -49,6 +49,7 @@
str << binaryBaseName << " " << getName()
<< " [OPTIONS] <INDEX> <SUBINDEX> <VALUE>" << endl
+ << " [OPTIONS] <INDEX> <VALUE>" << 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 <SUBINDEX>) 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 <alias>" << 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());