Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB
nicdrv.cpp
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
Generated on Tue Jul 12 2022 18:21:13 by
