Added ecrt_master_sdo_download_complete() for ad-hoc downloading SDOs (also stable-1.5
authorFlorian Pose <fp@igh-essen.com>
Mon, 24 Oct 2011 10:49:27 +0200
branchstable-1.5
changeset 2124 c4afc5fede19
parent 2123 4c335a1d4db0
child 2125 af3eda069078
child 2129 78efdac9ee87
Added ecrt_master_sdo_download_complete() for ad-hoc downloading SDOs (also
via the command-line tool).
include/ecrt.h
lib/master.c
master/cdev.c
master/ioctl.h
master/master.c
tool/CommandDownload.cpp
--- 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());