[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