]> git.feebdaed.xyz Git - 0xmirror/SOEM.git/commitdiff
Improved mailbox handling
authorHans-Erik Floryd <hans-erik.floryd@rt-labs.com>
Thu, 26 Sep 2024 11:49:01 +0000 (13:49 +0200)
committerHans-Erik Floryd <hans-erik.floryd@rt-labs.com>
Wed, 9 Jul 2025 10:15:39 +0000 (12:15 +0200)
This commit includes extensive changes across multiple files to
refactor the mailbox handling system and improve performance and
reliability in EtherCAT communication.

Update from Arthur Ketels 20240911.

Change-Id: I1177aea8b71156671a465473b7393af76be19c1c

20 files changed:
.github/workflows/build.yml [deleted file]
.gitignore
CMakeLists.txt
osal/linux/osal.c
osal/linux/osal_defs.h
osal/osal.h
osal/win32/osal_defs.h
oshw/linux/nicdrv.c
oshw/linux/nicdrv.h
soem/ethercatcoe.c
soem/ethercatconfig.c
soem/ethercatfoe.c
soem/ethercatmain.c
soem/ethercatmain.h
soem/ethercatsoe.c
soem/ethercattype.h
test/linux/coetest/CMakeLists.txt [new file with mode: 0644]
test/linux/coetest/coetest.c [new file with mode: 0644]
test/linux/simple_test/simple_test.c
test/linux/slaveinfo/slaveinfo.c

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644 (file)
index abd7515..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name: build
-on: [push, pull_request]
-env:
-  BUILD_TYPE: Release
-jobs:
-  build:
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os:
-          - ubuntu-latest
-          - ubuntu-20.04
-          - ubuntu-18.04
-          - macos-latest
-          - windows-latest
-    steps:
-      - uses: actions/checkout@v2
-        with:
-          submodules: true
-
-      - name: Configure
-        shell: bash
-        run: |
-          cmake -E make_directory $GITHUB_WORKSPACE/build
-          cmake -B $GITHUB_WORKSPACE/build -S $GITHUB_WORKSPACE \
-             -DCMAKE_BUILD_TYPE=$BUILD_TYPE
-
-      - name: Build
-        shell: bash
-        run: |
-          cmake --build $GITHUB_WORKSPACE/build -j4 --target install
index b4bbe2cc0e09cbf50a3860730db1f6b369b7823c..b905807467c0a5fce68028af240d916540dc7656 100644 (file)
@@ -4,3 +4,4 @@ install
 /doc/latex
 /doc/html
 tags
+.vscode
index e161a8861dcb42595b96719d531ac4c07a76404b..151f6b3c6378c84668e4d985617d475c9e70f39a 100644 (file)
@@ -127,4 +127,5 @@ if(BUILD_TESTS)
   add_subdirectory(test/linux/slaveinfo)
   add_subdirectory(test/linux/eepromtool)
   add_subdirectory(test/linux/simple_test)
+  add_subdirectory(test/linux/coetest)
 endif()
index 7ad3d62427ebd356845cb337322c44ce67d21d6c..2af6d4740c7c898b4d2759debd34c7ae49181416 100644 (file)
@@ -143,3 +143,33 @@ int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param)
 
    return 1;
 }
+
+void *osal_mutex_create(void)
+{
+   pthread_mutexattr_t mutexattr;
+   osal_mutext *mutex;
+   mutex = (osal_mutext *)osal_malloc (sizeof(osal_mutext));
+   if(mutex)
+   {
+      pthread_mutexattr_init(&mutexattr);
+      pthread_mutexattr_setprotocol(&mutexattr, PTHREAD_PRIO_INHERIT);
+      pthread_mutex_init(mutex, &mutexattr);
+   }
+   return (void *)mutex;
+}
+
+void osal_mutex_destroy(void *mutex)
+{
+   pthread_mutex_destroy((osal_mutext *)mutex);
+   osal_free(mutex);
+}
+
+void osal_mutex_lock(void *mutex)
+{
+   pthread_mutex_lock((osal_mutext *) mutex);
+}
+
+void osal_mutex_unlock(void *mutex)
+{
+   pthread_mutex_unlock((osal_mutext *) mutex);
+}
index b097742136d2a8ed698998d98b2519fe97b2c77f..f4c5ea5cc52787abd34f0314077b6253ef019850 100644 (file)
@@ -32,6 +32,8 @@ extern "C"
 #define OSAL_THREAD_FUNC void
 #define OSAL_THREAD_FUNC_RT void
 
+#define osal_mutext pthread_mutex_t
+
 #ifdef __cplusplus
 }
 #endif
index e59094cccd6fcd92f9fb4d4001fcc5a6d83007b2..0d13ee174edf89a86dda463aaec3fb7386b52209 100644 (file)
@@ -14,6 +14,7 @@ extern "C"
 
 #include "osal_defs.h"
 #include <stdint.h>
+#include <stddef.h>
 
 /* General types */
 #ifndef TRUE
@@ -52,6 +53,12 @@ ec_timet osal_current_time(void);
 void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff);
 int osal_thread_create(void *thandle, int stacksize, void *func, void *param);
 int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param);
+void *osal_malloc(size_t size);
+void osal_free(void *ptr);
+void *osal_mutex_create(void);
+void osal_mutex_destroy(void *mutex);
+void osal_mutex_lock(void *mutex);
+void osal_mutex_unlock(void *mutex);
 
 #ifdef __cplusplus
 }
index 2780029d1dec417d5bbe81786ce0a89dc21455a2..dec039a8456f3bef3887b65e1793a9d1f6b7e9c4 100644 (file)
@@ -39,6 +39,8 @@ extern "C"
 #define OSAL_THREAD_FUNC void
 #define OSAL_THREAD_FUNC_RT void
 
+#define osal_mutext CRITICAL_SECTION
+
 #ifdef __cplusplus
 }
 #endif
index d64cfc7528f33a51da41ec15d6f7fc3dc8eb19ff..0e90cde6b11376141ddd96ab158e307539312225 100644 (file)
@@ -31,6 +31,8 @@
  * This layer if fully transparent for the higher layers.
  */
 
+#define _GNU_SOURCE
+
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
@@ -44,6 +46,7 @@
 #include <string.h>
 #include <netpacket/packet.h>
 #include <pthread.h>
+#include <poll.h>
 
 #include "oshw.h"
 #include "osal.h"
@@ -92,7 +95,7 @@ int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
 {
    int i;
    int r, rval, ifindex;
-   struct timeval timeout;
//  struct timeval timeout;
    struct ifreq ifr;
    struct sockaddr_ll sll;
    int *psock;
@@ -148,11 +151,13 @@ int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
    if(*psock < 0)
       return 0;
 
+   r = 0;
+/*
    timeout.tv_sec =  0;
    timeout.tv_usec = 1;
-   r = 0;
    r |= setsockopt(*psock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    r |= setsockopt(*psock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+*/
    i = 1;
    r |= setsockopt(*psock, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i));
    /* connect socket to NIC by name */
@@ -406,14 +411,25 @@ int ecx_inframe(ecx_portt *port, uint8 idx, int stacknumber)
    else
    {
       pthread_mutex_lock(&(port->rx_mutex));
+      /* check again if requested index is already in buffer ?
+       * other task might have reveived it befor we grabbed mutex */
+      if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD))
+      {
+         l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
+         /* return WKC */
+         rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
+         /* mark as completed */
+         (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
+      }
       /* non blocking call to retrieve frame from socket */
-      if (ecx_recvpkt(port, stacknumber))
+      else if (ecx_recvpkt(port, stacknumber))
       {
          rval = EC_OTHERFRAME;
          ehp =(ec_etherheadert*)(stack->tempbuf);
          /* check if it is an EtherCAT frame */
          if (ehp->etype == htons(ETH_P_ECAT))
          {
+            stack->rxcnt++;
             ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
             l = etohs(ecp->elength) & 0x0fff;
             idxf = ecp->index;
@@ -478,17 +494,40 @@ static int ecx_waitinframe_red(ecx_portt *port, uint8 idx, osal_timert *timer)
    /* if not in redundant mode then always assume secondary is OK */
    if (port->redstate == ECT_RED_NONE)
       wkc2 = 0;
+   /* use ppoll to reduce busy_polling */
+   struct pollfd fds[2];
+   struct pollfd *fdsp;
+   int poll_err = 0;
+   struct timespec timeout_spec = { 0, 0 };
+   timeout_spec.tv_nsec = 50 * 1000;
+   ec_stackT *stack;
+   stack = &(port->stack);
+   fds[0].fd = *stack->sock;
+   fds[0].events = POLLIN;
+   int pollcnt = 1;
+   if(port->redstate != ECT_RED_NONE)
+   {
+      pollcnt = 2;
+      stack = &(port->redport->stack);
+      fds[1].fd = *stack->sock;
+      fds[1].events = POLLIN;
+   }
+   fdsp = &fds[0];
    do
    {
-      /* only read frame if not already in */
-      if (wkc <= EC_NOFRAME)
-         wkc  = ecx_inframe(port, idx, 0);
-      /* only try secondary if in redundant mode */
-      if (port->redstate != ECT_RED_NONE)
+      poll_err = ppoll(fdsp, pollcnt, &timeout_spec, NULL);
+      if(poll_err >= 0)
       {
          /* only read frame if not already in */
-         if (wkc2 <= EC_NOFRAME)
-            wkc2 = ecx_inframe(port, idx, 1);
+         if (wkc <= EC_NOFRAME)
+            wkc  = ecx_inframe(port, idx, 0);
+         /* only try secondary if in redundant mode */
+         if (port->redstate != ECT_RED_NONE)
+         {
+            /* only read frame if not already in */
+            if (wkc2 <= EC_NOFRAME)
+               wkc2 = ecx_inframe(port, idx, 1);
+         }
       }
    /* wait for both frames to arrive or timeout */
    } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer));
index a9c4246289c3b152f472487bd3e2484124998b3e..4e8db1a44ca26ab74ab1627a6dfd2c3472cbf932 100644 (file)
@@ -36,6 +36,7 @@ typedef struct
    int         (*rxbufstat)[EC_MAXBUF];
    /** received MAC source address (middle word) */
    int         (*rxsa)[EC_MAXBUF];
+   uint64      rxcnt;
 } ec_stackT;
 
 /** pointer structure to buffers for redundant port */
index e9c302bd3cafa196994b12a4725998f736471005..8887a3dee32d6113fe3739bfcbd59c912c1e758e 100644 (file)
@@ -123,25 +123,26 @@ int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subinde
 {
    ec_SDOt *SDOp, *aSDOp;
    uint16 bytesize, Framedatasize;
-   int wkc;
+   int wkc = 0;
    int32 SDOlen;
    uint8 *bp;
    uint8 *hp;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt, toggle;
    boolean NotLast;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOt *)&MbxIn;
-   SDOp = (ec_SDOt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOt *)MbxOut;
    SDOp->MbxHeader.length = htoes(0x000a);
    SDOp->MbxHeader.address = htoes(0x0000);
    SDOp->MbxHeader.priority = 0x00;
    /* get new mailbox count value, used as session handle */
-   cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
+   cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);   
    context->slavelist[slave].mbx_cnt = cnt;
    SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + MBX_HDR_SET_CNT(cnt); /* CoE */
    SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits (SDO request) */
@@ -161,14 +162,19 @@ int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subinde
    SDOp->SubIndex = subindex;
    SDOp->ldata[0] = 0;
    /* send CoE request to slave */
