Included ecrt_voe_handler_read_nosync()-Patch by Mathias Weber.
authorFlorian Pose <fp@igh-essen.com>
Tue, 18 Nov 2008 11:13:49 +0000
changeset 1314 b3d06a8807b3
parent 1313 ed15eef57d5c
child 1315 26b4f94cfdfb
Included ecrt_voe_handler_read_nosync()-Patch by Mathias Weber.
include/ecrt.h
lib/voe_handler.c
master/cdev.c
master/ioctl.h
master/voe_handler.c
--- a/include/ecrt.h	Mon Nov 17 17:18:02 2008 +0000
+++ b/include/ecrt.h	Tue Nov 18 11:13:49 2008 +0000
@@ -1049,6 +1049,25 @@
         ec_voe_handler_t *voe /**< VoE handler. */
         );
 
+/** Start a VoE read operation without querying the sync manager status.
+ *
+ * After this function has been called, the ecrt_voe_handler_execute() method
+ * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY. No
+ * other operation may be started while the handler is busy.
+ *
+ * The state machine queries the slave by sending an empty mailbox. The slave
+ * fills its data to the master in this mailbox. If no data appear within the
+ * EC_VOE_RESPONSE_TIMEOUT (defined in master/voe_handler.c), the operation
+ * fails.
+ *
+ * On success, the size of the read data can be determined via
+ * ecrt_voe_handler_data_size(), while the VoE header of the received data
+ * can be retrieved with ecrt_voe_handler_received_header().
+ */
+void ecrt_voe_handler_read_nosync(
+        ec_voe_handler_t *voe /**< VoE handler. */
+        );
+
 /** Execute the handler.
  *
  * This method executes the VoE handler. It has to be called in every bus cycle
--- a/lib/voe_handler.c	Mon Nov 17 17:18:02 2008 +0000
+++ b/lib/voe_handler.c	Tue Nov 18 11:13:49 2008 +0000
@@ -111,6 +111,20 @@
 
 /*****************************************************************************/
 
