AB&T / SOEM

Dependents:   EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nicdrv.cpp Source File

nicdrv.cpp

Go to the documentation of this file.
00001 /*
00002  * Licensed under the GNU General Public License version 2 with exceptions. See
00003  * LICENSE file in the project root for full license information
00004  */
00005 
00006 /** \file
00007  * \brief
00008  * EtherCAT RAW socket driver.
00009  *
00010  * Low level interface functions to send and receive EtherCAT packets.
00011  * EtherCAT has the property that packets are only send by the master,
00012  * and the send packets always return in the receive buffer.
00013  * There can be multiple packets "on the wire" before they return.
00014  * To combine the received packets with the original send packets a buffer
00015  * system is installed. The identifier is put in the index item of the
00016  * EtherCAT header. The index is stored and compared when a frame is received.
00017  * If there is a match the packet can be combined with the transmit packet
00018  * and returned to the higher level function.
00019  *
00020  * The socket layer can exhibit a reversal in the packet order (rare).
00021  * If the Tx order is A-B-C the return order could be A-C-B. The indexed buffer
00022  * will reorder the packets automatically.
00023  *
00024  * The "redundant" option will configure two sockets and two NIC interfaces.
00025  * Slaves are connected to both interfaces, one on the IN port and one on the
00026  * OUT port. Packets are send via both interfaces. Any one of the connections
00027  * (also an interconnect) can be removed and the slaves are still serviced with
00028  * packets. The software layer will detect the possible failure modes and
00029  * compensate. If needed the packets from interface A are resent through interface B.
00030  * This layer is fully transparent for the higher layers.
00031  */
00032 
00033 
00034 #include "mbed.h"
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 
00039 #include "osal.h"
00040 #include "oshw.h"
00041 
00042 #ifndef MAX
00043 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
00044 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
00045 #endif
00046 
00047 
00048 
00049 /** Redundancy modes */
00050 enum
00051 {
00052    /** No redundancy, single NIC mode */
00053    ECT_RED_NONE,
00054    /** Double redundant NIC connection */
00055    ECT_RED_DOUBLE
00056 };
00057 
00058 /** Primary source MAC address used for EtherCAT.
00059  * This address is not the MAC address used from the NIC.
00060  * EtherCAT does not care about MAC addressing, but it is used here to
00061  * differentiate the route the packet traverses through the EtherCAT
00062  * segment. This is needed to find out the packet flow in redundant
00063  * configurations. */
00064 const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 };
00065 /** Secondary source MAC address used for EtherCAT. */
00066 const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 };
00067 
00068 /** second MAC word is used for identification */
00069 #define RX_PRIM priMAC[1]
00070 /** second MAC word is used for identification */
00071 #define RX_SEC secMAC[1]
00072 
00073 
00074 
00075 
00076 //******************************************************************************
00077 // driver used:
00078 // \mbed-os-5.5.7\targets\TARGET_STM\TARGET_STM32F7\device\stm32f7xx_hal_eth.c
00079 //******************************************************************************
00080 
00081 
00082 GPIO_InitTypeDef GPIO_InitStructure;
00083 
00084 
00085 
00086 ETH_HandleTypeDef  hEth;           // ethernet interface handle structure
00087 
00088 ETH_DMADescTypeDef DMATxDescTab[ETH_TXBUFNB];        // dma tx descriptors 
00089 ETH_DMADescTypeDef DMARxDescTab[ETH_RXBUFNB];        // dma rx descriptors
00090 
00091 uint8_t DmaTxBuff[ETH_TXBUFNB][ETH_MAX_PACKET_SIZE]; // dma tx buffers    
00092 uint8_t DmaRxBuff[ETH_RXBUFNB][ETH_MAX_PACKET_SIZE]; // dma rx buffers      
00093 
00094 
00095 
00096 HAL_StatusTypeDef HalStatus;       // response from Hal functions
00097 
00098 
00099 //------------------------------------------------------------------------------
00100 
00101 void EthInit()
00102 {
00103                                         // HAL status codes
00104                                         //    
00105                                         // HAL_OK       = 0x00U,
00106                                         // HAL_ERROR    = 0x01U,
00107                                         // HAL_BUSY     = 0x02U,
00108                                         // HAL_TIMEOUT  = 0x03U
00109     
00110            
00111     uint8_t MACAddr[6] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};  // mac address    
00112 
00113     hEth.State = HAL_ETH_STATE_RESET;   // don't know if it is useful !!!  
00114     
00115     hEth.Instance = ETH;                               
00116     hEth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
00117     hEth.Init.Speed = ETH_SPEED_100M;
00118     hEth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
00119     hEth.Init.PhyAddress = 0x00;
00120     hEth.Init.MACAddr = &MACAddr[0];    
00121     hEth.Init.RxMode = ETH_RXPOLLING_MODE;
00122     hEth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
00123     hEth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
00124         
00125     HalStatus = HAL_ETH_Init(&hEth);
00126     NVIC_DisableIRQ(ETH_IRQn);         // we don't use interrupt
00127     if (HalStatus != HAL_OK)
00128     {
00129         printf ("HAL_ETH_Init err %d\n", HalStatus);    
00130     }      
00131      
00132     HalStatus = HAL_ETH_DMATxDescListInit(&hEth, &DMATxDescTab[0], &DmaTxBuff[0][0], ETH_TXBUFNB);
00133     if (HalStatus != HAL_OK)
00134     {
00135        printf ("HAL_ETH_DMATxDescListInit err %d\n", HalStatus);   
00136     }    
00137                                                    
00138     HalStatus = HAL_ETH_DMARxDescListInit(&hEth, &DMARxDescTab[0], &DmaRxBuff[0][0], ETH_RXBUFNB);
00139     if (HalStatus != HAL_OK)
00140     {    
00141         printf ("HAL_ETH_DMARxDescListInit err %d\n", HalStatus);     
00142     }
00143     
00144     HalStatus = HAL_ETH_Start(&hEth);
00145     if (HalStatus != HAL_OK)    
00146     {
00147         printf ("HAL_ETH_Start err %d\n", HalStatus);  
00148     }   
00149 }   
00150 
00151 //------------------------------------------------------------------------------
00152 
00153 int EthWrPacket (uint8_t* pBuff, uint16_t Len)
00154 {
00155     uint8_t* pDmaBuff;          
00156             
00157     if ((hEth.TxDesc->Status & ETH_DMATXDESC_OWN) == (uint32_t)RESET) 
00158     
00159     {
00160         pDmaBuff = (uint8_t*)(hEth.TxDesc->Buffer1Addr);
00161         
00162         memcpy (pDmaBuff, pBuff, Len);    
00163    
00164         HalStatus = HAL_ETH_TransmitFrame(&hEth, Len);
00165         if (HalStatus != HAL_OK)
00166         {
00167             printf ("HAL_ETH_TransmitFrame err %d\n", HalStatus);       
00168             return NULL;
00169         }        
00170           
00171         return Len;
00172     }        
00173     
00174     else
00175     {
00176         return NULL;
00177     }
00178 }    
00179 
00180 //------------------------------------------------------------------------------
00181 
00182 int EthRdPacket(uint8_t* pBuff)
00183 {
00184     int Len;
00185     uint8_t* pDmaBuff;
00186     
00187     HalStatus = HAL_ETH_GetReceivedFrame(&hEth);            // check if a packet has been received
00188     
00189     if (HalStatus == HAL_OK)                                // packet received
00190     {
00191         Len = hEth.RxFrameInfos.length;                     // packet lenght        
00192         pDmaBuff = (uint8_t*)hEth.RxFrameInfos.buffer;      // DMA buffer pointer
00193                
00194         memcpy (pBuff, pDmaBuff, Len);                      // read the data 
00195     
00196                                                             // release the descriptor                                                           
00197         hEth.RxFrameInfos.FSRxDesc->Status |= ETH_DMARXDESC_OWN;
00198         hEth.RxFrameInfos.SegCount = 0;                     // reset segment count
00199                  
00200         return Len;                                         // return the number of bytes read
00201     }   
00202      
00203     else
00204     {   
00205         return NULL;                                        // no packet received
00206     }
00207 }   
00208 
00209 //*****************************************************************************
00210 //              
00211 //*****************************************************************************
00212 
00213 
00214 
00215 static void ecx_clear_rxbufstat(int *rxbufstat)
00216 {
00217    int i;
00218    for(i = 0; i < EC_MAXBUF; i++)
00219    {
00220       rxbufstat[i] = EC_BUF_EMPTY;
00221    }
00222 }
00223 
00224 /** Basic setup to connect NIC to socket.
00225  * @param[in] port        = port context struct
00226  * @param[in] ifname      = Name of NIC device, f.e. "eth0"
00227  * @param[in] secondary   = if >0 then use secondary stack instead of primary
00228  * @return >0 if succeeded
00229  */
00230 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
00231 {
00232    int i;
00233    int rVal;
00234    int *psock;
00235 
00236     EthInit();     
00237         
00238    if (rVal != 0)
00239       return 0;
00240 
00241    if (secondary)
00242    {
00243       /* secondary port struct available? */
00244       if (port->redport)
00245       {
00246          /* when using secondary socket it is automatically a redundant setup */
00247          psock = &(port->redport->sockhandle);
00248          *psock = -1;
00249          port->redstate                   = ECT_RED_DOUBLE;
00250          port->redport->stack.sock        = &(port->redport->sockhandle);
00251          port->redport->stack.txbuf       = &(port->txbuf);
00252          port->redport->stack.txbuflength = &(port->txbuflength);
00253          port->redport->stack.tempbuf     = &(port->redport->tempinbuf);
00254          port->redport->stack.rxbuf       = &(port->redport->rxbuf);
00255          port->redport->stack.rxbufstat   = &(port->redport->rxbufstat);
00256          port->redport->stack.rxsa        = &(port->redport->rxsa);
00257          ecx_clear_rxbufstat(&(port->redport->rxbufstat[0]));
00258       }
00259       else
00260       {
00261          /* fail */
00262          return 0;
00263       }
00264    }
00265    else
00266    {
00267       port->sockhandle        = -1;
00268       port->lastidx           = 0;
00269       port->redstate          = ECT_RED_NONE;
00270       port->stack.sock        = &(port->sockhandle);
00271       port->stack.txbuf       = &(port->txbuf);
00272       port->stack.txbuflength = &(port->txbuflength);
00273       port->stack.tempbuf     = &(port->tempinbuf);
00274       port->stack.rxbuf       = &(port->rxbuf);
00275       port->stack.rxbufstat   = &(port->rxbufstat);
00276       port->stack.rxsa        = &(port->rxsa);
00277       ecx_clear_rxbufstat(&(port->rxbufstat[0]));
00278       psock = &(port->sockhandle);
00279    }
00280 
00281    /* setup ethernet headers in tx buffers so we don't have to repeat it */
00282    for (i = 0; i < EC_MAXBUF; i++)
00283    {
00284       ec_setupheader(&(port->txbuf[i]));
00285       port->rxbufstat[i] = EC_BUF_EMPTY;
00286    }
00287    ec_setupheader(&(port->txbuf2));
00288 
00289    return 1;
00290 }
00291 
00292 /** Close sockets used
00293  * @param[in] port        = port context struct
00294  * @return 0
00295  */
00296 int ecx_closenic(ecx_portt *port)
00297 {
00298    if (port->sockhandle >= 0)
00299    {
00300       close(port->sockhandle);
00301    }
00302    if ((port->redport) && (port->redport->sockhandle >= 0))
00303    {
00304       close(port->redport->sockhandle);
00305    }
00306    return 0;
00307 }
00308 
00309 /** Fill buffer with ethernet header structure.
00310  * Destination MAC is always broadcast.
00311  * Ethertype is always ETH_P_ECAT.
00312  * @param[out] p = buffer
00313  */
00314  
00315 void ec_setupheader(void *p)  
00316 {   
00317    ec_etherheadert *bp;                   
00318      
00319    bp = (ec_etherheadert*)p;
00320  
00321  
00322    bp->da0 = oshw_htons(0xffff);
00323    bp->da1 = oshw_htons(0xffff);
00324    bp->da2 = oshw_htons(0xffff);
00325    bp->sa0 = oshw_htons(priMAC[0]);
00326    bp->sa1 = oshw_htons(priMAC[1]);
00327    bp->sa2 = oshw_htons(priMAC[2]);
00328    bp->etype = oshw_htons(ETH_P_ECAT);   
00329 }
00330 
00331 /** Get new frame identifier index and allocate corresponding rx buffer.
00332  * @param[in] port        = port context struct
00333  * @return new index.
00334  */
00335 int ecx_getindex(ecx_portt *port)
00336 {
00337    int idx;
00338    int cnt;
00339 
00340  //  mtx_lock (port->getindex_mutex);               //******//
00341 
00342    idx = port->lastidx + 1;
00343    /* index can't be larger than buffer array */
00344    if (idx >= EC_MAXBUF)
00345    {
00346       idx = 0;
00347    }
00348    cnt = 0;
00349    /* try to find unused index */
00350    while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF))
00351    {
00352       idx++;
00353       cnt++;
00354       if (idx >= EC_MAXBUF)
00355       {
00356          idx = 0;
00357       }
00358    }
00359    port->rxbufstat[idx] = EC_BUF_ALLOC;
00360    if (port->redstate != ECT_RED_NONE)
00361    {
00362       port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
00363    }
00364    port->lastidx = idx;
00365 
00366  //  mtx_unlock (port->getindex_mutex);             //******//
00367 
00368    return idx;
00369 }
00370 
00371 /** Set rx buffer status.
00372  * @param[in] port     = port context struct
00373  * @param[in] idx      = index in buffer array
00374  * @param[in] bufstat  = status to set
00375  */
00376 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
00377 {
00378    port->rxbufstat[idx] = bufstat;
00379    if (port->redstate != ECT_RED_NONE)
00380    {
00381       port->redport->rxbufstat[idx] = bufstat;
00382    }
00383 }
00384 
00385 /** Transmit buffer over socket (non blocking).
00386  * @param[in] port        = port context struct
00387  * @param[in] idx         = index in tx buffer array
00388  * @param[in] stacknumber  = 0=Primary 1=Secondary stack
00389  * @return socket send result
00390  */
00391 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
00392 {
00393    int lp, rval;
00394    ec_stackT *stack;
00395 
00396    if (!stacknumber)
00397    {
00398       stack = &(port->stack);
00399    }
00400    else
00401    {
00402       stack = &(port->redport->stack);
00403    }
00404    lp = (*stack->txbuflength)[idx];
00405    (*stack->rxbufstat)[idx] = EC_BUF_TX;
00406  
00407    rval = EthWrPacket ((*stack->txbuf)[idx], lp); 
00408  
00409    return rval;
00410 }
00411 
00412 /** Transmit buffer over socket (non blocking).
00413  * @param[in] port        = port context struct
00414  * @param[in] idx = index in tx buffer array
00415  * @return socket send result
00416  */
00417 int ecx_outframe_red(ecx_portt *port, int idx)
00418 {
00419    ec_comt *datagramP;
00420    ec_etherheadert *ehp;
00421    int rval;
00422 
00423    ehp = (ec_etherheadert *)&(port->txbuf[idx]);
00424    /* rewrite MAC source address 1 to primary */
00425    ehp->sa1 = oshw_htons(priMAC[1]);
00426    /* transmit over primary socket*/
00427    rval = ecx_outframe(port, idx, 0);
00428    if (port->redstate != ECT_RED_NONE)
00429    {
00430  //     mtx_lock (port->tx_mutex);                              //******//
00431       ehp = (ec_etherheadert *)&(port->txbuf2);
00432       /* use dummy frame for secondary socket transmit (BRD) */
00433       datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
00434       /* write index to frame */
00435       datagramP->index = idx;
00436       /* rewrite MAC source address 1 to secondary */
00437       ehp->sa1 = oshw_htons(secMAC[1]);
00438       /* transmit over secondary socket */
00439       //send(sockhandle2, &ec_txbuf2, ec_txbuflength2 , 0);
00440       // OBS! redundant not ACTIVE for BFIN, just added to compile
00441  
00442       port->redport->rxbufstat[idx] = EC_BUF_TX;
00443       
00444       EthWrPacket((uint8_t*)&(port->txbuf2), port->txbuflength2);
00445         
00446  //     mtx_unlock (port->tx_mutex);                                  //******//      
00447    }                                                                    
00448 
00449    return rval;
00450 }
00451 
00452 /** Non blocking read of socket. Put frame in temporary buffer.
00453  * @param[in] port        = port context struct
00454  * @param[in] stacknumber = 0=primary 1=secondary stack
00455  * @return >0 if frame is available and read
00456  */
00457 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
00458 {
00459    int lp, bytesrx;
00460    ec_stackT *stack;
00461 
00462    if (!stacknumber)
00463    {
00464       stack = &(port->stack);
00465    }
00466    else
00467    {
00468       stack = &(port->redport->stack);
00469    }
00470    lp = sizeof(port->tempinbuf);
00471  
00472    bytesrx = EthRdPacket(*stack->tempbuf);
00473   
00474   
00475    port->tempinbufs = bytesrx;
00476 
00477    return (bytesrx > 0);
00478 }
00479 
00480 /** Non blocking receive frame function. Uses RX buffer and index to combine
00481  * read frame with transmitted frame. To compensate for received frames that
00482  * are out-of-order all frames are stored in their respective indexed buffer.
00483  * If a frame was placed in the buffer previously, the function retrieves it
00484  * from that buffer index without calling ec_recvpkt. If the requested index
00485  * is not already in the buffer it calls ec_recvpkt to fetch it. There are
00486  * three options now, 1 no frame read, so exit. 2 frame read but other
00487  * than requested index, store in buffer and exit. 3 frame read with matching
00488  * index, store in buffer, set completed flag in buffer status and exit.
00489  *
00490  * @param[in] port        = port context struct
00491  * @param[in] idx         = requested index of frame
00492  * @param[in] stacknumber = 0=primary 1=secondary stack
00493  * @return Workcounter if a frame is found with corresponding index, otherwise
00494  * EC_NOFRAME or EC_OTHERFRAME.
00495  */
00496 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
00497 {
00498    uint16  l;
00499    int     rval;
00500    uint8   idxf;
00501    ec_etherheadert *ehp;
00502    ec_comt *ecp;
00503    ec_stackT *stack;
00504    ec_bufT *rxbuf;
00505 
00506    if (!stacknumber)
00507    {
00508       stack = &(port->stack);
00509    }
00510    else
00511    {
00512       stack = &(port->redport->stack);
00513    }
00514    rval = EC_NOFRAME;
00515    rxbuf = &(*stack->rxbuf)[idx];
00516    /* check if requested index is already in buffer ? */
00517    if ((idx < EC_MAXBUF) && (   (*stack->rxbufstat)[idx] == EC_BUF_RCVD))
00518    {
00519       l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
00520       /* return WKC */
00521       rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
00522       /* mark as completed */
00523       (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
00524    }
00525    else
00526    {
00527    //   mtx_lock (port->rx_mutex);                                  //******//
00528       /* non blocking call to retrieve frame from socket */
00529       if (ecx_recvpkt(port, stacknumber))
00530       {
00531          rval = EC_OTHERFRAME;
00532          ehp =(ec_etherheadert*)(stack->tempbuf);
00533          /* check if it is an EtherCAT frame */
00534          if (ehp->etype == oshw_htons(ETH_P_ECAT))
00535          {
00536             ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
00537             l = etohs(ecp->elength) & 0x0fff;
00538             idxf = ecp->index;
00539             /* found index equals requested index ? */
00540             if (idxf == idx)
00541             {
00542                /* yes, put it in the buffer array (strip ethernet header) */
00543                memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
00544                /* return WKC */
00545                rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
00546                /* mark as completed */
00547                (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
00548                /* store MAC source word 1 for redundant routing info */
00549                (*stack->rxsa)[idx] = oshw_ntohs(ehp->sa1);
00550             }
00551             else
00552             {
00553                /* check if index exist and someone is waiting for it */
00554                if (idxf < EC_MAXBUF && (*stack->rxbufstat)[idxf] == EC_BUF_TX)
00555                {
00556                   rxbuf = &(*stack->rxbuf)[idxf];
00557                   /* put it in the buffer array (strip ethernet header) */
00558                   memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
00559                   /* mark as received */
00560                   (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
00561                   (*stack->rxsa)[idxf] = oshw_ntohs(ehp->sa1);
00562                }
00563                else
00564                {
00565                   /* strange things happened */
00566                }
00567             }
00568          }
00569       }
00570    //   mtx_unlock (port->rx_mutex);            //******//
00571 
00572    }
00573 
00574    /* WKC if matching frame found */
00575    return rval;
00576 }
00577 
00578 
00579 /** Blocking redundant receive frame function. If redundant mode is not active then
00580  * it skips the secondary stack and redundancy functions. In redundant mode it waits
00581  * for both (primary and secondary) frames to come in. The result goes in an decision
00582  * tree that decides, depending on the route of the packet and its possible missing arrival,
00583  * how to reroute the original packet to get the data in an other try.
00584  *
00585  * @param[in] port        = port context struct
00586  * @param[in] idx = requested index of frame
00587  * @param[in] timer = absolute timeout time
00588  * @return Workcounter if a frame is found with corresponding index, otherwise
00589  * EC_NOFRAME.
00590  */
00591 static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert timer)
00592 {
00593    int wkc  = EC_NOFRAME;
00594    int wkc2 = EC_NOFRAME;
00595    int primrx, secrx;
00596 
00597    /* if not in redundant mode then always assume secondary is OK */
00598    if (port->redstate == ECT_RED_NONE)
00599    {
00600       wkc2 = 0;
00601    }
00602    do
00603    {
00604       /* only read frame if not already in */
00605       if (wkc <= EC_NOFRAME)
00606       {
00607          wkc  = ecx_inframe(port, idx, 0);
00608       }
00609       /* only try secondary if in redundant mode */
00610       if (port->redstate != ECT_RED_NONE)
00611       {
00612          /* only read frame if not already in */
00613          if (wkc2 <= EC_NOFRAME)
00614             wkc2 = ecx_inframe(port, idx, 1);
00615       }
00616    /* wait for both frames to arrive or timeout */                       
00617     } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && (osal_timer_is_expired(&timer) == FALSE));
00618       
00619    /* only do redundant functions when in redundant mode */
00620    if (port->redstate != ECT_RED_NONE)
00621    {
00622       /* primrx if the received MAC source on primary socket */
00623       primrx = 0;
00624       if (wkc > EC_NOFRAME)
00625       {
00626          primrx = port->rxsa[idx];
00627       }
00628       /* secrx if the received MAC source on psecondary socket */
00629       secrx = 0;
00630       if (wkc2 > EC_NOFRAME)
00631       {
00632          secrx = port->redport->rxsa[idx];
00633       }
00634       /* primary socket got secondary frame and secondary socket got primary frame */
00635       /* normal situation in redundant mode */
00636       if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) )
00637       {
00638          /* copy secondary buffer to primary */
00639          memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
00640          wkc = wkc2;
00641       }
00642       /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
00643       /* we need to resend TX packet */
00644       if ( ((primrx == 0) && (secrx == RX_SEC)) ||
00645            ((primrx == RX_PRIM) && (secrx == RX_SEC)) )
00646       {
00647          osal_timert read_timer;
00648 
00649          /* If both primary and secondary have partial connection retransmit the primary received
00650           * frame over the secondary socket. The result from the secondary received frame is a combined
00651           * frame that traversed all slaves in standard order. */
00652          if ( (primrx == RX_PRIM) && (secrx == RX_SEC) )
00653          {
00654             /* copy primary rx to tx buffer */
00655             memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
00656          }
00657          
00658          //osal_timer_start(&read_timer, EC_TIMEOUTRET);
00659   
00660                         osal_timer_start(&read_timer, 500);       
00661          
00662          /* resend secondary tx */
00663          ecx_outframe(port, idx, 1);
00664          do
00665          {
00666             /* retrieve frame */
00667             wkc2 = ecx_inframe(port, idx, 1);
00668          } while ((wkc2 <= EC_NOFRAME) && (osal_timer_is_expired(&read_timer) == FALSE));
00669          if (wkc2 > EC_NOFRAME)
00670          {
00671             /* copy secondary result to primary rx buffer */
00672             memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
00673             wkc = wkc2;
00674          }
00675       }
00676    }
00677 
00678    /* return WKC or EC_NOFRAME */
00679    return wkc;
00680 }
00681 
00682 /** Blocking receive frame function. Calls ec_waitinframe_red().
00683  * @param[in] port        = port context struct
00684  * @param[in] idx       = requested index of frame
00685  * @param[in] timeout   = timeout in us
00686  * @return Workcounter if a frame is found with corresponding index, otherwise
00687  * EC_NOFRAME.
00688  */
00689 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
00690 {
00691    int wkc;
00692    
00693    osal_timert timer;
00694    osal_timer_start (&timer, timeout);
00695    wkc = ecx_waitinframe_red(port, idx, timer);
00696 
00697    return wkc;
00698 }
00699 
00700 /** Blocking send and receive frame function. Used for non processdata frames.
00701  * A datagram is build into a frame and transmitted via this function. It waits
00702  * for an answer and returns the workcounter. The function retries if time is
00703  * left and the result is WKC=0 or no frame received.
00704  *
00705  * The function calls ec_outframe_red() and ec_waitinframe_red().
00706  *
00707  * @param[in] port        = port context struct
00708  * @param[in] idx      = index of frame
00709  * @param[in] timeout  = timeout in us
00710  * @return Workcounter or EC_NOFRAME
00711  */
00712 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
00713 {
00714    int wkc = EC_NOFRAME;
00715    
00716    osal_timert timer;
00717    osal_timer_start(&timer, timeout);   
00718    
00719    do
00720    {
00721       osal_timert read_timer;
00722 
00723       /* tx frame on primary and if in redundant mode a dummy on secondary */
00724       ecx_outframe_red(port, idx);
00725       osal_timer_start(&read_timer, MIN(timeout, EC_TIMEOUTRET)); 
00726       
00727       /* get frame from primary or if in redundant mode possibly from secondary */
00728       wkc = ecx_waitinframe_red(port, idx, read_timer);
00729    /* wait for answer with WKC>0 or otherwise retry until timeout */
00730    } while ((wkc <= EC_NOFRAME) && (osal_timer_is_expired(&timer) == FALSE));
00731 
00732    return wkc;
00733 }
00734 
00735 
00736 #ifdef EC_VER1
00737 int ec_setupnic(const char *ifname, int secondary)
00738 {
00739    return ecx_setupnic(&ecx_port, ifname, secondary);
00740 }
00741 
00742 int ec_closenic(void)
00743 {
00744    return ecx_closenic(&ecx_port);
00745 }
00746 
00747 int ec_getindex(void)
00748 {
00749    return ecx_getindex(&ecx_port);
00750 }
00751 
00752 void ec_setbufstat(int idx, int bufstat)
00753 {
00754    ecx_setbufstat(&ecx_port, idx, bufstat);
00755 }
00756 
00757 int ec_outframe(int idx, int stacknumber)
00758 {
00759    return ecx_outframe(&ecx_port, idx, stacknumber);
00760 }
00761 
00762 int ec_outframe_red(int idx)
00763 {
00764    return ecx_outframe_red(&ecx_port, idx);
00765 }
00766 
00767 int ec_inframe(int idx, int stacknumber)
00768 {
00769    return ecx_inframe(&ecx_port, idx, stacknumber);
00770 }
00771 
00772 int ec_waitinframe(int idx, int timeout)
00773 {
00774    return ecx_waitinframe(&ecx_port, idx, timeout);
00775 }
00776 
00777 int ec_srconfirm(int idx, int timeout)
00778 {
00779    return ecx_srconfirm(&ecx_port, idx, timeout);
00780 }
00781 #endif
00782