-   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    if (wkc > 0) /* succeeded to place mailbox in slave ? */
    {
-      /* clean mailboxbuffer */
-      ec_clearmbx(&MbxIn);
       /* read slave response */
-      wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
-      if (wkc > 0) /* succeeded to read slave response ? */
+      if(MbxIn) ecx_dropmbx(context, MbxIn);
+      MbxIn = NULL;
+      do
+      {
+         wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
+      } while ((wkc > 0) && !MbxIn);   
+      aSDOp = (ec_SDOt *)MbxIn;
+      if ((wkc > 0) && MbxIn) /* succeeded to read slave response ? */
       {
          /* slave response should be CoE, SDO response and the correct index */
          if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
@@ -213,7 +219,13 @@ int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subinde
                      toggle= 0x00;
                      while (NotLast) /* segmented transfer */
                      {
-                        SDOp = (ec_SDOt *)&MbxOut;
+                        MbxOut = ecx_getmbx(context);
+                        if(!MbxOut)
+                        {
+                           NotLast = FALSE;
+                           break;
+                        }
+                        SDOp = (ec_SDOt *)MbxOut;
                         SDOp->MbxHeader.length = htoes(0x000a);
                         SDOp->MbxHeader.address = htoes(0x0000);
                         SDOp->MbxHeader.priority = 0x00;
@@ -226,13 +238,15 @@ int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subinde
                         SDOp->SubIndex = subindex;
                         SDOp->ldata[0] = 0;
                         /* send segmented upload request to slave */
-                        wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
-                        /* is mailbox transferred to slave ? */
+                        wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+                        MbxOut = NULL;
                         if (wkc > 0)
                         {
-                           ec_clearmbx(&MbxIn);
+                           if(MbxIn) ecx_dropmbx(context, MbxIn);
+                           MbxIn = NULL;
                            /* read slave response */
-                           wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+                           wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
+                           aSDOp = (ec_SDOt *)MbxIn;
                            /* has slave responded ? */
                            if (wkc > 0)
                            {
@@ -308,6 +322,8 @@ int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subinde
          }
       }
    }
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
@@ -332,18 +348,20 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
                  boolean CA, int psize, const void *p, int Timeout)
 {
    ec_SDOt *SDOp, *aSDOp;
-   int wkc, maxdata, framedatasize;
-   ec_mbxbuft MbxIn, MbxOut;
+   int wkc, maxdata;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt, toggle;
+   int framedatasize;
    boolean  NotLast;
    const uint8 *hp;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOt *)&MbxIn;
-   SDOp = (ec_SDOt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   wkc = ecx_mbxreceive2(context, Slave, &MbxIn, 0);
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOt *)MbxOut;
    maxdata = context->slavelist[Slave].mbx_l - 0x10; /* data section=mailbox size - 6 mbx - 2 CoE - 8 sdo req */
    /* if small data use expedited transfer */
    if ((psize <= 4) && !CA)
@@ -363,14 +381,17 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
       /* copy parameter data to mailbox */
       memcpy(&SDOp->ldata[0], hp, psize);
       /* send mailbox SDO download request to slave */
-      wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+      wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+      MbxOut = NULL;
       if (wkc > 0)
       {
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout);
+         wkc = ecx_mbxreceive2(context, Slave, &MbxIn, Timeout);
          if (wkc > 0)
          {
+            aSDOp = (ec_SDOt *)MbxIn;
             /* response should be CoE, SDO response, correct index and subindex */
             if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
                 ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) &&
@@ -433,14 +454,17 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
       hp += framedatasize;
       psize -= framedatasize;
       /* send mailbox SDO download request to slave */
-      wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+      wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+      MbxOut = NULL;
       if (wkc > 0)
       {
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout);
+         wkc = ecx_mbxreceive2(context, Slave, &MbxIn, Timeout);
          if (wkc > 0)
          {
+            aSDOp = (ec_SDOt *)MbxIn;
             /* response should be CoE, SDO response, correct index and subindex */
             if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
                 ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) &&
@@ -453,7 +477,14 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
                /* repeat while segments left */
                while (NotLast)
                {
-                  SDOp = (ec_SDOt *)&MbxOut;
+                  MbxOut = ecx_getmbx(context);
+                  if(!MbxOut)
+                  {
+                     NotLast = FALSE;
+                     break;
+                  }
+                  ec_clearmbx(MbxOut);
+                  SDOp = (ec_SDOt *)MbxOut;
                   framedatasize = psize;
                   NotLast = FALSE;
                   SDOp->Command = 0x01; /* last segment */
@@ -486,14 +517,17 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
                   hp += framedatasize;
                   psize -= framedatasize;
                   /* send SDO download request */
-                  wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+                  wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+                  MbxOut = NULL;
                   if (wkc > 0)
                   {
-                     ec_clearmbx(&MbxIn);
+                     if(MbxIn) ecx_dropmbx(context, MbxIn);
+                     MbxIn = NULL;
                      /* read slave response */
-                     wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout);
+                     wkc = ecx_mbxreceive2(context, Slave, &MbxIn, Timeout);
                      if (wkc > 0)
                      {
+                        aSDOp = (ec_SDOt *)MbxIn;
                         if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
                             ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) &&
                             ((aSDOp->Command & 0xe0) == 0x20))
@@ -534,7 +568,8 @@ int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubInd
          }
       }
    }
-
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
@@ -553,14 +588,17 @@ int ecx_RxPDO(ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize
 {
    ec_SDOt *SDOp;
    int wkc, maxdata, framedatasize;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
-
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   SDOp = (ec_SDOt *)&MbxOut;
+   
+   MbxIn = NULL;
+   MbxOut = NULL;
+   wkc = ecx_mbxreceive2(context, Slave, &MbxIn, 0);
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOt *)MbxOut;
    maxdata = context->slavelist[Slave].mbx_l - 0x08; /* data section=mailbox size - 6 mbx - 2 CoE */
    framedatasize = psize;
    if (framedatasize > maxdata)
@@ -578,8 +616,8 @@ int ecx_RxPDO(ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize
    /* copy PDO data to mailbox */
    memcpy(&SDOp->Command, p, framedatasize);
    /* send mailbox RxPDO request to slave */
-   wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
-
+   wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    return wkc;
 }
 
@@ -599,16 +637,18 @@ int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber , int *psi
 {
    ec_SDOt *SDOp, *aSDOp;
    int wkc;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
    uint16 framedatasize;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOt *)&MbxIn;
-   SDOp = (ec_SDOt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOt *)MbxOut;
    SDOp->MbxHeader.length = htoes(0x02);
    SDOp->MbxHeader.address = htoes(0x0000);
    SDOp->MbxHeader.priority = 0x00;
@@ -617,15 +657,17 @@ int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber , int *psi
    context->slavelist[slave].mbx_cnt = cnt;
    SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + MBX_HDR_SET_CNT(cnt); /* CoE */
    SDOp->CANOpen = htoes((TxPDOnumber & 0x01ff) + (ECT_COES_TXPDO_RR << 12)); /* number 9bits service upper 4 bits */
-   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    if (wkc > 0)
    {
-      /* clean mailboxbuffer */
-      ec_clearmbx(&MbxIn);
+      if(MbxIn) ecx_dropmbx(context, MbxIn);
+      MbxIn = NULL;
       /* read slave response */
-      wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+      wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
       if (wkc > 0) /* succeeded to read slave response ? */
       {
+         aSDOp = (ec_SDOt *)MbxIn;
          /* slave response should be CoE, TxPDO */
          if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
              ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_TXPDO))
@@ -661,7 +703,8 @@ int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber , int *psi
          }
       }
    }
-
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
@@ -999,7 +1042,7 @@ int ecx_readPDOmapCA(ecx_contextt *context, uint16 Slave, int Thread_n, uint32 *
 int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
 {
    ec_SDOservicet *SDOp, *aSDOp;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    int wkc;
    uint16 x, n, i, sp, offset;
    boolean stop;
@@ -1008,12 +1051,15 @@ int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
 
    pODlist->Slave = Slave;
    pODlist->Entries = 0;
-   ec_clearmbx(&MbxIn);
-   /* clear pending out mailbox in slave if available. Timeout is set to 0 */
-   wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOservicet*)&MbxIn;
-   SDOp = (ec_SDOservicet*)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, Slave, &MbxIn, 0);
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOservicet *)MbxOut;
    SDOp->MbxHeader.length = htoes(0x0008);
    SDOp->MbxHeader.address = htoes(0x0000);
    SDOp->MbxHeader.priority = 0x00;
@@ -1027,7 +1073,8 @@ int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
    SDOp->Fragments = 0; /* fragments left */
    SDOp->wdata[0] = htoes(0x01); /* all objects */
    /* send get object description list request to slave */
-   wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    /* mailbox placed in slave ? */
    if (wkc > 0)
    {
@@ -1038,12 +1085,14 @@ int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
       do
       {
          stop = TRUE; /* assume this is last iteration */
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM);
+         wkc = ecx_mbxreceive2(context, Slave, &MbxIn, EC_TIMEOUTRXM);
          /* got response ? */
          if (wkc > 0)
          {
+            aSDOp = (ec_SDOservicet*)MbxIn;
             /* response should be CoE and "get object description list response" */
             if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
                 ((aSDOp->Opcode & 0x7f) == ECT_GET_ODLIST_RES))
@@ -1105,6 +1154,8 @@ int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
       }
       while ((x <= 128) && !stop);
    }
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
@@ -1120,7 +1171,7 @@ int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlis
    ec_SDOservicet *SDOp, *aSDOp;
    int wkc;
    uint16  n, Slave;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
 
    Slave = pODlist->Slave;
@@ -1128,12 +1179,15 @@ int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlis
    pODlist->ObjectCode[Item] = 0;
    pODlist->MaxSub[Item] = 0;
    pODlist->Name[Item][0] = 0;
-   ec_clearmbx(&MbxIn);
-   /* clear pending out mailbox in slave if available. Timeout is set to 0 */
-   wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOservicet*)&MbxIn;
-   SDOp = (ec_SDOservicet*)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, Slave, &MbxIn, 0);
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOservicet *)MbxOut;
    SDOp->MbxHeader.length = htoes(0x0008);
    SDOp->MbxHeader.address = htoes(0x0000);
    SDOp->MbxHeader.priority = 0x00;
@@ -1147,16 +1201,19 @@ int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlis
    SDOp->Fragments = 0; /* fragments left */
    SDOp->wdata[0] = htoes(pODlist->Index[Item]); /* Data of Index */
    /* send get object description request to slave */
-   wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    /* mailbox placed in slave ? */
    if (wkc > 0)
    {
-      ec_clearmbx(&MbxIn);
+      if (MbxIn) ecx_dropmbx(context, MbxIn);  
+      MbxIn = NULL;
       /* read slave response */
-      wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM);
+      wkc = ecx_mbxreceive2(context, Slave, &MbxIn, EC_TIMEOUTRXM);
       /* got response ? */
       if (wkc > 0)
       {
+         aSDOp = (ec_SDOservicet*)MbxIn;
          if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
              ((aSDOp->Opcode & 0x7f) == ECT_GET_OD_RES))
          {
@@ -1187,7 +1244,8 @@ int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlis
          }
       }
    }
-
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
@@ -1207,18 +1265,21 @@ int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt
    int wkc;
    uint16 Index, Slave;
    int16 n;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
 
    wkc = 0;
    Slave = pODlist->Slave;
    Index = pODlist->Index[Item];
-   ec_clearmbx(&MbxIn);
-   /* clear pending out mailbox in slave if available. Timeout is set to 0 */
-   wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSDOp = (ec_SDOservicet*)&MbxIn;
-   SDOp = (ec_SDOservicet*)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, Slave, &MbxIn, 0);
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   MbxOut = ecx_getmbx(context);
+   if(!MbxOut) return wkc;
+   ec_clearmbx(MbxOut);
+   SDOp = (ec_SDOservicet *)MbxOut;
    SDOp->MbxHeader.length = htoes(0x000a);
    SDOp->MbxHeader.address = htoes(0x0000);
    SDOp->MbxHeader.priority = 0x00;
@@ -1234,16 +1295,19 @@ int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt
    SDOp->bdata[2] = SubI;       /* SubIndex */
    SDOp->bdata[3] = 1 + 2 + 4; /* get access rights, object category, PDO */
    /* send get object entry description request to slave */
-   wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, Slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    /* mailbox placed in slave ? */
    if (wkc > 0)
    {
-      ec_clearmbx(&MbxIn);
+      if (MbxIn) ecx_dropmbx(context, MbxIn);  
+      MbxIn = NULL;
       /* read slave response */
-      wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM);
+      wkc = ecx_mbxreceive2(context, Slave, &MbxIn, EC_TIMEOUTRXM);
       /* got response ? */
       if (wkc > 0)
       {
+         aSDOp = (ec_SDOservicet*)MbxIn;
          if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) &&
              ((aSDOp->Opcode &  0x7f) == ECT_GET_OE_RES))
          {
@@ -1280,7 +1344,8 @@ int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt
          }
       }
    }
-
+   if (MbxIn) ecx_dropmbx(context, MbxIn);  
+   if (MbxOut) ecx_dropmbx(context, MbxOut);  
    return wkc;
 }
 
index 017028b4905f9e881cf0484eb6b1edfa7616cd22..7e4473f4776cfbc5ab044fcfc1e358842b9be085 100644 (file)
@@ -114,6 +114,7 @@ void ecx_init_context(ecx_contextt *context)
    {
       /* default start address per group entry */
       context->grouplist[lp].logstartaddr = lp << EC_LOGGROUPOFFSET;
+      ecx_initmbxqueue(context, lp);
    }
 }
 
