/** Blocking send and recieve frame function. Used for non processdata frames. * A datagram is build into a frame and transmitted via this function. It waits * for an answer and returns the workcounter. The function retries if time is * left and the result is WKC=0 or no frame received. * * The function calls ec_outframe_red() and ec_waitinframe_red(). * * @param[in] port = port context struct * @param[in] idx = index of frame * @param[in] timeout = timeout in us * @return Workcounter or EC_NOFRAME */ int ecx_srconfirm(ecx_portt *port, int idx, int timeout) { int wkc = EC_NOFRAME; osal_timert timer; osal_timer_start(&timer, timeout); do { osal_timert read_timer; /* tx frame on primary and if in redundant mode a dummy on secondary */ ecx_outframe_red(port, idx); osal_timer_start(&read_timer, MIN(timeout, EC_TIMEOUTRET)); /* get frame from primary or if in redundant mode possibly from secondary */ wkc = ecx_waitinframe_red(port, idx, read_timer); /* wait for answer with WKC>0 or otherwise retry until timeout */ } while ((wkc <= EC_NOFRAME) && (osal_timer_is_expired(&timer) == FALSE)); /* if nothing received, clear buffer index status so it can be used again */ if (wkc <= EC_NOFRAME) { ecx_setbufstat(port, idx, EC_BUF_EMPTY); } return wkc; }
/** Blocking send and recieve frame function. Used for non processdata frames. * A datagram is build into a frame and transmitted via this function. It waits * for an answer and returns the workcounter. The function retries if time is * left and the result is WKC=0 or no frame received. * * The function calls ec_outframe_red() and ec_waitinframe_red(). * * @param[in] port = port context struct * @param[in] idx = index of frame * @param[in] timeout = timeout in us * @return Workcounter or EC_NOFRAME */ int ecx_srconfirm(ecx_portt *port, int idx, int timeout) { int wkc = EC_NOFRAME; osal_timert timer1, timer2; osal_timer_start (&timer1, timeout); do { /* tx frame on primary and if in redundant mode a dummy on secondary */ ecx_outframe_red(port, idx); if (timeout < EC_TIMEOUTRET) { osal_timer_start (&timer2, timeout); } else { /* normally use partial timout for rx */ osal_timer_start (&timer2, EC_TIMEOUTRET); } /* get frame from primary or if in redundant mode possibly from secondary */ wkc = ecx_waitinframe_red(port, idx, &timer2); /* wait for answer with WKC>=0 or otherwise retry until timeout */ } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1)); /* if nothing received, clear buffer index status so it can be used again */ if (wkc <= EC_NOFRAME) { ecx_setbufstat(port, idx, EC_BUF_EMPTY); } return wkc; }
/** Blocking send and receive frame function. Used for non processdata frames. * A datagram is build into a frame and transmitted via this function. It waits * for an answer and returns the workcounter. The function retries if time is * left and the result is WKC=0 or no frame received. * * The function calls ec_outframe_red() and ec_waitinframe_red(). * * @param[in] port = port context struct * @param[in] idx = index of frame * @param[in] timeout = timeout in us * @return Workcounter or EC_NOFRAME */ int ecx_srconfirm(ecx_portt *port, int idx, int timeout) { int wkc = EC_NOFRAME; osal_timert timer; osal_timer_start(&timer, timeout); do { osal_timert read_timer; /* tx frame on primary and if in redundant mode a dummy on secondary */ ecx_outframe_red(port, idx); osal_timer_start(&read_timer, MIN(timeout, EC_TIMEOUTRET)); /* get frame from primary or if in redundant mode possibly from secondary */ wkc = ecx_waitinframe_red(port, idx, read_timer); /* wait for answer with WKC>0 or otherwise retry until timeout */ } while ((wkc <= EC_NOFRAME) && (osal_timer_is_expired(&timer) == FALSE)); return wkc; }
/** Blocking redundant receive frame function. If redundant mode is not active then * it skips the secondary stack and redundancy functions. In redundant mode it waits * for both (primary and secondary) frames to come in. The result goes in an decision * tree that decides, depending on the route of the packet and its possible missing arrival, * how to reroute the original packet to get the data in an other try. * * @param[in] port = port context struct * @param[in] idx = requested index of frame * @param[in] timer = absolute timeout time * @return Workcounter if a frame is found with corresponding index, otherwise * EC_NOFRAME. */ static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert timer) { int wkc = EC_NOFRAME; int wkc2 = EC_NOFRAME; int primrx, secrx; /* if not in redundant mode then always assume secondary is OK */ if (port->redstate == ECT_RED_NONE) { wkc2 = 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) { /* 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) == FALSE)); /* only do redundant functions when in redundant mode */ if (port->redstate != ECT_RED_NONE) { /* primrx if the reveived MAC source on primary socket */ primrx = 0; if (wkc > EC_NOFRAME) { primrx = port->rxsa[idx]; } /* secrx if the reveived MAC source on psecondary socket */ secrx = 0; if (wkc2 > EC_NOFRAME) { secrx = port->redport->rxsa[idx]; } /* primary socket got secondary frame and secondary socket got primary frame */ /* normal situation in redundant mode */ if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) ) { /* copy secondary buffer to primary */ memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); wkc = wkc2; } /* primary socket got nothing or primary frame, and secondary socket got secondary frame */ /* we need to resend TX packet */ if ( ((primrx == 0) && (secrx == RX_SEC)) || ((primrx == RX_PRIM) && (secrx == RX_SEC)) ) { osal_timert read_timer; /* If both primary and secondary have partial connection retransmit the primary received * frame over the secondary socket. The result from the secondary received frame is a combined * frame that traversed all slaves in standard order. */ if ( (primrx == RX_PRIM) && (secrx == RX_SEC) ) { /* copy primary rx to tx buffer */ memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); } osal_timer_start(&read_timer, EC_TIMEOUTRET); /* resend secondary tx */ ecx_outframe(port, idx, 1); do { /* retrieve frame */ wkc2 = ecx_inframe(port, idx, 1); } while ((wkc2 <= EC_NOFRAME) && (osal_timer_is_expired(&read_timer) == FALSE)); if (wkc2 > EC_NOFRAME) { /* copy secondary result to primary rx buffer */ memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); wkc = wkc2; } } } /* return WKC or EC_NOFRAME */ return wkc; }