Thank you Jun, and yes, I owe you a cake! To complete this discussion, I'd like to tell the developers how the patch was tested.
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: 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: 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. 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). 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). Once again, thank you Jun and I certainly hope the developers of the EtherCAT master would include this patch in the next version. Shahbaz Date: Mon, 2 Jul 2012 17:43:24 +0200 > From: Jun Yuan <[email protected]> > Subject: Re: [etherlab-users] Waiting for network receive? > To: [email protected] > Message-ID: > < > cab0klgunw_ist0z0u51wwrwzumjcbo2kvchbabugofb1uks...@mail.gmail.com> > Content-Type: text/plain; charset="utf-8" > > 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:[email protected]. 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) > > > > /*****************************************************************************/ >
_______________________________________________ etherlab-users mailing list [email protected] http://lists.etherlab.org/mailman/listinfo/etherlab-users