+void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
+{
+    ec_ioctl_voe_t data;
+
+    data.config_index = voe->config->index;
+    data.voe_index = voe->index;
+
+    if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_READ_NOSYNC, &data) == -1)
+        fprintf(stderr, "Failed to initiate VoE reading: %s\n",
+                strerror(errno));
+}
+
+/*****************************************************************************/
+
 void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
 {
     ec_ioctl_voe_t data;
--- a/master/cdev.c	Mon Nov 17 17:18:02 2008 +0000
+++ b/master/cdev.c	Tue Nov 18 11:13:49 2008 +0000
@@ -2227,6 +2227,45 @@
 
 /*****************************************************************************/
 
+/** Starts a VoE read operation without sending a sync message first.
+ */
+int ec_cdev_ioctl_voe_read_nosync(
+        ec_master_t *master, /**< EtherCAT master. */
+        unsigned long arg, /**< ioctl() argument. */
+        ec_cdev_priv_t *priv /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_voe_t data;
+    ec_slave_config_t *sc;
+    ec_voe_handler_t *voe;
+
+	if (unlikely(!priv->requested))
+        return -EPERM;
+
+    if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
+        return -EFAULT;
+
+    if (down_interruptible(&master->master_sem))
+        return -EINTR;
+
+    if (!(sc = ec_master_get_config(master, data.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    up(&master->master_sem);
+
+    ecrt_voe_handler_read_nosync(voe);
+    return 0;
+}
+
+/*****************************************************************************/
+
 /** Starts a VoE write operation.
  */
 int ec_cdev_ioctl_voe_write(
@@ -2559,6 +2598,10 @@
         case EC_IOCTL_VOE_READ:
             if (!(filp->f_mode & FMODE_WRITE))
 				return -EPERM;
+        case EC_IOCTL_VOE_READ_NOSYNC:
+            if (!(filp->f_mode & FMODE_WRITE))
+				return -EPERM;
+			return ec_cdev_ioctl_voe_read_nosync(master, arg, priv);
 			return ec_cdev_ioctl_voe_read(master, arg, priv);
         case EC_IOCTL_VOE_WRITE:
             if (!(filp->f_mode & FMODE_WRITE))
--- a/master/ioctl.h	Mon Nov 17 17:18:02 2008 +0000
+++ b/master/ioctl.h	Tue Nov 18 11:13:49 2008 +0000
@@ -104,9 +104,10 @@
 #define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x2a, ec_ioctl_voe_t)
 #define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x2b, ec_ioctl_voe_t)
 #define EC_IOCTL_VOE_READ              EC_IOW(0x2c, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x2d, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x2e, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x2f, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x2d, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x2e, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x2f, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x30, ec_ioctl_voe_t)
 
 /*****************************************************************************/
 
--- a/master/voe_handler.c	Mon Nov 17 17:18:02 2008 +0000
+++ b/master/voe_handler.c	Tue Nov 18 11:13:49 2008 +0000
@@ -65,6 +65,9 @@
 void ec_voe_handler_state_read_check(ec_voe_handler_t *);
 void ec_voe_handler_state_read_response(ec_voe_handler_t *);
 
+void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *);
+void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *);
+
 void ec_voe_handler_state_end(ec_voe_handler_t *);
 void ec_voe_handler_state_error(ec_voe_handler_t *);
 
@@ -168,6 +171,15 @@
 
 /*****************************************************************************/
 
+void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
+{
+    voe->dir = EC_DIR_INPUT;
+    voe->state = ec_voe_handler_state_read_nosync_start;
+    voe->request_state = EC_INT_REQUEST_QUEUED;
+}
+
+/*****************************************************************************/
+
 void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
 {
     voe->dir = EC_DIR_OUTPUT;
@@ -427,6 +439,106 @@
 
 /*****************************************************************************/
 
+/** Start reading VoE data without sending a sync message before.
+ */
+void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+
+    if (slave->master->debug_level)
+        EC_DBG("Reading VoE data to slave %u.\n", slave->ring_position);
+
+    if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
+        EC_ERR("Slave %u does not support VoE!\n", slave->ring_position);
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+	
+    ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+
+    voe->jiffies_start = jiffies;
+    voe->retries = EC_FSM_RETRIES;
+    voe->state = ec_voe_handler_state_read_nosync_response;
+}
+
+/*****************************************************************************/
+
+/** Read the pending mailbox data without sending a sync message before. This
+ *  might lead to an empty reponse from the client.
+ */
+void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+    ec_master_t *master = voe->config->master;
+    uint8_t *data, mbox_prot;
+    size_t rec_size;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Failed to receive VoE read datagram for"
+               " slave %u (datagram state %u).\n",
+               slave->ring_position, datagram->state);
+        return;
+    }
+
+    if (datagram->working_counter == 0) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_DBG("Slave (%u) did not send data with Mailbox.",
+                slave->ring_position);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_WARN("Reception of VoE read response failed on slave %u: ",
+                slave->ring_position);
+        ec_datagram_print_wc_error(datagram);
+        return;
+    }
+
+    if (!(data = ec_slave_mbox_fetch(slave, datagram,
+				     &mbox_prot, &rec_size))) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+
+    if (mbox_prot != EC_MBOX_TYPE_VOE) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        ec_print_data(data, rec_size);
+        return;
+    }
+
+    if (rec_size < EC_VOE_HEADER_SIZE) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Received VoE header is incomplete (%u bytes)!\n", rec_size);
+        return;
+    }
+
+    if (master->debug_level) {
+        EC_DBG("VoE data:\n");
+        ec_print_data(data, rec_size);
+    }
+
+    voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
+    voe->request_state = EC_INT_REQUEST_SUCCESS;
+    voe->state = ec_voe_handler_state_end; // success
+}
+
+/*****************************************************************************/
+
 /** Successful termination state function.
  */
 void ec_voe_handler_state_end(ec_voe_handler_t *voe)