@@ -357,12 +358,6 @@ int ecx_config_init(ecx_contextt *context, uint8 usetable)
       {
          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* Manuf */
          context->slavelist[slave].eep_man = etohl(eedat);
-         ecx_readeeprom1(context, slave, ECT_SII_SN); /* serial # */
-      }
-      for (slave = 1; slave <= *(context->slavecount); slave++)
-      {
-         eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* serial # */
-         context->slavelist[slave].eep_sn = etohl(eedat);
          ecx_readeeprom1(context, slave, ECT_SII_ID); /* ID */
       }
       for (slave = 1; slave <= *(context->slavecount); slave++)
@@ -375,6 +370,12 @@ int ecx_config_init(ecx_contextt *context, uint8 usetable)
       {
          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* revision */
          context->slavelist[slave].eep_rev = etohl(eedat);
+         ecx_readeeprom1(context, slave, ECT_SII_SER); /* serial number */
+      }
+      for (slave = 1; slave <= *(context->slavecount); slave++)
+      {
+         eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* serial number */
+         context->slavelist[slave].eep_ser = etohl(eedat);
          ecx_readeeprom1(context, slave, ECT_SII_RXMBXADR); /* write mailbox address + mailboxsize */
       }
       for (slave = 1; slave <= *(context->slavecount); slave++)
@@ -1167,6 +1168,46 @@ static void ecx_config_create_output_mappings(ecx_contextt *context, void *pIOma
    context->slavelist[slave].FMMUunused = FMMUc;
 }
 
+static void ecx_config_create_mbxstatus_mappings(ecx_contextt *context, void *pIOmap,
+   uint8 group, int16 slave, uint32 * LogAddr)
+{
+   uint16 FMMUsize = 1;
+   uint16 configadr;
+   uint8 FMMUc;
+   int position;
+
+   EC_PRINT(" =Slave %d, MBXSTATUS MAPPING\n", slave);
+
+   configadr = context->slavelist[slave].configadr;
+   FMMUc = context->slavelist[slave].FMMUunused;
+   if (context->slavelist[slave].mbx_l && (FMMUc < EC_MAXFMMU)) /* slave with mailbox */
+   {
+      context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(*LogAddr);
+      context->slavelist[slave].FMMU[FMMUc].LogStartbit = 0;
+      *LogAddr += FMMUsize;
+      context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
+      context->slavelist[slave].FMMU[FMMUc].LogEndbit = 7;
+      context->slavelist[slave].FMMU[FMMUc].PhysStart  = ECT_REG_SM1STAT;
+      context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;
+      context->slavelist[slave].FMMU[FMMUc].FMMUtype = 1;
+      context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;
+      /* program FMMU for input */
+      ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),
+         sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
+
+      position = etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);
+      context->slavelist[slave].mbxstatus = (uint8 *)(pIOmap) + position;
+      position -= context->grouplist[group].Obytes + context->grouplist[group].Ibytes;
+      context->grouplist[group].mbxstatuslookup[position] = slave;
+      context->grouplist[group].mbxstatuslength++;
+      FMMUc++;
+      /* account for MBXSTATUS wkc increment */
+      if(!context->slavelist[slave].Ibytes)
+         context->grouplist[group].inputsWKC++;
+   }
+   context->slavelist[slave].FMMUunused = FMMUc;
+}
+
 static int ecx_main_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group, boolean forceByteAlignment)
 {
    uint16 slave, configadr;
@@ -1339,14 +1380,52 @@ static int ecx_main_config_map_group(ecx_contextt *context, void *pIOmap, uint8
       context->grouplist[group].nsegments = currentsegment + 1;
       context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes;
       context->grouplist[group].Ibytes = LogAddr -
-         context->grouplist[group].logstartaddr -
-         context->grouplist[group].Obytes;
+               context->grouplist[group].logstartaddr -
+               context->grouplist[group].Obytes;
+
+      /* do mbxstatus mapping of slave and program FMMUs */
+      for (slave = 1; slave <= *(context->slavecount); slave++)
+      {
+         configadr = context->slavelist[slave].configadr;
+         if (!group || (group == context->slavelist[slave].group))
+         {
+            ecx_config_create_mbxstatus_mappings(context, pIOmap, group, slave, &LogAddr);
+            diff = LogAddr - oLogAddr;
+            oLogAddr = LogAddr;
+            if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
+            {
+                  context->grouplist[group].IOsegment[currentsegment] = segmentsize;
+                  if (currentsegment < (EC_MAXIOSEGMENTS - 1))
+                  {
+                        currentsegment++;
+                        segmentsize = diff;
+                  }
+            }
+            else
+            {
+                  segmentsize += diff;
+            }
+            ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */
+            ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET3); /* set safeop status */
+            if (context->slavelist[slave].blockLRW)
+            {
+               context->grouplist[group].blockLRW++;
+            }
+            context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
+         }
+      }
+
+      context->grouplist[group].IOsegment[currentsegment] = segmentsize;
+      context->grouplist[group].nsegments = currentsegment + 1;
+      context->grouplist[group].mbxstatus = (uint8 *)(pIOmap) + context->grouplist[group].Obytes + context->grouplist[group].Ibytes;
+      context->grouplist[group].mbxstatuslength = LogAddr - context->grouplist[group].Obytes - context->grouplist[group].Ibytes;
       if (!group)
       {
          context->slavelist[0].inputs = (uint8 *)(pIOmap) + context->slavelist[0].Obytes;
          context->slavelist[0].Ibytes = LogAddr -
             context->grouplist[group].logstartaddr -
             context->slavelist[0].Obytes; /* store input bytes in master record */
+         context->slavelist[0].mbxstatus = (uint8 *)(pIOmap) + context->slavelist[0].Obytes + context->slavelist[0].Ibytes;
       }
 
       EC_PRINT("IOmapSize %d\n", LogAddr - context->grouplist[group].logstartaddr);
@@ -1512,7 +1591,9 @@ int ecx_config_overlap_map_group(ecx_contextt *context, void *pIOmap, uint8 grou
       context->grouplist[group].outputs = pIOmap;
       context->grouplist[group].inputs = (uint8 *)pIOmap + context->grouplist[group].Obytes;
 
-      /* Move calculated inputs with OBytes offset*/
+      context->grouplist[group].mbxstatus = (uint8 *)pIOmap + context->grouplist[group].Obytes + context->grouplist[group].Ibytes;
+
+     /* Move calculated inputs with OBytes offset*/
       for (slave = 1; slave <= *(context->slavecount); slave++)
       {
          if (!group || (group == context->slavelist[slave].group))
@@ -1531,6 +1612,7 @@ int ecx_config_overlap_map_group(ecx_contextt *context, void *pIOmap, uint8 grou
          context->slavelist[0].Obytes = soLogAddr - context->grouplist[group].logstartaddr;
          context->slavelist[0].inputs = (uint8 *)pIOmap + context->slavelist[0].Obytes;
          context->slavelist[0].Ibytes = siLogAddr - context->grouplist[group].logstartaddr;
+         context->slavelist[0].mbxstatus = (uint8 *)pIOmap + context->slavelist[0].Obytes + context->slavelist[0].Ibytes;
       }
 
       EC_PRINT("IOmapSize %d\n", context->grouplist[group].Obytes + context->grouplist[group].Ibytes);
@@ -1637,6 +1719,8 @@ int ecx_reconfig_slave(ecx_contextt *context, uint16 slave, int timeout)
                sizeof(ec_smt), &context->slavelist[slave].SM[nSM], timeout);
          }
       }
+      /* small delay to allow slave to process SM changes */
+      osal_usleep(5000);
       ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP) , timeout);
       state = ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */
       if( state == EC_STATE_PRE_OP)
