[etherlab-users] Waiting for network receive?
Shahbaz Youssefi
shabbyx at gmail.com
Tue Jul 3 14:15:49 CEST 2012
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 <j.yuan at rtleaders.com>
> Subject: Re: [etherlab-users] Waiting for network receive?
> To: etherlab-users at etherlab.org
> Message-ID:
> <
> CAB0kLgunW_iST0z0U51wWRwZUMJcbO2KVcHBABuGofB1Uks8qw at 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: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)
>
>
> /*****************************************************************************/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.etherlab.org/pipermail/etherlab-users/attachments/20120703/c74ce9b3/attachment-0005.htm>
More information about the Etherlab-users
mailing list