[etherlab-users] Waiting for network receive?

Jun Yuan j.yuan at rtleaders.com
Mon Jul 2 17:43:24 CEST 2012


Hi Shahbaz,

I was just about to delete myself from the mailing list today, then I
saw your email. Thanks for the introduction, Shahbaz. Now I know you
owe me a cake :P

I didn't send it to the EtherLab developers, because I don't know if
they've already understood the need. So let me express the problem
again. The original master loop is like the following.

while (true) {
    ecrt_master_receive(master);    // check my mailbox
    ecrt_domain_process(domain);  // check those replies from
yesterday, cry if not all the replies have been received

    // read replies, write new mails

    ecrt_domain_queue(domain);  // drop them to the sending box
    ecrt_master_send(master);     // send them out
    wait_for_next_cycle();            // call it a day
}

The problem is that, the replies may already lie in our mailbox long
before the next day. Some may argue that we can make the day shorter
(decrease the cycle time). Well, we cannot always do that. Some slaves
need a certain cycle time.

And there is another drawback in the original loop: the
ecrt_master_send() comes after the data processing, which's duration
may vary. This would cause jitter in datagram sending interval, which
causes further problem in some realtime application. We should have
the sending happens before our data processing.

Since our mailman won't ring the doorbell when he brings mails to us
(There's no interrupt in EtherLab Master, so forget about it), we need
to check our mailbox again and again to see whether new mails have
been arrived.

while (true) {
	// if you have DC sync, do it here
	ecrt_master_send(master);                       // send my mails out
	
	do {
		sleep(a while);                                // take a nap
		ecrt_master_receive(master);           // check the mailbox
	} while (!ecrt_domain_received(domain));  // until all the replys has
been received

	ecrt_domain_process(domain);                // check those replies

	// read replies, write new mails

	ecrt_domain_queue(domain);                 // drop them to the sending box
	wait_for_next_cycle();                           // call it a day
}


This solution is not ideal, but that's what we can do if we are eager
to read the replies ASAP. An ideal solution would be, if we know how
long does it take to get replies, we just sleep for that long and wake
up, hurra, all the replies have just been arrived. But how can we
determine that time?

The implementation the function ecrt_domain_received(domain) is quite easy.

int ecrt_domain_received(const ec_domain_t *domain)
{
    ec_datagram_t *datagram;

    list_for_each_entry(datagram, &domain->datagrams, list) {
        if (datagram->state != EC_DATAGRAM_RECEIVED) {
            return 0;
        }
    }
    return 1;
}

Please find enclosed the patch for 2292:0f7a243b03e4 at stable-1.5. The
patch works for userspace too.

diff -r 0f7a243b03e4 include/ecrt.h
--- a/include/ecrt.h	Mon Jan 30 15:33:54 2012 +0100
+++ b/include/ecrt.h	Mon Jul 02 16:37:08 2012 +0200
@@ -1346,6 +1346,16 @@
         ec_domain_t *domain /**< Domain. */
         );

+/** Check if all the datagrams of the domain have been received.
+ *
+ * \retval  1 on received.
+ * \retval  0 not received.
+ * \retval <0 Error code.
+ */
+int ecrt_domain_received(
+		const ec_domain_t *domain /**< Domain. */
+		);
+
 /** Determines the states of the domain's datagrams.
  *
  * Evaluates the working counters of the received datagrams and outputs
diff -r 0f7a243b03e4 lib/domain.c
--- a/lib/domain.c	Mon Jan 30 15:33:54 2012 +0100
+++ b/lib/domain.c	Mon Jul 02 16:37:08 2012 +0200
@@ -99,6 +99,20 @@

 /*****************************************************************************/