index e319c8f48c432c6207276ee30d040d2560df80fa..d7d4efc514a3fb3ab94aa5d44ffd9afb4447e278 100644 (file)
@@ -82,17 +82,18 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
    int32 dataread = 0;
    int32 buffersize, packetnumber, prevpacket = 0;
    uint16 fnsize, maxdata, segmentdata;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
    boolean worktodo;
 
    buffersize = *psize;
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aFOEp = (ec_FOEt *)&MbxIn;
-   FOEp = (ec_FOEt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
+   MbxOut = ecx_getmbx(context);
+   ec_clearmbx(MbxOut);
+   FOEp = (ec_FOEt *)MbxOut;
    fnsize = (uint16)strlen(filename);
    if (fnsize > EC_MAXFOEDATA)
    {
@@ -115,18 +116,20 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
    /* copy filename in mailbox */
    memcpy(&FOEp->FileName[0], filename, fnsize);
    /* send FoE request to slave */
-   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    if (wkc > 0) /* succeeded to place mailbox in slave ? */
    {
       do
       {
          worktodo = FALSE;
-         /* clean mailboxbuffer */
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+         wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
          if (wkc > 0) /* succeeded to read slave response ? */
          {
+            aFOEp = (ec_FOEt *)MbxIn;
             /* slave response should be FoE */
             if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
             {
@@ -143,6 +146,9 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
                      {
                         worktodo = TRUE;
                      }
+                     MbxOut = ecx_getmbx(context);
+                     ec_clearmbx(MbxOut);
+                     FOEp = (ec_FOEt *)MbxOut;
                      FOEp->MbxHeader.length = htoes(0x0006);
                      FOEp->MbxHeader.address = htoes(0x0000);
                      FOEp->MbxHeader.priority = 0x00;
@@ -153,7 +159,8 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
                      FOEp->OpCode = ECT_FOE_ACK;
                      FOEp->PacketNumber = htoel(packetnumber);
                      /* send FoE ack to slave */
-                     wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+                     wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+                     MbxOut = NULL;
                      if (wkc <= 0)
                      {
                         worktodo = FALSE;
@@ -192,7 +199,8 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
          }
       } while (worktodo);
    }
-
+   if(MbxIn) ecx_dropmbx(context, MbxIn);
+   if(MbxOut) ecx_dropmbx(context, MbxOut);
    return wkc;
 }
 
@@ -214,17 +222,18 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
    int32 packetnumber, sendpacket = 0;
    uint16 fnsize, maxdata;
    int segmentdata;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
    boolean worktodo, dofinalzero;
    int tsize;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aFOEp = (ec_FOEt *)&MbxIn;
-   FOEp = (ec_FOEt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
+   MbxOut = ecx_getmbx(context);
+   ec_clearmbx(MbxOut);
+   FOEp = (ec_FOEt *)MbxOut;
    dofinalzero = TRUE;
    fnsize = (uint16)strlen(filename);
    if (fnsize > EC_MAXFOEDATA)
@@ -248,18 +257,20 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
    /* copy filename in mailbox */
    memcpy(&FOEp->FileName[0], filename, fnsize);
    /* send FoE request to slave */
-   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    if (wkc > 0) /* succeeded to place mailbox in slave ? */
    {
       do
       {
          worktodo = FALSE;
-         /* clean mailboxbuffer */
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+         wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
          if (wkc > 0) /* succeeded to read slave response ? */
          {
+            aFOEp = (ec_FOEt *)MbxIn;
             /* slave response should be FoE */
             if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
             {
@@ -291,6 +302,9 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
                            {
                               dofinalzero = TRUE;
                            }
+                           MbxOut = ecx_getmbx(context);
+                           ec_clearmbx(MbxOut);
+                           FOEp = (ec_FOEt *)MbxOut;
                            FOEp->MbxHeader.length = htoes((uint16)(0x0006 + segmentdata));
                            FOEp->MbxHeader.address = htoes(0x0000);
                            FOEp->MbxHeader.priority = 0x00;
@@ -304,7 +318,8 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
                            memcpy(&FOEp->Data[0], p, segmentdata);
                            p = (uint8 *)p + segmentdata;
                            /* send FoE data to slave */
-                           wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+                           wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+                           MbxOut = NULL;
                            if (wkc <= 0)
                            {
                               worktodo = FALSE;
@@ -395,7 +410,8 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
          }
       } while (worktodo);
    }
-
+   if(MbxIn) ecx_dropmbx(context, MbxIn);
+   if(MbxOut) ecx_dropmbx(context, MbxOut);
    return wkc;
 }
 
index a0951b89cd91711411c6ee62b2741bc2386eed12..174eb4fbfa35a0c7bad722f9625e821b8bcdcc8e 100644 (file)
@@ -98,6 +98,8 @@ int64                   ec_DCtime;
 ecx_portt               ecx_port;
 ecx_redportt            ecx_redport;
 
+ec_mbxpoolt             ec_mbxpool;
+
 ecx_contextt  ecx_context = {
     &ecx_port,          // .port          =
     &ec_slave[0],       // .slavelist     =
@@ -117,6 +119,7 @@ ecx_contextt  ecx_context = {
     &ec_PDOdesc[0],     // .PDOdesc       =
     &ec_SM,             // .eepSM         =
     &ec_FMMU,           // .eepFMMU       =
+    &ec_mbxpool,        // .mbxpool       =
     NULL,               // .FOEhook()
     NULL,               // .EOEhook()
     0,                  // .manualstatechange
@@ -287,6 +290,7 @@ static void ecx_mbxemergencyerror(ecx_contextt *context, uint16 Slave,uint16 Err
  */
 int ecx_init(ecx_contextt *context, const char * ifname)
 {
+   ecx_initmbxpool(context);
    return ecx_setupnic(context->port, ifname, FALSE);
 }
 
@@ -302,6 +306,7 @@ int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, const char
    int rval, zbuf;
    ec_etherheadert *ehp;
 
+   ecx_initmbxpool(context);
    context->port->redport = redport;
    ecx_setupnic(context->port, ifname, FALSE);
    rval = ecx_setupnic(context->port, if2name, TRUE);
@@ -320,9 +325,200 @@ int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, const char
  */
 void ecx_close(ecx_contextt *context)
 {
+   osal_mutex_destroy(context->mbxpool->mbxmutex);
    ecx_closenic(context->port);
-};
+}
+
+ec_mbxbuft *ecx_getmbx(ecx_contextt *context)
+{
+   ec_mbxbuft *mbx = NULL;
+   ec_mbxpoolt *mbxpool = context->mbxpool;
+   osal_mutex_lock(mbxpool->mbxmutex);
+   if(mbxpool->listcount > 0)
+   {
+      mbx = (ec_mbxbuft *)&(mbxpool->mbx[mbxpool->mbxemptylist[mbxpool->listtail]]);
+//      printf("getmbx item:%d mbx:%p\n\r",mbxpool->mbxemptylist[mbxpool->listtail], mbx);
+      mbxpool->listtail++;
+      if(mbxpool->listtail >= EC_MBXPOOLSIZE) mbxpool->listtail = 0;
+      mbxpool->listcount--;
+   }
+   osal_mutex_unlock(mbxpool->mbxmutex);
+   return mbx;
+}
+
+int ecx_dropmbx(ecx_contextt *context, ec_mbxbuft *mbx)
+{
+   ec_mbxpoolt *mbxpool = context->mbxpool;
+   int item = mbx - &(mbxpool->mbx[0]);
+//   printf("dropmbx item:%d mbx:%p\n\r",item, mbx);
+   if((item >= 0) && (item < EC_MBXPOOLSIZE))
+   {
+      osal_mutex_lock(mbxpool->mbxmutex);
+      mbxpool->mbxemptylist[mbxpool->listhead++] = item;
+      if(mbxpool->listhead >= EC_MBXPOOLSIZE) mbxpool->listhead = 0;
+      mbxpool->listcount++;
+      osal_mutex_unlock(mbxpool->mbxmutex);
+      return 1;
+   }
+   return 0;
+}
+
+int ecx_initmbxpool(ecx_contextt *context)
+{
+   int retval = 0;
+   ec_mbxpoolt *mbxpool = context->mbxpool;
+   mbxpool->mbxmutex = (osal_mutext *)osal_mutex_create();
+   for(int item = 0 ; item < EC_MBXPOOLSIZE ; item++)
+   {
+      mbxpool->mbxemptylist[item] = item;
+   }
+   mbxpool->listhead = 0;
+   mbxpool->listtail = 0;
+   mbxpool->listcount = EC_MBXPOOLSIZE;
+ //  printf("intmbxpool mbxp:%p mutex:%p\n\r", mbxpool->mbx[0],  mbxpool->mbxmutex);
+   return retval;
+}
+
+int ecx_initmbxqueue(ecx_contextt *context, uint16 group)
+{
+   int retval = 0;
+   int cnt;
+   ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+   mbxqueue->mbxmutex = (osal_mutext *)osal_mutex_create();
+   mbxqueue->listhead = 0;
+   mbxqueue->listtail = 0;
+   mbxqueue->listcount = 0;
+   for(cnt = 0 ; cnt < EC_MBXPOOLSIZE ; cnt++)
+      mbxqueue->mbxticket[cnt] = -1;
+   return retval;
+}
+
+int ecx_mbxaddqueue(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx)
+{
+   int ticketloc;
+   int ticket = -1;
+   uint8 group = context->slavelist[slave].group;
+   ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+   osal_mutex_lock(mbxqueue->mbxmutex);
+   if((mbxqueue->listcount < EC_MBXPOOLSIZE))
+   {
+      ticketloc = mbxqueue->listhead;
+      while((++ticket < EC_MBXPOOLSIZE) && (mbxqueue->mbxticket[ticket] >= 0)) {};
+      mbxqueue->mbxticket[ticket] = ticketloc;
+      mbxqueue->mbxslave[ticketloc] = slave;
+      mbxqueue->mbx[ticketloc] = mbx;
+      mbxqueue->listhead++;
+      if(mbxqueue->listhead >= EC_MBXPOOLSIZE) mbxqueue->listhead = 0;
+      mbxqueue->mbxremove[ticketloc] = 0;
+      mbxqueue->mbxstate[ticketloc] = EC_MBXQUEUESTATE_REQ;
+      mbxqueue->listcount++;
+   }
+   osal_mutex_unlock(mbxqueue->mbxmutex);
+   return ticket;
+}
+
+int ecx_mbxdonequeue(ecx_contextt *context, uint16 slave, int ticket)
+{
+   int retval = 0;
+   if((ticket >= 0) && (ticket < EC_MBXPOOLSIZE))
+   {
+      uint8 group = context->slavelist[slave].group;
+      ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+      osal_mutex_lock(mbxqueue->mbxmutex);
+      if(mbxqueue->mbxstate[mbxqueue->mbxticket[ticket]] == EC_MBXQUEUESTATE_DONE)
+      {
+         mbxqueue->mbxremove[mbxqueue->mbxticket[ticket]] = 1;
+         mbxqueue->mbxticket[ticket] = -1;
+         retval = 1;
+      }
+      osal_mutex_unlock(mbxqueue->mbxmutex);
+   }
+   return retval;
+}
+
+int ecx_mbxexpirequeue(ecx_contextt *context, uint16 slave, int ticket)
+{
+   int retval = 0;
+   if((ticket >= 0) && (ticket < EC_MBXPOOLSIZE))
+   {
+      uint8 group = context->slavelist[slave].group;
+      ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+      osal_mutex_lock(mbxqueue->mbxmutex);
+      if(mbxqueue->mbxstate[mbxqueue->mbxticket[ticket]] > EC_MBXQUEUESTATE_NONE)
+      {
+         mbxqueue->mbxremove[mbxqueue->mbxticket[ticket]] = 1;
+         mbxqueue->mbxticket[ticket] = -1;
+         retval = 1;
+      }
+      osal_mutex_unlock(mbxqueue->mbxmutex);
+   }
+   return retval;
+}
+
+int ecx_mbxrotatequeue(ecx_contextt *context, uint16 group, int ticketloc)
+{
+   int retval = 0;
+   int cnt = 0;
+   int ticket;
+   ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+   osal_mutex_lock(mbxqueue->mbxmutex);
+   int head = mbxqueue->listhead;
+   int tail = mbxqueue->listtail;
+   if(head != tail)
+   {
+      while((cnt < EC_MBXPOOLSIZE) && (mbxqueue->mbxticket[cnt] != ticketloc)) cnt++;
+      ticket = cnt;
+      if((ticket >= 0) && (ticket < EC_MBXPOOLSIZE))
+      {
+         mbxqueue->mbxticket[ticket] = head;
+         mbxqueue->mbxremove[head] = mbxqueue->mbxremove[tail];
+         mbxqueue->mbxstate[head] = mbxqueue->mbxstate[tail];
+         mbxqueue->mbxslave[head] = mbxqueue->mbxslave[tail];
+         mbxqueue->mbx[head] = mbxqueue->mbx[tail];
+         mbxqueue->listhead++;
+         if(mbxqueue->listhead >= EC_MBXPOOLSIZE) mbxqueue->listhead = 0;
+         mbxqueue->listtail++;
+         if(mbxqueue->listtail >= EC_MBXPOOLSIZE) mbxqueue->listtail = 0;
+         retval = 1;
+      }
+   }
+   else 
+   {
+      retval = 1;
+   }
+   osal_mutex_unlock(mbxqueue->mbxmutex);
+   return retval;
+}
+
+int ecx_slavembxcyclic(ecx_contextt *context, uint16 slave)
+{
+   if(context->slavelist[slave].mbxstatus)
+   {
+      context->slavelist[slave].coembxin = EC_MBXINENABLE;
+      context->slavelist[slave].mbxhandlerstate = ECT_MBXH_CYCLIC;
+      return 1;
+   }
+   return 0;
+}
 
+ec_mbxbuft *ecx_mbxdropqueue(ecx_contextt *context, uint16 group, int ticketloc)
+{
+   ec_mbxbuft *mbx;
+   ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+//   printf("mbxgetqueue item:%d mbx:%p\n\r",item, mbx);
+   osal_mutex_lock(mbxqueue->mbxmutex);
+   mbxqueue->mbxstate[ticketloc] = EC_MBXQUEUESTATE_NONE;
+   mbxqueue->mbxremove[ticketloc] = 0;
+   mbxqueue->mbxslave[ticketloc] = 0;
+   mbx = mbxqueue->mbx[ticketloc];
+   mbxqueue->mbx[ticketloc] = NULL;
+   mbxqueue->listtail++;
+   if(mbxqueue->listtail >= EC_MBXPOOLSIZE) mbxqueue->listtail = 0;
+   mbxqueue->listcount--;
+   osal_mutex_unlock(mbxqueue->mbxmutex);
+   return mbx;
+}
 /** Read one byte from slave EEPROM via cache.
  *  If the cache location is empty then a read request is made to the slave.
  *  Depending on the slave capabilities the request is 4 or 8 bytes.
@@ -926,9 +1122,45 @@ uint8 ec_nextmbxcnt(uint8 cnt)
  */
 void ec_clearmbx(ec_mbxbuft *Mbx)
 {
+  if(Mbx)      
     memset(Mbx, 0x00, EC_MAXMBX);
 }
 
+int ecx_clearmbxstatus(ecx_contextt *context, uint8 group)
+{
+   if(context->grouplist[group].mbxstatus && context->grouplist[group].mbxstatuslength)
+   {
+      memset(context->grouplist[group].mbxstatus, 0x00, context->grouplist[group].mbxstatuslength);
+      return 1;
+   }
+   return 0;
+}
+
+int ecx_readmbxstatus(ecx_contextt *context, uint16 slave, uint8 *SMstat)
+{
+   int wkc = 0;
+   if(context->slavelist[slave].mbxhandlerstate == ECT_MBXH_CYCLIC)
+   {
+      *SMstat = *(context->slavelist[slave].mbxstatus);
+      wkc = 1;
+   }
+   else
+   { 
+      uint16 configadr = context->slavelist[slave].configadr;
+      wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(uint8), SMstat, EC_TIMEOUTRET);
+   }
+   return wkc;
+}
+
+int ecx_readmbxstatusex(ecx_contextt *context, uint16 slave, uint16 *SMstatex)
+{
+   uint16 hu16;
+   uint16 configadr = context->slavelist[slave].configadr;
+   int wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(hu16), &hu16, EC_TIMEOUTRET);
+   *SMstatex = etohs(hu16);
+   return wkc;
+}
+
 /** Check if IN mailbox of slave is empty.
  * @param[in] context  = context struct
  * @param[in] slave    = Slave number
@@ -964,35 +1196,321 @@ int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout)
    return 0;
 }
 
+int ecx_mbxinhandler(ecx_contextt *context, uint8 group, int limit)
+{
+   int cnt, cntoffset, wkc, wkc2, limitcnt;
+   int maxcnt = context->grouplist[group].mbxstatuslength;
+   ec_mbxbuft *mbx;
+   ec_mbxheadert *mbxh;
+   ec_emcyt *EMp;
+   ec_mbxerrort *MBXEp;
+   uint8 SMcontr;
+   uint16 SMstatex;
+   
+   limitcnt = 0;
+   int firstmbxpos = context->grouplist[group].lastmbxpos + 1;
+   int maxcntstored = maxcnt;
+   /* iterate over all possible mailbox slaves */
+   for(cnt = 0 ; cnt < maxcnt ; cnt++)
+   {
+      /* start from last stored slave position to allow fair handling under load */
+      cntoffset =  firstmbxpos + cnt;
+      if(cntoffset >= maxcntstored) cntoffset -= maxcntstored;
+      context->grouplist[group].lastmbxpos = cntoffset;
+      uint16 slave = context->grouplist[group].mbxstatuslookup[cntoffset];
+      ec_slavet *slaveitem = &context->slavelist[slave];
+      uint16 configadr = slaveitem->configadr;
+      /* cyclic handler enabled for this slave */
+      if(slaveitem->mbxhandlerstate == ECT_MBXH_CYCLIC)
+      {
+         /* handle robust mailbox protocol state machine */
+         if(slaveitem->mbxrmpstate)
+         {
+            if(slaveitem->islost) slaveitem->mbxrmpstate = 0;   
+            else
+            {
+               switch(slaveitem->mbxrmpstate)
+               {
+                  case 1 :
+                     if(ecx_readmbxstatusex(context, slave, &(slaveitem->mbxinstateex)) > 0)
+                     {
+                        slaveitem->mbxinstateex ^= 0x0200; /* toggle repeat request */
+                        slaveitem->mbxrmpstate++;
+                     }
+                     break;
+                  case 2 :
+                     SMstatex = htoes(slaveitem->mbxinstateex);
+                     if(ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstatex), &(slaveitem->mbxinstateex), EC_TIMEOUTRET) > 0)
+                     {
+                        slaveitem->mbxrmpstate++;
+                     }
+                     break; 
+                  case 3 :
+                     /* wait for repeat ack */
+                     wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET);
+                     if((wkc2 > 0) && ((SMcontr & 0x02) == (HI_BYTE(SMstatex) & 0x02)))
+                     {
+                        slaveitem->mbxrmpstate = 0;
+                     }
+                     break;
+               }
+               /* keep track of work limit */
+               if(++limitcnt >= limit) maxcnt = 0;
+            }
+         }
+         /* mbxin full detected */
+         else if((*(context->grouplist[group].mbxstatus + cntoffset) & 0x08) > 0)
+         {
+            uint16 mbxl = slaveitem->mbx_rl;
+            uint16 mbxro = slaveitem->mbx_ro;
+            if((mbxl > 0) && (mbx = ecx_getmbx(context)))
+            {
+               /* keep track of work limit */
+               if(++limitcnt >= limit) maxcnt = 0;
+               wkc = ecx_FPRD(context->port, configadr, mbxro, mbxl, mbx, EC_TIMEOUTRET); /* get mailbox */
+               if(wkc > 0)
+               {
+                  mbxh = (ec_mbxheadert *)mbx;
+                  if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_ERR) /* Mailbox error response? */
+                  {
+                     MBXEp = (ec_mbxerrort *)mbx;
+                     ecx_mbxerror(context, slave, etohs(MBXEp->Detail));
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_COE) /* CoE response? */
+                  {
+                     EMp = (ec_emcyt *)mbx;
+                     if ((etohs(EMp->CANOpen) >> 12) == 0x01) /* Emergency request? */
+                     {
+                        ecx_mbxemergencyerror(context, slave, etohs(EMp->ErrorCode), EMp->ErrorReg,
+                                 EMp->bData, etohs(EMp->w1), etohs(EMp->w2));
+                     }
+                     else
+                     {
+                        if(slaveitem->coembxin && (slaveitem->coembxinfull == FALSE))
+                        {
+                           slaveitem->coembxin = (uint8 *)mbx;
+                           mbx = NULL;
+                           slaveitem->coembxinfull = TRUE;
+                        }
+                        else
+                        {
+                           slaveitem->coembxoverrun++;
+                        }
+                     }
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_SOE) /* SoE response? */
+                  {
+                     if(slaveitem->soembxin && (slaveitem->soembxinfull == FALSE))
+                     {
+                        slaveitem->soembxin = (uint8 *)mbx;
+                        mbx = NULL;
+                        slaveitem->soembxinfull = TRUE;
+                     }
+                     else
+                     {
+                        slaveitem->soembxoverrun++;
+                     }
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_EOE) /* EoE response? */
+                  {
+                     if(slaveitem->eoembxin && (slaveitem->eoembxinfull == FALSE))
+                     {
+                        slaveitem->eoembxin = (uint8 *)mbx;
+                        mbx = NULL;
+                        slaveitem->eoembxinfull = TRUE;
+                     }
+                     else
+                     {
+                        slaveitem->eoembxoverrun++;
+                     }
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_FOE) /* FoE response? */
+                  {
+                     if(slaveitem->foembxin && (slaveitem->foembxinfull == FALSE))
+                     {
+                        slaveitem->foembxin = (uint8 *)mbx;
+                        mbx = NULL;
+                        slaveitem->foembxinfull = TRUE;
+                     }
+                     else
+                     {
+                        slaveitem->foembxoverrun++;
+                     }
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_VOE) /* VoE response? */
+                  {
+                     if(slaveitem->voembxin && (slaveitem->voembxinfull == FALSE))
+                     { 
+                        slaveitem->voembxin = (uint8 *)mbx;
+                        mbx = NULL;
+                        slaveitem->voembxinfull = TRUE;
+                     }
+                     else
+                     {
+                        slaveitem->voembxoverrun++;
+                     }
+                  }
+                  else if ((mbxh->mbxtype & 0x0f) == ECT_MBXT_AOE) /* AoE response? */
+                  {
+                     if(slaveitem->aoembxin && (slaveitem->aoembxinfull == FALSE))
+                     {
+                        slaveitem->aoembxin = (uint8 *)mbx;
+                        mbx = NULL;
+                        slaveitem->aoembxinfull = TRUE;
+                     }
+                     else
+                     {
+                        slaveitem->aoembxoverrun++;
+                     }
+                  }
+               }
+               else
+               {
+                  /* mailbox lost, initiate robust mailbox protocol */
+                  slaveitem->mbxrmpstate = 1;
+               }
+               /* release mailbox to pool if still owner */
+               if (mbx)
+               {
+                  ecx_dropmbx(context, mbx);  
+               }
+            }
+         }
+      } 
+   } 
+   return limitcnt;
+}
+
+int ecx_mbxouthandler(ecx_contextt *context, uint8 group, int limit)
+{
+   int wkc;
+   int limitcnt = 0;
+   int ticketloc, state;
+   uint16 slave, mbxl, mbxwo, configadr;
+   ec_mbxbuft *mbx;
+   ec_mbxqueuet *mbxqueue = &(context->grouplist[group].mbxtxqueue);
+   int listcount = mbxqueue->listcount;
+   while((limitcnt <= limit) && listcount) 
+   {
+      listcount--;
+      ticketloc = mbxqueue->listtail;
+      state = mbxqueue->mbxstate[ticketloc];
+      switch(state)
+      {
+         case EC_MBXQUEUESTATE_REQ :
+         case EC_MBXQUEUESTATE_FAIL:
+            slave = mbxqueue->mbxslave[ticketloc];
+            mbx = mbxqueue->mbx[ticketloc];
+            mbxl = context->slavelist[slave].mbx_l;
+            configadr = context->slavelist[slave].configadr;
+            mbxwo = context->slavelist[slave].mbx_wo;
+            limitcnt++;
+            if(context->slavelist[slave].state >= EC_STATE_PRE_OP)
+            {
+               /* write slave in mailbox 1st try*/
+               wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET);
+               if(wkc > 0)
+               {
+                  mbxqueue->mbxstate[ticketloc] = EC_MBXQUEUESTATE_DONE; // mbx tx ok
+                  ecx_dropmbx(context, mbx);
+                  mbxqueue->mbx[ticketloc] = NULL;
+               }
+               else
+               {
+                  if(state != EC_MBXQUEUESTATE_FAIL)
+                     mbxqueue->mbxstate[ticketloc] = EC_MBXQUEUESTATE_FAIL; // mbx tx fail, retry
+               }
+            }
+            /* fall through */
+         case EC_MBXQUEUESTATE_DONE: // mbx tx ok   
+            ecx_mbxrotatequeue(context, group, ticketloc);
+            break;
+      }
+      if(mbxqueue->mbxremove[ticketloc])
+      {
+         mbx = ecx_mbxdropqueue(context, group, ticketloc);
+         if(mbx) ecx_dropmbx(context, mbx);
+      }
+   }   
+   return limitcnt;
+}
+
+int ecx_mbxhandler(ecx_contextt *context, uint8 group, int limit)
+{
+   int limitcnt;
+   limitcnt = ecx_mbxinhandler(context, group, limit);
+   return ecx_mbxouthandler(context, group, (limit - limitcnt));
+ //return limitcnt;
+}
+
 /** Write IN mailbox to slave.
+ * Mailbox is fetched from pool by caller, ownership is transferred and dropped back to pool automatically.
  * @param[in]  context    = context struct
  * @param[in]  slave      = Slave number
- * @param[out] mbx        = Mailbox data
+ * @param[out] mbx        = Pointer to mailbox data
  * @param[in]  timeout    = Timeout in us
  * @return Work counter (>0 is success)
  */
 int ecx_mbxsend(ecx_contextt *context, uint16 slave,ec_mbxbuft *mbx, int timeout)
 {
-   uint16 mbxwo,mbxl,configadr;
-   int wkc;
+   uint16 mbxwo, mbxl, configadr;
+   int wkc, ticket;
+   osal_timert timer;
+   ec_slavet *slavelist = &(context->slavelist[slave]);
 
    wkc = 0;
-   configadr = context->slavelist[slave].configadr;
-   mbxl = context->slavelist[slave].mbx_l;
-   if ((mbxl > 0) && (mbxl <= EC_MAXMBX))
+   configadr = slavelist->configadr;
+   mbxl = slavelist->mbx_l;
+   if (slavelist->mbxhandlerstate == ECT_MBXH_CYCLIC)
    {
-      if (ecx_mbxempty(context, slave, timeout))
+      osal_timer_start(&timer, timeout);
+      wkc = 0;
+      if(mbxl > 0)
       {
-         mbxwo = context->slavelist[slave].mbx_wo;
-         /* write slave in mailbox */
-         wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET3);
+         do
+         {
+            if((ticket = ecx_mbxaddqueue(context, slave, mbx)) >= 0)
+            {
+               mbx = NULL;
+               do
+               {
+                  wkc = ecx_mbxdonequeue(context, slave, ticket);
+                  if (!wkc && (timeout > EC_LOCALDELAY))
+                  {
+                     osal_usleep(EC_LOCALDELAY);
+                  }
+               }
+               while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE));
+               if(wkc <= 0)
+               {
+                  if(!ecx_mbxexpirequeue(context, slave, ticket))
+                  {
+//                     printf("expirequeue failed\n\r");
+                  }
+               }
+            }
+            else if ((timeout > EC_LOCALDELAY))
+            {
+               osal_usleep(EC_LOCALDELAY);
+            }
+         }
+         while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE));
       }
