Thank you Jun, and yes, I owe you a cake!<br><br>To complete this discussion, I'd like to tell the developers how the patch was tested.<br><br>Since Jun's patch about 6~7 months ago, we have been using EtherCAT in our tests using his patch, with the cycle he described. With real data, we have had 2 slaves, ~60 PDOs and ~700  entries, with which we didn't have any problem. The only case where it was unclear what the behavior of the master would be was the following:<br>
<br>Imagine a domain that is so big, it requires multiple packets to be sent and received to read all data from the network. It was unknown what would happen if `ecrt_master_receive` is called while some packets have arrived and others not. To test this, we created the following setup:<br>
<br>2 slaves, each producing 1.2k data, split equally in 2 datagrams. A 
bridge placed in the network that introduces a delay between the 2 
datagrams. The delays I tested with were 100us, 500us and 1ms. That is, 
the bridge makes sure there is at least 1ms delay between passing 
frames. I logged the passing times and this is done correctly.<br><br>In this test, using `ecrt_domain_received`,
 I could see that it returns true after the correct time. That is, when I 
increase the gap in the bridge, the receive time in the network is 
increased. With another program I checked the data received from the 
slaves and they are correct (both datagrams arrive).<br><br>The only problem I found was that `ecrt_domain_received` should **not** be called after `ecrt_domain_process` (otherwise, there would be a kernel crash).<br><br>
Once again, thank you Jun and I certainly hope the developers of the EtherCAT master would include this patch in the next version.<br>Shahbaz<br><div class="gmail_quote"><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Date: Mon, 2 Jul 2012 17:43:24 +0200<br>
From: Jun Yuan <<a href="mailto:j.yuan@rtleaders.com">j.yuan@rtleaders.com</a>><br>
Subject: Re: [etherlab-users] Waiting for network receive?<br>
To: <a href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a><br>
Message-ID:<br>
        <<a href="mailto:CAB0kLgunW_iST0z0U51wWRwZUMJcbO2KVcHBABuGofB1Uks8qw@mail.gmail.com">CAB0kLgunW_iST0z0U51wWRwZUMJcbO2KVcHBABuGofB1Uks8qw@mail.gmail.com</a>><br>
Content-Type: text/plain; charset="utf-8"<br>
<br>
Hi Shahbaz,<br>
<br>
I was just about to delete myself from the mailing list today, then I<br>
saw your email. Thanks for the introduction, Shahbaz. Now I know you<br>
owe me a cake :P<br>
<br>
I didn't send it to the EtherLab developers, because I don't know if<br>
they've already understood the need. So let me express the problem<br>
again. The original master loop is like the following.<br>
<br>
while (true) {<br>
    ecrt_master_receive(master);    // check my mailbox<br>
    ecrt_domain_process(domain);  // check those replies from<br>
yesterday, cry if not all the replies have been received<br>
<br>
    // read replies, write new mails<br>
<br>
    ecrt_domain_queue(domain);  // drop them to the sending box<br>
    ecrt_master_send(master);     // send them out<br>
    wait_for_next_cycle();            // call it a day<br>
}<br>
<br>
The problem is that, the replies may already lie in our mailbox long<br>
before the next day. Some may argue that we can make the day shorter<br>
(decrease the cycle time). Well, we cannot always do that. Some slaves<br>
need a certain cycle time.<br>
<br>
And there is another drawback in the original loop: the<br>
ecrt_master_send() comes after the data processing, which's duration<br>
may vary. This would cause jitter in datagram sending interval, which<br>
causes further problem in some realtime application. We should have<br>
the sending happens before our data processing.<br>
<br>
Since our mailman won't ring the doorbell when he brings mails to us<br>
(There's no interrupt in EtherLab Master, so forget about it), we need<br>
to check our mailbox again and again to see whether new mails have<br>
been arrived.<br>
<br>
while (true) {<br>
        // if you have DC sync, do it here<br>
        ecrt_master_send(master);                       // send my mails out<br>
<br>
        do {<br>
                sleep(a while);                                // take a nap<br>
                ecrt_master_receive(master);           // check the mailbox<br>
        } while (!ecrt_domain_received(domain));  // until all the replys has<br>
been received<br>
<br>
        ecrt_domain_process(domain);                // check those replies<br>
<br>
        // read replies, write new mails<br>
<br>
        ecrt_domain_queue(domain);                 // drop them to the sending box<br>
        wait_for_next_cycle();                           // call it a day<br>
}<br>
<br>
<br>
This solution is not ideal, but that's what we can do if we are eager<br>
to read the replies ASAP. An ideal solution would be, if we know how<br>
long does it take to get replies, we just sleep for that long and wake<br>
up, hurra, all the replies have just been arrived. But how can we<br>
determine that time?<br>
<br>
The implementation the function ecrt_domain_received(domain) is quite easy.<br>
<br>
int ecrt_domain_received(const ec_domain_t *domain)<br>
{<br>
    ec_datagram_t *datagram;<br>
<br>
    list_for_each_entry(datagram, &domain->datagrams, list) {<br>
        if (datagram->state != EC_DATAGRAM_RECEIVED) {<br>
            return 0;<br>
        }<br>
    }<br>
    return 1;<br>
}<br>
<br>
Please find enclosed the patch for 2292:0f7a243b03e4@stable-1.5. The<br>
patch works for userspace too.<br>
<br>
diff -r 0f7a243b03e4 include/ecrt.h<br>
--- a/include/ecrt.h    Mon Jan 30 15:33:54 2012 +0100<br>
+++ b/include/ecrt.h    Mon Jul 02 16:37:08 2012 +0200<br>
@@ -1346,6 +1346,16 @@<br>
         ec_domain_t *domain /**< Domain. */<br>
         );<br>