+int ecrt_domain_received(const ec_domain_t *domain)
+{
+	int received = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_RECEIVED,
+            domain->index);
+
+    if (received < 0) {
+        fprintf(stderr, "Failed to process domain: %s\n", strerror(errno));
+    }
+
+    return received;
+}
+
+/*****************************************************************************/
+
 void ecrt_domain_process(ec_domain_t *domain)
 {
     if (ioctl(domain->master->fd, EC_IOCTL_DOMAIN_PROCESS,
diff -r 0f7a243b03e4 master/cdev.c
--- a/master/cdev.c	Mon Jan 30 15:33:54 2012 +0100
+++ b/master/cdev.c	Mon Jul 02 16:37:08 2012 +0200
@@ -2522,6 +2522,31 @@

 /*****************************************************************************/

+/** Check domain's datagrams have received.
+ */
+int ec_cdev_ioctl_domain_received(
+        ec_master_t *master, /**< EtherCAT master. */
+        unsigned long arg, /**< ioctl() argument. */
+        ec_cdev_priv_t *priv /**< Private data structure of file handle. */
+        )
+{
+    const ec_domain_t *domain;
+
+    if (unlikely(!priv->requested))
+        return -EPERM;
+
+    /* no locking of master_sem needed, because domain will not be deleted in
+     * the meantime. */
+
+    if (!(domain = ec_master_find_domain(master, arg))) {
+        return -ENOENT;
+    }
+
+    return ecrt_domain_received(domain);
+}
+
+/*****************************************************************************/
+
 /** Process the domain.
  */
 int ec_cdev_ioctl_domain_process(
@@ -3750,6 +3775,9 @@
         case EC_IOCTL_DOMAIN_OFFSET:
             ret = ec_cdev_ioctl_domain_offset(master, arg, priv);
             break;
+        case EC_IOCTL_DOMAIN_RECEIVED:
+        	ret = ec_cdev_ioctl_domain_received(master, arg, priv);
+            break;
         case EC_IOCTL_DOMAIN_PROCESS:
             if (!(filp->f_mode & FMODE_WRITE)) {
                 ret = -EPERM;
diff -r 0f7a243b03e4 master/domain.c
--- a/master/domain.c	Mon Jan 30 15:33:54 2012 +0100
+++ b/master/domain.c	Mon Jul 02 16:37:08 2012 +0200
@@ -396,6 +396,20 @@

 /*****************************************************************************/

+int ecrt_domain_received(const ec_domain_t *domain)
+{
+    ec_datagram_t *datagram;
+
+    list_for_each_entry(datagram, &domain->datagrams, list) {
+        if (datagram->state != EC_DATAGRAM_RECEIVED) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/*****************************************************************************/
+
 void ecrt_domain_process(ec_domain_t *domain)
 {
     uint16_t working_counter_sum;
@@ -467,6 +481,7 @@
 EXPORT_SYMBOL(ecrt_domain_size);
 EXPORT_SYMBOL(ecrt_domain_external_memory);
 EXPORT_SYMBOL(ecrt_domain_data);
+EXPORT_SYMBOL(ecrt_domain_received);
 EXPORT_SYMBOL(ecrt_domain_process);
 EXPORT_SYMBOL(ecrt_domain_queue);
 EXPORT_SYMBOL(ecrt_domain_state);
diff -r 0f7a243b03e4 master/ioctl.h
--- a/master/ioctl.h	Mon Jan 30 15:33:54 2012 +0100
+++ b/master/ioctl.h	Mon Jul 02 16:37:08 2012 +0200
@@ -137,6 +137,7 @@
 #define EC_IOCTL_VOE_EXEC             EC_IOWR(0x47, ec_ioctl_voe_t)
 #define EC_IOCTL_VOE_DATA             EC_IOWR(0x48, ec_ioctl_voe_t)
 #define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x49, size_t)
+#define EC_IOCTL_DOMAIN_RECEIVED       EC_IO(0x50)

 /*****************************************************************************/


On Mon, Jul 2, 2012 at 12:00 PM,  Shahbaz Youssefi wrote:
> From: Shahbaz Youssefi <shabbyx at gmail.com>
> To: etherlab-users <etherlab-users at etherlab.org>
> Cc:
> Date: Sun, 1 Jul 2012 12:33:21 +0200
> Subject: Re: [etherlab-users] Waiting for network receive?
> I don't specifically know about user-space, but "Jun Yuan" wrote a patch for me, adding a function called `ecrt_domain_received` that tells you whether the domain has been received or not (in kernel-space).
>
> I have tested this function with domains spanning into multiple packets and calling it while some of the packets have been received and others not, and it is safe. I just checked the latest development branch and unfortunately this has not been added to the repository (I wonder why).
>
> If the developers of the master are interested, I could present the test we performed so that they could be sure the patch works and hopefully include it in the next release.
>
> On Sun, Jul 1, 2012 at 12:00 PM, <etherlab-users-request at etherlab.org> wrote:
>>
>>
>> I was looking at the code and they map the datagram directly to user
>> space and has a skb ring size of 2 frames. data cannot be available for
>> a re-write until it is acked by the interrupt completion of the ethernet
>> device.
>> You need to query the skb->users counter and check when it is
>> decremented back -- meaning when transmission complete takes place.
>>
>> I believe the curretn design might cause problem in heavy traffic or in
>> preempt rt when the transmit complete threaded interrupt has a "too" low
>> priority.
>>
>> On Thu, 2012-06-28 at 19:38 +0200, Johnathan Van Why wrote:
>> > The software system we are setting up needs to be able to send an
>> > EtherCAT frame, then wait until the network data is available for
>> > processing to resume (rather than wait until the next cycle time). Is
>> > there any way to do that with the EtherCAT Master? This is a userspace
>> > application.
>> >
>> > Thanks for any help,
>> > Johnathan Van Why
-------------- next part --------------
A non-text attachment was scrubbed...
Name: check_received_2292.patch
Type: application/octet-stream
Size: 4191 bytes
Desc: not available
URL: <http://lists.etherlab.org/pipermail/etherlab-users/attachments/20120702/02b8a9df/attachment-0005.obj>


More information about the Etherlab-users mailing list