-      else
+   }
+   else if ((mbxl > 0) && (mbxl <= EC_MAXMBX) && (slavelist->state >= EC_STATE_PRE_OP))
+   {
+      mbxwo = context->slavelist[slave].mbx_wo;
+      /* write slave in mailbox 1st try*/
+      wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET3);
+      /* if failed wait for empty mailbox */
+      if ((wkc <= 0) && ecx_mbxempty(context, slave, timeout))
       {
-         wkc = 0;
+         /* retry */
+         wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET3);
       }
+      if(wkc < 0 ) wkc = 0;
    }
-
+   if (mbx) ecx_dropmbx(context, mbx);  
    return wkc;
 }
 
@@ -1009,25 +1527,58 @@ int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int tim
    uint16 mbxro,mbxl,configadr;
    int wkc=0;
    int wkc2;
-   uint16 SMstat;
+   uint8 SMstat;
+   uint16 SMstatex;
    uint8 SMcontr;
    ec_mbxheadert *mbxh;
    ec_emcyt *EMp;
    ec_mbxerrort *MBXEp;
+   osal_timert timer;
+   ec_slavet *slavelist = &(context->slavelist[slave]);
 
-   configadr = context->slavelist[slave].configadr;
-   mbxl = context->slavelist[slave].mbx_rl;
-   if ((mbxl > 0) && (mbxl <= EC_MAXMBX))
+   configadr = slavelist->configadr;
+   mbxl = slavelist->mbx_rl;
+   if (slavelist->mbxhandlerstate == ECT_MBXH_CYCLIC)
+   {
+      osal_timer_start(&timer, timeout);
+      wkc = 0;
+      do
+      {
+         if (slavelist->coembxinfull == TRUE)
+         {
+            memcpy(mbx, slavelist->coembxin, mbxl);
+            ecx_dropmbx(context, (ec_mbxbuft *)slavelist->coembxin);
+            slavelist->coembxin = EC_MBXINENABLE;
+            slavelist->coembxinfull = FALSE;
+            wkc = 1;
+         }
+         else if (slavelist->soembxinfull == TRUE)
+         {
+            memcpy(mbx, slavelist->soembxin, mbxl);
+            slavelist->soembxinfull = FALSE;
+            wkc = 1;
+         }
+         else if (slavelist->foembxinfull == TRUE)
+         {
+            memcpy(mbx, slavelist->foembxin, mbxl);
+            slavelist->foembxinfull = FALSE;
+            wkc = 1;
+         }
+         if (!wkc && (timeout > EC_LOCALDELAY))
+         {
+            osal_usleep(EC_LOCALDELAY);
+         }
+      }
+      while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE));
+   }
+   else if ((mbxl > 0) && (mbxl <= EC_MAXMBX))
    {
-      osal_timert timer;
-
       osal_timer_start(&timer, timeout);
       wkc = 0;
       do /* wait for read mailbox available */
       {
          SMstat = 0;
-         wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
-         SMstat = etohs(SMstat);
+         wkc = ecx_readmbxstatus(context, slave, &SMstat);
          if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY))
          {
             osal_usleep(EC_LOCALDELAY);
@@ -1037,7 +1588,7 @@ int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int tim
 
       if ((wkc > 0) && ((SMstat & 0x08) > 0)) /* read mailbox available ? */
       {
-         mbxro = context->slavelist[slave].mbx_ro;
+         mbxro = slavelist->mbx_ro;
          mbxh = (ec_mbxheadert *)mbx;
          do
          {
@@ -1081,26 +1632,176 @@ int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int tim
             {
                if (wkc <= 0) /* read mailbox lost */
                {
-                  SMstat ^= 0x0200; /* toggle repeat request */
-                  SMstat = htoes(SMstat);
-                  wkc2 = ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
-                  SMstat = etohs(SMstat);
+                  do /* read extended mailbox status */
+                  {
+                     wkc2 = ecx_readmbxstatusex(context, slave, &SMstatex);
+                  } while ((wkc2 <= 0) && (osal_timer_is_expired(&timer) == FALSE));
+                  SMstatex ^= 0x0200; /* toggle repeat request */
+                  SMstatex = htoes(SMstatex);
+                  wkc2 = ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstatex), &SMstatex, EC_TIMEOUTRET);
+                  SMstatex = etohs(SMstatex);
+                  do /* wait for toggle ack */
+                  {
+                     wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET);
+                   } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstatex) & 0x02))) && (osal_timer_is_expired(&timer) == FALSE));
+                  do /* wait for read mailbox available */
+                  {
+                     wkc2 = ecx_readmbxstatusex(context, slave, &SMstatex);
+                     if (((SMstatex & 0x08) == 0) && (timeout > EC_LOCALDELAY))
+                     {
+                        osal_usleep(EC_LOCALDELAY);
+                     }
+                  } while (((wkc2 <= 0) || ((SMstatex & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE));
+               }
+            }
+         } while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE)); /* if WKC<=0 repeat */
+      }
+      else /* no read mailbox available */
+      {
+          wkc = 0;
+      }
+   }
+
+   return wkc;
+}
+
+/** Read OUT mailbox from slave.
+ * Supports Mailbox Link Layer with repeat requests.
+ * Mailbox is fetched from pool, caller is owner after return 
+ * and therefore should drop it back to the pool whe finished.
+ * @param[in]  context    = context struct
+ * @param[in]  slave      = Slave number
+ * @param[out] mbx        = Double pointer to mailbox data
+ * @param[in]  timeout    = Timeout in us
+ * @return Work counter (>0 is success)
+ */
+int ecx_mbxreceive2(ecx_contextt *context, uint16 slave, ec_mbxbuft **mbx, int timeout)
+{
+   uint16 mbxro,mbxl,configadr;
+   int wkc=0;
+   int wkc2;
+   uint8 SMstat;
+   uint16 SMstatex;
+   uint8 SMcontr;
+   ec_mbxbuft *mbxin;
+   ec_mbxheadert *mbxh;
+   ec_emcyt *EMp;
+   ec_mbxerrort *MBXEp;
+   osal_timert timer;
+   ec_slavet *slavelist = &(context->slavelist[slave]);
+
+   configadr = slavelist->configadr;
+   mbxl = slavelist->mbx_rl;
+   if (slavelist->mbxhandlerstate == ECT_MBXH_CYCLIC)
+   {
+      osal_timer_start(&timer, timeout);
+      wkc = 0;
+      do
+      {
+         if (slavelist->coembxinfull == TRUE)
+         {
+            *mbx = (ec_mbxbuft *)slavelist->coembxin;
+            slavelist->coembxin = EC_MBXINENABLE;
+            slavelist->coembxinfull = FALSE;
+            wkc = 1;
+         }
+         else if (slavelist->soembxinfull == TRUE)
+         {
+            *mbx = (ec_mbxbuft *)slavelist->soembxin;
+            slavelist->soembxin = EC_MBXINENABLE;
+            slavelist->soembxinfull = FALSE;
+            wkc = 1;
+         }
+         else if (slavelist->foembxinfull == TRUE)
+         {
+            *mbx = (ec_mbxbuft *)slavelist->foembxin;
+            slavelist->foembxin = EC_MBXINENABLE;
+            slavelist->foembxinfull = FALSE;
+            wkc = 1;
+         }
+         if (!wkc && (timeout > EC_LOCALDELAY))
+         {
+            osal_usleep(EC_LOCALDELAY);
+         }
+      }
+      while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE));
+   }
+   else if ((mbxl > 0) && (mbxl <= EC_MAXMBX))
+   {
+      osal_timer_start(&timer, timeout);
+      wkc = 0;
+      do /* wait for read mailbox available */
+      {
+         SMstat = 0;
+         wkc = ecx_readmbxstatus(context, slave, &SMstat);
+         if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY))
+         {
+            osal_usleep(EC_LOCALDELAY);
+         }
+      }
+      while (((wkc <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE));
+
+      if ((wkc > 0) && ((SMstat & 0x08) > 0)) /* read mailbox available ? */
+      {
+         mbxro = slavelist->mbx_ro;
+         mbxin = ecx_getmbx(context);
+         mbxh = (ec_mbxheadert *)mbxin;
+         do
+         {
+            wkc = ecx_FPRD(context->port, configadr, mbxro, mbxl, mbxin, EC_TIMEOUTRET); /* get mailbox */
+            if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x00)) /* Mailbox error response? */
+            {
+               MBXEp = (ec_mbxerrort *)mbxin;
+               ecx_mbxerror(context, slave, etohs(MBXEp->Detail));
+               ecx_dropmbx(context, mbxin);
+               mbxin = NULL;
+               wkc = 0; /* prevent emergency to cascade up, it is already handled. */
+            }
+            else if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x03)) /* CoE response? */
+            {
+               EMp = (ec_emcyt *)mbx;
+               if ((etohs(EMp->CANOpen) >> 12) == 0x01) /* Emergency request? */
+               {
+                  ecx_mbxemergencyerror(context, slave, etohs(EMp->ErrorCode), EMp->ErrorReg,
+                          EMp->bData, etohs(EMp->w1), etohs(EMp->w2));
+                  ecx_dropmbx(context, mbxin);
+                  mbxin = NULL;
+                  wkc = 0; /* prevent emergency to cascade up, it is already handled. */
+               }
+               else 
+               {
+                  *mbx = mbxin;
+                  mbxin = NULL;
+               }
+            }
+            else
+            {
+               if (wkc <= 0) /* read mailbox lost */
+               {
+                  do /* read extended mailbox status */
+                  {
+                     wkc2 = ecx_readmbxstatusex(context, slave, &SMstatex);
+                  } while ((wkc2 <= 0) && (osal_timer_is_expired(&timer) == FALSE));
+                  SMstatex ^= 0x0200; /* toggle repeat request */
+                  SMstatex = htoes(SMstatex);
+                  wkc2 = ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstatex), &SMstatex, EC_TIMEOUTRET);
+                  SMstatex = etohs(SMstatex);
                   do /* wait for toggle ack */
                   {
                      wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET);