<br>
+/** Check if all the datagrams of the domain have been received.<br>
+ *<br>
+ * \retval  1 on received.<br>
+ * \retval  0 not received.<br>
+ * \retval <0 Error code.<br>
+ */<br>
+int ecrt_domain_received(<br>
+               const ec_domain_t *domain /**< Domain. */<br>
+               );<br>
+<br>
 /** Determines the states of the domain's datagrams.<br>
  *<br>
  * Evaluates the working counters of the received datagrams and outputs<br>
diff -r 0f7a243b03e4 lib/domain.c<br>
--- a/lib/domain.c      Mon Jan 30 15:33:54 2012 +0100<br>
+++ b/lib/domain.c      Mon Jul 02 16:37:08 2012 +0200<br>
@@ -99,6 +99,20 @@<br>
<br>
 /*****************************************************************************/<br>
<br>
+int ecrt_domain_received(const ec_domain_t *domain)<br>
+{<br>
+       int received = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_RECEIVED,<br>
+            domain->index);<br>
+<br>
+    if (received < 0) {<br>
+        fprintf(stderr, "Failed to process domain: %s\n", strerror(errno));<br>
+    }<br>
+<br>
+    return received;<br>
+}<br>
+<br>
+/*****************************************************************************/<br>
+<br>
 void ecrt_domain_process(ec_domain_t *domain)<br>
 {<br>
     if (ioctl(domain->master->fd, EC_IOCTL_DOMAIN_PROCESS,<br>
diff -r 0f7a243b03e4 master/cdev.c<br>
--- a/master/cdev.c     Mon Jan 30 15:33:54 2012 +0100<br>
+++ b/master/cdev.c     Mon Jul 02 16:37:08 2012 +0200<br>
@@ -2522,6 +2522,31 @@<br>
<br>
 /*****************************************************************************/<br>
<br>
+/** Check domain's datagrams have received.<br>
+ */<br>
+int ec_cdev_ioctl_domain_received(<br>
+        ec_master_t *master, /**< EtherCAT master. */<br>
+        unsigned long arg, /**< ioctl() argument. */<br>
+        ec_cdev_priv_t *priv /**< Private data structure of file handle. */<br>
+        )<br>
+{<br>
+    const ec_domain_t *domain;<br>
+<br>
+    if (unlikely(!priv->requested))<br>
+        return -EPERM;<br>
+<br>
+    /* no locking of master_sem needed, because domain will not be deleted in<br>
+     * the meantime. */<br>
+<br>
+    if (!(domain = ec_master_find_domain(master, arg))) {<br>
+        return -ENOENT;<br>
+    }<br>
+<br>
+    return ecrt_domain_received(domain);<br>
+}<br>
+<br>
+/*****************************************************************************/<br>
+<br>
 /** Process the domain.<br>
  */<br>
 int ec_cdev_ioctl_domain_process(<br>
@@ -3750,6 +3775,9 @@<br>
         case EC_IOCTL_DOMAIN_OFFSET:<br>
             ret = ec_cdev_ioctl_domain_offset(master, arg, priv);<br>
             break;<br>
+        case EC_IOCTL_DOMAIN_RECEIVED:<br>
+               ret = ec_cdev_ioctl_domain_received(master, arg, priv);<br>
+            break;<br>
         case EC_IOCTL_DOMAIN_PROCESS:<br>
             if (!(filp->f_mode & FMODE_WRITE)) {<br>
                 ret = -EPERM;<br>
diff -r 0f7a243b03e4 master/domain.c<br>
--- a/master/domain.c   Mon Jan 30 15:33:54 2012 +0100<br>
+++ b/master/domain.c   Mon Jul 02 16:37:08 2012 +0200<br>
@@ -396,6 +396,20 @@<br>
<br>
 /*****************************************************************************/<br>
<br>
+int ecrt_domain_received(const ec_domain_t *domain)<br>
+{<br>
+    ec_datagram_t *datagram;<br>
+<br>
+    list_for_each_entry(datagram, &domain->datagrams, list) {<br>
+        if (datagram->state != EC_DATAGRAM_RECEIVED) {<br>
+            return 0;<br>
+        }<br>
+    }<br>
+    return 1;<br>
+}<br>
+<br>
+/*****************************************************************************/<br>
+<br>
 void ecrt_domain_process(ec_domain_t *domain)<br>
 {<br>
     uint16_t working_counter_sum;<br>
@@ -467,6 +481,7 @@<br>
 EXPORT_SYMBOL(ecrt_domain_size);<br>
 EXPORT_SYMBOL(ecrt_domain_external_memory);<br>
 EXPORT_SYMBOL(ecrt_domain_data);<br>
+EXPORT_SYMBOL(ecrt_domain_received);<br>
 EXPORT_SYMBOL(ecrt_domain_process);<br>
 EXPORT_SYMBOL(ecrt_domain_queue);<br>
 EXPORT_SYMBOL(ecrt_domain_state);<br>
diff -r 0f7a243b03e4 master/ioctl.h<br>
--- a/master/ioctl.h    Mon Jan 30 15:33:54 2012 +0100<br>
+++ b/master/ioctl.h    Mon Jul 02 16:37:08 2012 +0200<br>
@@ -137,6 +137,7 @@<br>
 #define EC_IOCTL_VOE_EXEC             EC_IOWR(0x47, ec_ioctl_voe_t)<br>
 #define EC_IOCTL_VOE_DATA             EC_IOWR(0x48, ec_ioctl_voe_t)<br>
 #define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x49, size_t)<br>
+#define EC_IOCTL_DOMAIN_RECEIVED       EC_IO(0x50)<br>
<br>
 /*****************************************************************************/<br>
</blockquote></div><br>