-                   } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstat) & 0x02))) && (osal_timer_is_expired(&timer) == FALSE));
+                   } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstatex) & 0x02))) && (osal_timer_is_expired(&timer) == FALSE));
                   do /* wait for read mailbox available */
                   {
-                     wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
-                     SMstat = etohs(SMstat);
-                     if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY))
+                     wkc2 = ecx_readmbxstatusex(context, slave, &SMstatex);
+                     if (((SMstatex & 0x08) == 0) && (timeout > EC_LOCALDELAY))
                      {
                         osal_usleep(EC_LOCALDELAY);
                      }
-                  } while (((wkc2 <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE));
+                  } while (((wkc2 <= 0) || ((SMstatex & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE));
                }
             }
          } while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE)); /* if WKC<=0 repeat */
+         if(mbxin) ecx_dropmbx(context, mbxin);
       }
       else /* no read mailbox available */
       {
@@ -1723,6 +2424,8 @@ static int ecx_main_send_processdata(ecx_contextt *context, uint8 group, boolean
       first = TRUE;
    }
 
+   ecx_clearmbxstatus(context, group);
    /* For overlapping IO map use the biggest */
    if(use_overlap_io == TRUE)
    {
index afec783e015c48547b4dca7cfb111f2e2786c03a..4bfcac8961c31eb9f92efcd039948ecf623ee1ad 100644 (file)
@@ -85,6 +85,36 @@ typedef struct PACKED ec_state_status
 } ec_state_status;
 PACKED_END
 
+/** mailbox buffer array */
+typedef uint8 ec_mbxbuft[EC_MAXMBX + 1];
+
+#define EC_MBXPOOLSIZE  32
+#define EC_MBXINENABLE  (uint8 *)1
+
+typedef struct
+{
+   int         listhead, listtail, listcount;
+   int         mbxemptylist[EC_MBXPOOLSIZE];
+   osal_mutext *mbxmutex;
+   ec_mbxbuft  mbx[EC_MBXPOOLSIZE];
+} ec_mbxpoolt;
+
+#define EC_MBXQUEUESTATE_NONE       0
+#define EC_MBXQUEUESTATE_REQ        1
+#define EC_MBXQUEUESTATE_FAIL       2
+#define EC_MBXQUEUESTATE_DONE       3
+
+typedef struct
+{
+   int         listhead, listtail, listcount;
+   ec_mbxbuft  *mbx[EC_MBXPOOLSIZE];
+   int         mbxstate[EC_MBXPOOLSIZE];
+   int         mbxremove[EC_MBXPOOLSIZE];
+   int         mbxticket[EC_MBXPOOLSIZE];
+   uint16      mbxslave[EC_MBXPOOLSIZE];
+   osal_mutext *mbxmutex;
+} ec_mbxqueuet;
+
 #define ECT_MBXPROT_AOE      0x0001
 #define ECT_MBXPROT_EOE      0x0002
 #define ECT_MBXPROT_COE      0x0004
@@ -103,6 +133,10 @@ PACKED_END
 
 typedef struct ecx_context ecx_contextt;
 
+#define ECT_MBXH_NONE         0
+#define ECT_MBXH_CYCLIC       1
+#define ECT_MBXH_LOST         2
+
 /** for list of ethercat slaves detected */
 typedef struct ec_slave
 {
@@ -121,7 +155,7 @@ typedef struct ec_slave
    /** revision from EEprom */
    uint32           eep_rev;
    /** serial number from EEprom */
-   uint32           eep_sn;
+   uint32           eep_ser;
    /** Interface type */
    uint16           Itype;
    /** Device type */
@@ -132,6 +166,8 @@ typedef struct ec_slave
    uint32           Obytes;
    /** output pointer in IOmap buffer */
    uint8            *outputs;
+   /** output offset in IOmap buffer */
+   uint32           Ooffset;
    /** startbit in first output byte */
    uint8            Ostartbit;
    /** input bits */
@@ -140,6 +176,8 @@ typedef struct ec_slave
    uint32           Ibytes;
    /** input pointer in IOmap buffer */
    uint8            *inputs;
+   /** input offset in IOmap buffer */
+   uint32           Ioffset;
    /** startbit in first input byte */
    uint8            Istartbit;
    /** SM structure */
@@ -148,7 +186,7 @@ typedef struct ec_slave
    uint8            SMtype[EC_MAXSM];
    /** FMMU structure */
    ec_fmmut         FMMU[EC_MAXFMMU];
-   /** FMMU0 function */
+   /** FMMU0 function 0=unused 1=outputs 2=inputs 3=SM status*/
    uint8            FMMU0func;
    /** FMMU1 function */
    uint8            FMMU1func;
@@ -234,6 +272,50 @@ typedef struct ec_slave
    int              (*PO2SOconfig)(uint16 slave);
    /** registered configuration function PO->SO */
    int              (*PO2SOconfigx)(ecx_contextt * context, uint16 slave);
+   /** mailbox handler state, 0 = no handler, 1 = cyclic task mbx handler, 2 = slave lost */
+   int              mbxhandlerstate;
+   /** mailbox handler robust mailbox protocol state */
+   int              mbxrmpstate;
+   /** mailbox handler RMP extended mbx in state */
+   uint16           mbxinstateex;
+   /** pointer to CoE mailbox in buffer */
+   uint8            *coembxin;
+   /** CoE mailbox in flag, true = mailbox full */
+   boolean          coembxinfull;
+   /** CoE mailbox in overrun counter */
+   int              coembxoverrun;
+   /** pointer to SoE mailbox in buffer */
+   uint8            *soembxin;
+   /** SoE mailbox in flag, true = mailbox full */
+   boolean          soembxinfull;
+   /** SoE mailbox in overrun counter */
+   int              soembxoverrun;
+   /** pointer to FoE mailbox in buffer */
+   uint8            *foembxin;
+   /** FoE mailbox in flag, true = mailbox full */
+   boolean          foembxinfull;
+   /** FoE mailbox in overrun counter */
+   int              foembxoverrun;
+   /** pointer to EoE mailbox in buffer */
+   uint8            *eoembxin;
+   /** EoE mailbox in flag, true = mailbox full */
+   boolean          eoembxinfull;
+   /** EoE mailbox in overrun counter */
+   int              eoembxoverrun;
+   /** pointer to VoE mailbox in buffer */
+   uint8            *voembxin;
+   /** VoE mailbox in flag, true = mailbox full */
+   boolean          voembxinfull;
+   /** VoE mailbox in overrun counter */
+   int              voembxoverrun;
+   /** pointer to AoE mailbox in buffer */
+   uint8            *aoembxin;
+   /** AoE mailbox in flag, true = mailbox full */
+   boolean          aoembxinfull;
+   /** AoE mailbox in overrun counter */
+   int              aoembxoverrun;
+   /** pointer to out mailbox status register buffer */
+   uint8            *mbxstatus;
    /** readable name */
    char             name[EC_MAXNAME + 1];
 } ec_slavet;
@@ -273,6 +355,16 @@ typedef struct ec_group
    boolean          docheckstate;
    /** IO segmentation list. Datagrams must not break SM in two. */
    uint32           IOsegment[EC_MAXIOSEGMENTS];
+   /** pointer to out mailbox status register buffer */
+   uint8            *mbxstatus;
+   /** mailbox status register buffer length */
+   int32            mbxstatuslength;
+   /** mailbox status lookup table */
+   uint16           mbxstatuslookup[EC_MAXSLAVE];
+   /** mailbox last handled in mxbhandler */
+   uint16           lastmbxpos;
+   /** mailbox  transmit queue struct */
+   ec_mbxqueuet     mbxtxqueue;
 } ec_groupt;
 
 /** SII FMMU structure */
@@ -311,9 +403,6 @@ typedef struct ec_eepromPDO
    uint16  SMbitsize[EC_MAXSM];
 } ec_eepromPDOt;
 
-/** mailbox buffer array */
-typedef uint8 ec_mbxbuft[EC_MAXMBX + 1];
-
 /** standard ethercat mailbox header */
 PACKED_BEGIN
 typedef struct PACKED ec_mbxheader
@@ -344,6 +433,7 @@ typedef struct ec_idxstack
    void    *data[EC_MAXBUF];
    uint16  length[EC_MAXBUF];
    uint16  dcoffset[EC_MAXBUF];
+   uint8   type[EC_MAXBUF];
 } ec_idxstackT;
 
 /** ringbuf for error storage */
@@ -423,13 +513,15 @@ struct ecx_context
    ec_eepromSMt   *eepSM;
    /** internal, FMMU list from eeprom */
    ec_eepromFMMUt *eepFMMU;
+   /** internal, mailbox pool */
+   ec_mbxpoolt    *mbxpool;
    /** registered FoE hook */
    int            (*FOEhook)(uint16 slave, int packetnumber, int datasize);
    /** registered EoE hook */
    int            (*EOEhook)(ecx_contextt * context, uint16 slave, void * eoembx);
    /** flag to control legacy automatic state change or manual state change */
    int            manualstatechange;
-   /** userdata, promotes application configuration esp. in EC_VER2 with multiple 
+   /** userdata, promotes application configuration esp. in EC_VER2 with multiple
     * ec_context instances. Note: userdata memory is managed by application, not SOEM */
    void           *userdata;
 };
@@ -445,6 +537,7 @@ extern int         ec_slavecount;
 extern ec_groupt   ec_group[EC_MAXGROUP];
 extern boolean     EcatError;
 extern int64       ec_DCtime;
+extern ec_mbxpoolt ec_mbxpool;
 
 void ec_pusherror(const ec_errort *Ec);
 boolean ec_poperror(ec_errort *Ec);
@@ -506,9 +599,11 @@ uint32 ecx_siiPDO(ecx_contextt *context, uint16 slave, ec_eepromPDOt* PDO, uint8
 int ecx_readstate(ecx_contextt *context);
 int ecx_writestate(ecx_contextt *context, uint16 slave);
 uint16 ecx_statecheck(ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout);
+int ecx_mbxhandler(ecx_contextt *context, uint8 group, int limit);
 int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout);
 int ecx_mbxsend(ecx_contextt *context, uint16 slave,ec_mbxbuft *mbx, int timeout);
 int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout);
+int ecx_mbxreceive2(ecx_contextt *context, uint16 slave, ec_mbxbuft **mbx, int timeout);
 void ecx_esidump(ecx_contextt *context, uint16 slave, uint8 *esibuf);
 uint32 ecx_readeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout);
 int ecx_writeeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout);
@@ -526,6 +621,11 @@ int ecx_send_processdata(ecx_contextt *context);
 int ecx_send_overlap_processdata(ecx_contextt *context);
 int ecx_receive_processdata(ecx_contextt *context, int timeout);
 int ecx_send_processdata_group(ecx_contextt *context, uint8 group);
+ec_mbxbuft *ecx_getmbx(ecx_contextt *context);
+int ecx_dropmbx(ecx_contextt *context, ec_mbxbuft *mbx);
+int ecx_initmbxpool(ecx_contextt *context);
+int ecx_initmbxqueue(ecx_contextt *context, uint16 group);
+int ecx_slavembxcyclic(ecx_contextt *context, uint16 slave);
 
 #ifdef __cplusplus
 }
index 68c8540aca618ad8a2a159a1aa2841abc7d3b627..862f4f13c78d9f2b5c879918930b52a75d6ba88d 100644 (file)
@@ -84,16 +84,17 @@ int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elemen
    uint8 *bp;
    uint8 *mp;
    uint16 *errorcode;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
    boolean NotLast;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSoEp = (ec_SoEt *)&MbxIn;
-   SoEp = (ec_SoEt *)&MbxOut;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
+   MbxOut = ecx_getmbx(context);
+   ec_clearmbx(MbxOut);
+   SoEp = (ec_SoEt *)MbxOut;
    SoEp->MbxHeader.length = htoes(sizeof(ec_SoEt) - sizeof(ec_mbxheadert));
    SoEp->MbxHeader.address = htoes(0x0000);
    SoEp->MbxHeader.priority = 0x00;
@@ -109,20 +110,22 @@ int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elemen
    SoEp->idn = htoes(idn);
    totalsize = 0;
    bp = p;
-   mp = (uint8 *)&MbxIn + sizeof(ec_SoEt);
+   mp = (uint8 *)MbxIn + sizeof(ec_SoEt);
    NotLast = TRUE;
    /* send SoE request to slave */
-   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+   wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+   MbxOut = NULL;
    if (wkc > 0) /* succeeded to place mailbox in slave ? */
    {
       while (NotLast)
       {
-         /* clean mailboxbuffer */
-         ec_clearmbx(&MbxIn);
+         if(MbxIn) ecx_dropmbx(context, MbxIn);
+         MbxIn = NULL;
          /* read slave response */
-         wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+         wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
          if (wkc > 0) /* succeeded to read slave response ? */
          {
+            aSoEp = (ec_SoEt *)MbxIn;
             /* slave response should be SoE, ReadRes */
             if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) &&
                 (aSoEp->opCode == ECT_SOE_READRES) &&
@@ -162,7 +165,7 @@ int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elemen
                    (aSoEp->opCode == ECT_SOE_READRES) &&
                    (aSoEp->error == 1))
                {
-                  mp = (uint8 *)&MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16));
+                  mp = (uint8 *)MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16));
                   errorcode = (uint16 *)mp;
                   ecx_SoEerror(context, slave, idn, *errorcode);
                }
@@ -180,6 +183,8 @@ int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elemen
          }
       }
    }
+   if(MbxIn) ecx_dropmbx(context, MbxIn);
+   if(MbxOut) ecx_dropmbx(context, MbxOut);
    return wkc;
 }
 
@@ -206,28 +211,29 @@ int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 eleme
    uint8 *mp;
    uint8 *hp;
    uint16 *errorcode;
-   ec_mbxbuft MbxIn, MbxOut;
+   ec_mbxbuft *MbxIn, *MbxOut;
    uint8 cnt;
    boolean NotLast;
 
-   ec_clearmbx(&MbxIn);
-   /* Empty slave out mailbox if something is in. Timeout set to 0 */
-   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
-   ec_clearmbx(&MbxOut);
-   aSoEp = (ec_SoEt *)&MbxIn;
-   SoEp = (ec_SoEt *)&MbxOut;
-   SoEp->MbxHeader.address = htoes(0x0000);
-   SoEp->MbxHeader.priority = 0x00;
-   SoEp->opCode = ECT_SOE_WRITEREQ;
-   SoEp->error = 0;
-   SoEp->driveNo = driveNo;
-   SoEp->elementflags = elementflags;
+   MbxIn = NULL;
+   MbxOut = NULL;
+   /* Empty slave out mailbox if something is in. Timout set to 0 */
+   wkc = ecx_mbxreceive2(context, slave, &MbxIn, 0);
    hp = p;
-   mp = (uint8 *)&MbxOut + sizeof(ec_SoEt);
    maxdata = context->slavelist[slave].mbx_l - sizeof(ec_SoEt);
    NotLast = TRUE;
    while (NotLast)
    {
+      MbxOut = ecx_getmbx(context);
+      ec_clearmbx(MbxOut);
+      SoEp = (ec_SoEt *)MbxOut;
+      SoEp->MbxHeader.address = htoes(0x0000);
+      SoEp->MbxHeader.priority = 0x00;
+      SoEp->opCode = ECT_SOE_WRITEREQ;
+      SoEp->error = 0;
+      SoEp->driveNo = driveNo;
+      SoEp->elementflags = elementflags;
+      mp = (uint8 *)MbxOut + sizeof(ec_SoEt);
       framedatasize = psize;
       NotLast = FALSE;
       SoEp->idn = htoes(idn);
@@ -249,17 +255,19 @@ int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 eleme
       hp += framedatasize;
       psize -= framedatasize;
       /* send SoE request to slave */
-      wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
+      wkc = ecx_mbxsend(context, slave, MbxOut, EC_TIMEOUTTXM);
+      MbxOut = NULL;
       if (wkc > 0) /* succeeded to place mailbox in slave ? */
       {
          if (!NotLast || !ecx_mbxempty(context, slave, timeout))
          {
-            /* clean mailboxbuffer */
-            ec_clearmbx(&MbxIn);
+            if(MbxIn) ecx_dropmbx(context, MbxIn);
+            MbxIn = NULL;
             /* read slave response */
-            wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
+            wkc = ecx_mbxreceive2(context, slave, &MbxIn, timeout);
             if (wkc > 0) /* succeeded to read slave response ? */
             {
+               aSoEp = (ec_SoEt *)MbxIn;
                NotLast = FALSE;
                /* slave response should be SoE, WriteRes */
                if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) &&
@@ -277,7 +285,7 @@ int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 eleme
                       (aSoEp->opCode == ECT_SOE_READRES) &&
                       (aSoEp->error == 1))
                   {
-                     mp = (uint8 *)&MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16));
+                     mp = (uint8 *)MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16));
                      errorcode = (uint16 *)mp;
                      ecx_SoEerror(context, slave, idn, *errorcode);
                   }
@@ -295,6 +303,8 @@ int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 eleme
          }
       }
    }
+   if(MbxIn) ecx_dropmbx(context, MbxIn);
+   if(MbxOut) ecx_dropmbx(context, MbxOut);
    return wkc;
 }
 
index 83a90af31c1af6249c74a29fc2d0f8adf45300b3..724987c282e19c7d9fbc477efe040acb6a8693f3 100644 (file)
@@ -302,7 +302,7 @@ enum
    ECT_SII_MANUF       = 0x0008,
    ECT_SII_ID          = 0x000a,
    ECT_SII_REV         = 0x000c,
-   ECT_SII_S         = 0x000e,
+   ECT_SII_SER         = 0x000e,
    ECT_SII_BOOTRXMBX   = 0x0014,
    ECT_SII_BOOTTXMBX   = 0x0016,
    ECT_SII_MBXSIZE     = 0x0019,
diff --git a/test/linux/coetest/CMakeLists.txt b/test/linux/coetest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6cf5757
--- /dev/null
@@ -0,0 +1,3 @@
+set(SOURCES coetest.c)
+add_executable(coetest ${SOURCES})
+target_link_libraries(coetest soem)
\ No newline at end of file
diff --git a/test/linux/coetest/coetest.c b/test/linux/coetest/coetest.c
new file mode 100644 (file)
index 0000000..ec2431c
--- /dev/null
@@ -0,0 +1,265 @@
+/** \file
+ * \brief CoE example code for Simple Open EtherCAT master
+ *
+ * Usage : coetest [ifname1]
+ * ifname is NIC interface, f.e. eth0
+ *
+ * (c)Arthur Ketels 2010 - 2024
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pthread.h>
+
+#include "ethercat.h"
+
+boolean forceByteAlignment = FALSE;
+#define EC_TIMEOUTMON 500
+
+char IOmap[4096];
+OSAL_THREAD_HANDLE threadrt, thread1;
+int expectedWKC;
+int mappingdone, dorun, inOP, dowkccheck;
+int adapterisbound, conf_io_size, currentgroup; 
+int64_t cycletime = 1000000;
+#define NSEC_PER_MSEC 1000000
+#define NSEC_PER_SEC 1000000000
+
+/* add ns to timespec */
+void add_timespec(struct timespec *ts, int64 addtime)
+{
+   int64 sec, nsec;
+
+   nsec = addtime % NSEC_PER_SEC;
+   sec = (addtime - nsec) / NSEC_PER_SEC;
+   ts->tv_sec += sec;
+   ts->tv_nsec += nsec;
+   if ( ts->tv_nsec >= NSEC_PER_SEC )
+   {
+      nsec = ts->tv_nsec % NSEC_PER_SEC;
+      ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;
+      ts->tv_nsec = nsec;
+   }
+}
+
+static float pgain = 0.01f;
+static float igain = 0.00002f;
+/* set linux sync point 500us later than DC sync, just as example */
+static int64 syncoffset = 500000;
+int64 timeerror;
+
+/* PI calculation to get linux time synced to DC time */
+void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime)
+{
+   static int64 integral = 0;
+   int64 delta;
+   delta = (reftime - syncoffset) % cycletime;
+   if(delta> (cycletime / 2)) { delta = delta - cycletime; }
+   timeerror = -delta;
+   integral += timeerror;
+   *offsettime = (timeerror * pgain) + (integral * igain);
+}
+
+/* RT EtherCAT thread */
+OSAL_THREAD_FUNC_RT ecatthread(void)
+{
+   struct timespec   ts, tleft;
+   int ht, wkc;
+   static int64_t toff = 0;
+
+   dorun = 0;
+   while(!mappingdone) { osal_usleep(100); } 
+   clock_gettime(CLOCK_MONOTONIC, &ts);
+   ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
+   ts.tv_nsec = ht * 1000000;
+   ecx_send_processdata(&ecx_context);
+   while(1)
+   {
+      /* calculate next cycle start */
+      add_timespec(&ts, cycletime + toff);
+      /* wait to cycle start */
+      clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
+      if (dorun > 0)
+      {
+        wkc = ecx_receive_processdata(&ecx_context, EC_TIMEOUTRET);
+        if(wkc != expectedWKC) dowkccheck++; else dowkccheck = 0;
+        if (ec_slave[0].hasdc && (wkc > 0))
+        {
+        /* calulate toff to get linux time and DC synced */
+        ec_sync(ec_DCtime, cycletime, &toff);
+        }
+        ecx_mbxhandler(&ecx_context, 0, 4);
+        ecx_send_processdata(&ecx_context);
+      }
+   }
+}
+
+OSAL_THREAD_FUNC ecatcheck( void)
+{
+    int slave;
+
+    while(1)
+    {
+        if( inOP && ((dowkccheck > 2) || ec_group[currentgroup].docheckstate))
+        {
+            /* one ore more slaves are not responding */
+            ec_group[currentgroup].docheckstate = FALSE;
+            ec_readstate();
+            for (slave = 1; slave <= ec_slavecount; slave++)
+            {
+               if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL))
+               {
+                  ec_group[currentgroup].docheckstate = TRUE;
+                  if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
+                  {
+                     printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
+                     ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK);
+                     ec_writestate(slave);
+                  }
+                  else if(ec_slave[slave].state == EC_STATE_SAFE_OP)
+                  {
+                     printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
+                     ec_slave[slave].state = EC_STATE_OPERATIONAL;
+                     ec_writestate(slave);
+                  }
+                  else if(ec_slave[slave].state > EC_STATE_NONE)
+                  {
+                     if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
+                     {
+                        ec_slave[slave].islost = FALSE;
+                        printf("MESSAGE : slave %d reconfigured\n",slave);
+                     }
+                  }
+                  else if(!ec_slave[slave].islost)
+                  {
+                     /* re-check state */
+                     ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);
+                     if (ec_slave[slave].state == EC_STATE_NONE)
+                     {
+                        ec_slave[slave].islost = TRUE;
+                        printf("ERROR : slave %d lost\n",slave);
+                     }
+                  }
+               }
+               if (ec_slave[slave].islost)
+               {
+                  if(ec_slave[slave].state <= EC_STATE_INIT)
+                  {
+                     if (ec_recover_slave(slave, EC_TIMEOUTMON))
+                     {
+                        ec_slave[slave].islost = FALSE;
+                        printf("MESSAGE : slave %d recovered\n",slave);
+                     }
+                  }
+                  else
+                  {
+                     ec_slave[slave].islost = FALSE;
+                     printf("MESSAGE : slave %d found. State %2.2x\n",slave, ec_slave[slave].state);
+                  }
+               }
+            }
+            if(!ec_group[currentgroup].docheckstate)
+               printf("OK : all slaves resumed OPERATIONAL.\n");
+            dowkccheck = 0;   
+        }
+        osal_usleep(10000);
+    }
+}
+
+void ethercatstartup(char *ifname)
+{
+    printf("EtherCAT Startup\n");
+    int rv = ecx_init(&ecx_context, ifname);
+    if(rv)
+    {
+        adapterisbound = 1;
+        ecx_config_init(&ecx_context, FALSE);
+        if(ec_slavecount > 0)
+        {
+            if(forceByteAlignment)
+                conf_io_size = ecx_config_map_group_aligned(&ecx_context, &IOmap, 0);
+            else
+                conf_io_size = ecx_config_map_group(&ecx_context, &IOmap, 0);
+            expectedWKC = (ecx_context.grouplist[0].outputsWKC * 2) + ecx_context.grouplist[0].inputsWKC;
+            mappingdone = 1;
+            ecx_configdc(&ecx_context);
+            int sdoslave = -1;
+            for(int si = 1 ; si <= *ecx_context.slavecount ; si++ )
+            {
+                ec_slavet *slave = &ecx_context.slavelist[si];
+                printf("Slave %d name:%s man:%8.8x id:%8.8x rev:%d ser:%d\n", si, slave->name, slave->eep_man, slave->eep_id, slave->eep_rev, slave->eep_ser);
+                if(slave->CoEdetails > 0)
+                {
+                    ecx_slavembxcyclic(&ecx_context, si);
+                    sdoslave = si;
+                    printf(" Slave added to cyclic mailbox handler\n");
+                } 
+            }
+            dorun = 1;
+            osal_usleep(1000000);
+            ecx_context.slavelist[0].state = EC_STATE_OPERATIONAL;
+            ecx_writestate(&ecx_context, 0);
+            ecx_statecheck(&ecx_context, 0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE);
+            inOP = 1;
+            printf("EtherCAT OP\n");
+            uint32_t aval = 0;
+            int avals = sizeof(aval);
+            for(int i = 0 ; i < 100 ; i++)
+            {
+                printf("Cycle %d timeerror %ld\n", i, timeerror);
+                if(sdoslave >0)
+                {
+                    aval = 0;
+                    int rval = ecx_SDOread(&ecx_context, sdoslave, 0x1018, 0x02, FALSE, &avals, &aval, EC_TIMEOUTRXM);
+                    printf(" Slave %d Rval %d Prodcode %8.8x\n", sdoslave, rval , aval);
+                }
+                osal_usleep(100000);
+            }
+            inOP = 0;
+            printf("EtherCAT to safe-OP\n");
+            ecx_context.slavelist[0].state = EC_STATE_SAFE_OP;
+            ecx_writestate(&ecx_context, 0);
+            ecx_statecheck(&ecx_context, 0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE);
+            printf("EtherCAT to INIT\n");
+            ecx_context.slavelist[0].state = EC_STATE_INIT;
+            ecx_writestate(&ecx_context, 0);
+            ecx_statecheck(&ecx_context, 0, EC_STATE_INIT, EC_TIMEOUTSTATE);
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+   printf("SOEM (Simple Open EtherCAT Master)\nCoEtest\n");
+
+   if (argc > 1)
+   {
+      /* create thread to handle slave error handling in OP */
+      osal_thread_create_rt(&threadrt, 128000, &ecatthread, NULL);
+      /* create thread to handle slave error handling in OP */
+      osal_thread_create(&thread1, 128000, &ecatcheck, NULL);
+      /* start cyclic part */
+      ethercatstartup(argv[1]);
+   }
+   else
+   {
+      ec_adaptert * adapter = NULL;
+      printf("Usage: coetest ifname1\nifname = eth0 for example\n");
+
+      printf ("\nAvailable adapters:\n");
+      adapter = ec_find_adapters ();
+      while (adapter != NULL)
+      {
+         printf ("    - %s  (%s)\n", adapter->name, adapter->desc);
+         adapter = adapter->next;
+      }
+      ec_free_adapters(adapter);
+   }
+
+   printf("End program\n");
+   return (0);
+}
index f74757c5494967a443ab643a734ffc59b0b9ad65..acc5e15dc5c498584fd7de3a3eeb4e6ae8733dc9 100644 (file)
@@ -183,11 +183,12 @@ OSAL_THREAD_FUNC ecatcheck( void *ptr )
                   {
                      printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
                      ec_slave[slave].state = EC_STATE_OPERATIONAL;
+                     if(ec_slave[slave].mbxhandlerstate == ECT_MBXH_LOST) ec_slave[slave].mbxhandlerstate = ECT_MBXH_CYCLIC;
                      ec_writestate(slave);
                   }
                   else if(ec_slave[slave].state > EC_STATE_NONE)
                   {
-                     if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
+                     if (ec_reconfig_slave(slave, EC_TIMEOUTMON) >= EC_STATE_PRE_OP)
                      {
                         ec_slave[slave].islost = FALSE;
                         printf("MESSAGE : slave %d reconfigured\n",slave);
@@ -200,13 +201,20 @@ OSAL_THREAD_FUNC ecatcheck( void *ptr )
                      if (ec_slave[slave].state == EC_STATE_NONE)
                      {
                         ec_slave[slave].islost = TRUE;
+                        ec_slave[slave].mbxhandlerstate = ECT_MBXH_LOST;
+                        /* zero input data for this slave */
+                        if(ec_slave[slave].Ibytes)
+                        {
+                           memset(ec_slave[slave].inputs, 0x00, ec_slave[slave].Ibytes);
+                           printf("zero inputs %p %d\n\r", ec_slave[slave].inputs, ec_slave[slave].Ibytes);
+                        }
                         printf("ERROR : slave %d lost\n",slave);
                      }
                   }
                }
                if (ec_slave[slave].islost)
                {
-                  if(ec_slave[slave].state == EC_STATE_NONE)
+                  if(ec_slave[slave].state <= EC_STATE_INIT)
                   {
                      if (ec_recover_slave(slave, EC_TIMEOUTMON))
                      {
index e81ba3b5d392510a2a7f94c01b4fd0c7a8a40f82..8556d7a2dccf4ca14b58b2b7a87883d475772152 100644 (file)
@@ -529,7 +529,7 @@ void si_sdo(int cnt)
         printf(" CoE Object Description found, %d entries.\n",ODlist.Entries);
         for( i = 0 ; i < ODlist.Entries ; i++)
         {
-            uint8_t max_sub;
+            uint16_t max_sub;
             char name[128] = { 0 };
 
             ec_readODdescription(i, &ODlist);