1 /***********************************************************************************************************************
2 * DISCLAIMER
3 * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. No
4 * other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
5 * applicable laws, including copyright laws.
6 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
7 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
8 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. TO THE MAXIMUM
9 * EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES
10 * SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS
11 * SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
12 * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of
13 * this software. By using this software, you agree to the additional terms and conditions found by accessing the
14 * following link:
15 * http://www.renesas.com/disclaimer
16 *
17 * Copyright (C) 2020 Renesas Electronics Corporation. All rights reserved.
18 ***********************************************************************************************************************/
19 
20 /***********************************************************************************************************************
21 * File Name    : NetworkInterface.c
22 * Device(s)    : RX
23 * Description  : Interfaces FreeRTOS TCP/IP stack to RX Ethernet driver.
24 ***********************************************************************************************************************/
25 
26 /***********************************************************************************************************************
27 * History : DD.MM.YYYY Version  Description
28 *         : 07.03.2018 0.1     Development
29 ***********************************************************************************************************************/
30 
31 /***********************************************************************************************************************
32 *  Includes   <System Includes> , "Project Includes"
33 ***********************************************************************************************************************/
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 /* FreeRTOS includes. */
40 #include "FreeRTOS.h"
41 #include "task.h"
42 #include "FreeRTOS_IP.h"
43 #include "FreeRTOS_IP_Private.h"
44 /*#include "FreeRTOS_DNS.h" */
45 #include "NetworkBufferManagement.h"
46 #include "NetworkInterface.h"
47 
48 #include "r_ether_rx_if.h"
49 #include "r_pinset.h"
50 
51 /***********************************************************************************************************************
52  * Macro definitions
53  **********************************************************************************************************************/
54 #define ETHER_BUFSIZE_MIN    60
55 
56 #if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M ) || defined( BSP_MCU_RX72M )
57     #if ETHER_CFG_MODE_SEL == 0
58         #define R_ETHER_PinSet_CHANNEL_0()    R_ETHER_PinSet_ETHERC0_MII()
59     #elif ETHER_CFG_MODE_SEL == 1
60         #define R_ETHER_PinSet_CHANNEL_0()    R_ETHER_PinSet_ETHERC0_RMII()
61     #endif
62 #elif defined( BSP_MCU_RX63N )
63     #if ETHER_CFG_MODE_SEL == 0
64         #define R_ETHER_PinSet_CHANNEL_0()    R_ETHER_PinSet_ETHERC_MII()
65     #elif ETHER_CFG_MODE_SEL == 1
66         #define R_ETHER_PinSet_CHANNEL_0()    R_ETHER_PinSet_ETHERC_RMII()
67     #endif
68 #endif /* if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M ) */
69 
70 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
71 
72 /* Check if the LinkSStatus in the PHY is still high after 2 seconds of not
73  * receiving packets. */
74     #define PHY_LS_HIGH_CHECK_TIME_MS    2000
75 #endif
76 
77 #ifndef PHY_LS_LOW_CHECK_TIME_MS
78     /* Check if the LinkSStatus in the PHY is still low every second. */
79     #define PHY_LS_LOW_CHECK_TIME_MS    1000
80 #endif
81 
82 /***********************************************************************************************************************
83  * Private global variables and functions
84  **********************************************************************************************************************/
85 typedef enum
86 {
87     eMACInit,   /* Must initialise MAC. */
88     eMACPass,   /* Initialisation was successful. */
89     eMACFailed, /* Initialisation failed. */
90 } eMAC_INIT_STATUS_TYPE;
91 
92 static TaskHandle_t ether_receive_check_task_handle = 0;
93 static TaskHandle_t xTaskToNotify = NULL;
94 static BaseType_t xPHYLinkStatus;
95 static BaseType_t xReportedStatus;
96 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
97 
98 static int16_t SendData( uint8_t * pucBuffer,
99                          size_t length );
100 static int InitializeNetwork( void );
101 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters );
102 static void clear_all_ether_rx_discriptors( uint32_t event );
103 
104 int32_t callback_ether_regist( void );
105 void EINT_Trig_isr( void * );
106 void get_random_number( uint8_t * data,
107                         uint32_t len );
108 
109 void prvLinkStatusChange( BaseType_t xStatus );
110 
111 /***********************************************************************************************************************
112  * Function Name: xNetworkInterfaceInitialise ()
113  * Description  : Initialization of Ethernet driver.
114  * Arguments    : none
115  * Return Value : pdPASS, pdFAIL
116  **********************************************************************************************************************/
xNetworkInterfaceInitialise(void)117 BaseType_t xNetworkInterfaceInitialise( void )
118 {
119     BaseType_t xReturn;
120 
121     if( xMacInitStatus == eMACInit )
122     {
123         /*
124          * Perform the hardware specific network initialization here using the Ethernet driver library to initialize the
125          * Ethernet hardware, initialize DMA descriptors, and perform a PHY auto-negotiation to obtain a network link.
126          *
127          * InitialiseNetwork() uses Ethernet peripheral driver library function, and returns 0 if the initialization fails.
128          */
129         if( InitializeNetwork() == pdFALSE )
130         {
131             xMacInitStatus = eMACFailed;
132         }
133         else
134         {
135             /* Indicate that the MAC initialisation succeeded. */
136             xMacInitStatus = eMACPass;
137         }
138 
139         FreeRTOS_printf( ( "InitializeNetwork returns %s\n", ( xMacInitStatus == eMACPass ) ? "OK" : " Fail" ) );
140     }
141 
142     if( xMacInitStatus == eMACPass )
143     {
144         xReturn = xPHYLinkStatus;
145     }
146     else
147     {
148         xReturn = pdFAIL;
149     }
150 
151     FreeRTOS_printf( ( "xNetworkInterfaceInitialise returns %d\n", xReturn ) );
152 
153     return xReturn;
154 } /* End of function xNetworkInterfaceInitialise() */
155 
156 
157 /***********************************************************************************************************************
158  * Function Name: xNetworkInterfaceOutput ()
159  * Description  : Simple network output interface.
160  * Arguments    : pxDescriptor, xReleaseAfterSend
161  * Return Value : pdTRUE, pdFALSE
162  **********************************************************************************************************************/
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t xReleaseAfterSend)163 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
164                                     BaseType_t xReleaseAfterSend )
165 {
166     BaseType_t xReturn = pdFALSE;
167 
168     /* Simple network interfaces (as opposed to more efficient zero copy network
169      * interfaces) just use Ethernet peripheral driver library functions to copy
170      * data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer.
171      * This example assumes SendData() is a peripheral driver library function that
172      * takes a pointer to the start of the data to be sent and the length of the
173      * data to be sent as two separate parameters.  The start of the data is located
174      * by pxDescriptor->pucEthernetBuffer.  The length of the data is located
175      * by pxDescriptor->xDataLength. */
176     if( xPHYLinkStatus != 0 )
177     {
178         if( SendData( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ) >= 0 )
179         {
180             xReturn = pdTRUE;
181             /* Call the standard trace macro to log the send event. */
182             iptraceNETWORK_INTERFACE_TRANSMIT();
183         }
184     }
185     else
186     {
187         /* As the PHY Link Status is low, it makes no sense trying to deliver a packet. */
188     }
189 
190     if( xReleaseAfterSend != pdFALSE )
191     {
192         /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
193          * buffer.  The Ethernet buffer is therefore no longer needed, and must be
194          * freed for re-use. */
195         vReleaseNetworkBufferAndDescriptor( pxDescriptor );
196     }
197 
198     return xReturn;
199 } /* End of function xNetworkInterfaceOutput() */
200 
201 
202 /***********************************************************************************************************************
203  * Function Name: prvEMACDeferredInterruptHandlerTask ()
204  * Description  : The deferred interrupt handler is a standard RTOS task.
205  * Arguments    : pvParameters
206  * Return Value : none
207  **********************************************************************************************************************/
prvEMACDeferredInterruptHandlerTask(void * pvParameters)208 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters )
209 {
210     NetworkBufferDescriptor_t * pxBufferDescriptor;
211     int32_t xBytesReceived = 0;
212 
213     /* Avoid compiler warning about unreferenced parameter. */
214     ( void ) pvParameters;
215 
216     /* Used to indicate that xSendEventStructToIPTask() is being called because
217      * of an Ethernet receive event. */
218     IPStackEvent_t xRxEvent;
219 
220     uint8_t * buffer_pointer;
221 
222     /* Some variables related to monitoring the PHY. */
223     TimeOut_t xPhyTime;
224     TickType_t xPhyRemTime;
225     const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
226 
227     vTaskSetTimeOutState( &xPhyTime );
228     xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
229 
230     FreeRTOS_printf( ( "Deferred Interrupt Handler Task started\n" ) );
231     xTaskToNotify = ether_receive_check_task_handle;
232 
233     for( ; ; )
234     {
235         #if ( ipconfigHAS_PRINTF != 0 )
236             {
237                 /* Call a function that monitors resources: the amount of free network
238                  * buffers and the amount of free space on the heap.  See FreeRTOS_IP.c
239                  * for more detailed comments. */
240                 vPrintResourceStats();
241             }
242         #endif /* ( ipconfigHAS_PRINTF != 0 ) */
243 
244         /* Wait for the Ethernet MAC interrupt to indicate that another packet
245          * has been received.  */
246         if( xBytesReceived <= 0 )
247         {
248             ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
249         }
250 
251         /* See how much data was received.  */
252         xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer );
253 
254         if( xBytesReceived < 0 )
255         {
256             /* This is an error. Logged. */
257             FreeRTOS_printf( ( "R_ETHER_Read_ZC2: rc = %d\n", xBytesReceived ) );
258         }
259         else if( xBytesReceived > 0 )
260         {
261             /* Allocate a network buffer descriptor that points to a buffer
262              * large enough to hold the received frame.  As this is the simple
263              * rather than efficient example the received data will just be copied
264              * into this buffer. */
265             pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( ( size_t ) xBytesReceived, 0 );
266 
267             if( pxBufferDescriptor != NULL )
268             {
269                 /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet
270                  * buffer large enough to hold the received data.  Copy the
271                  * received data into pcNetworkBuffer->pucEthernetBuffer.  Here it
272                  * is assumed ReceiveData() is a peripheral driver function that
273                  * copies the received data into a buffer passed in as the function's
274                  * parameter.  Remember! While is is a simple robust technique -
275                  * it is not efficient.  An example that uses a zero copy technique
276                  * is provided further down this page. */
277                 memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer_pointer, ( size_t ) xBytesReceived );
278                 /*ReceiveData( pxBufferDescriptor->pucEthernetBuffer ); */
279 
280                 /* Set the actual packet length, in case a larger buffer was returned. */
281                 pxBufferDescriptor->xDataLength = ( size_t ) xBytesReceived;
282 
283                 R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 );
284 
285                 /* See if the data contained in the received Ethernet frame needs
286                 * to be processed.  NOTE! It is preferable to do this in
287                 * the interrupt service routine itself, which would remove the need
288                 * to unblock this task for packets that don't need processing. */
289                 if( eConsiderFrameForProcessing( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer )
290                 {
291                     /* The event about to be sent to the TCP/IP is an Rx event. */
292                     xRxEvent.eEventType = eNetworkRxEvent;
293 
294                     /* pvData is used to point to the network buffer descriptor that
295                      * now references the received data. */
296                     xRxEvent.pvData = ( void * ) pxBufferDescriptor;
297 
298                     /* Send the data to the TCP/IP stack. */
299                     if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
300                     {
301                         /* The buffer could not be sent to the IP task so the buffer must be released. */
302                         vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
303 
304                         /* Make a call to the standard trace macro to log the occurrence. */
305                         iptraceETHERNET_RX_EVENT_LOST();
306                         clear_all_ether_rx_discriptors( 0 );
307                     }
308                     else
309                     {
310                         /* The message was successfully sent to the TCP/IP stack.
311                         * Call the standard trace macro to log the occurrence. */
312                         iptraceNETWORK_INTERFACE_RECEIVE();
313                         R_BSP_NOP();
314                     }
315                 }
316                 else
317                 {
318                     /* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */
319                     vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
320                 }
321             }
322             else
323             {
324                 /* The event was lost because a network buffer was not available.
325                  * Call the standard trace macro to log the occurrence. */
326                 iptraceETHERNET_RX_EVENT_LOST();
327                 clear_all_ether_rx_discriptors( 1 );
328                 FreeRTOS_printf( ( "R_ETHER_Read_ZC2: Cleared descriptors\n" ) );
329             }
330         }
331 
332         if( xBytesReceived > 0 )
333         {
334             /* A packet was received. No need to check for the PHY status now,
335              * but set a timer to check it later on. */
336             vTaskSetTimeOutState( &xPhyTime );
337             xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
338 
339             /* Indicate that the Link Status is high, so that
340              * xNetworkInterfaceOutput() can send packets. */
341             if( xPHYLinkStatus == 0 )
342             {
343                 xPHYLinkStatus = 1;
344                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS assume %d\n", xPHYLinkStatus ) );
345             }
346         }
347         else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) )
348         {
349             R_ETHER_LinkProcess( ETHER_CHANNEL_0 );
350 
351             if( xPHYLinkStatus != xReportedStatus )
352             {
353                 xPHYLinkStatus = xReportedStatus;
354                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", xPHYLinkStatus ) );
355             }
356 
357             vTaskSetTimeOutState( &xPhyTime );
358 
359             if( xPHYLinkStatus != 0 )
360             {
361                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
362             }
363             else
364             {
365                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
366             }
367         }
368     }
369 } /* End of function prvEMACDeferredInterruptHandlerTask() */
370 
371 
372 /***********************************************************************************************************************
373  * Function Name: vNetworkInterfaceAllocateRAMToBuffers ()
374  * Description  : .
375  * Arguments    : pxNetworkBuffers
376  * Return Value : none
377  **********************************************************************************************************************/
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])378 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
379 {
380     uint32_t ul;
381     uint8_t * buffer_address;
382 
383     R_BSP_SECTION_OPERATORS_INIT( B_ETHERNET_BUFFERS_1 )
384 
385     buffer_address = R_BSP_SECTOP( B_ETHERNET_BUFFERS_1 );
386 
387     for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
388     {
389         pxNetworkBuffers[ ul ].pucEthernetBuffer = ( buffer_address + ( ETHER_CFG_BUFSIZE * ul ) );
390     }
391 } /* End of function vNetworkInterfaceAllocateRAMToBuffers() */
392 
393 
394 /***********************************************************************************************************************
395  * Function Name: prvLinkStatusChange ()
396  * Description  : Function will be called when the Link Status of the phy has changed ( see ether_callback.c )
397  * Arguments    : xStatus : true when statyus has become high
398  * Return Value : void
399  **********************************************************************************************************************/
prvLinkStatusChange(BaseType_t xStatus)400 void prvLinkStatusChange( BaseType_t xStatus )
401 {
402     if( xReportedStatus != xStatus )
403     {
404         FreeRTOS_printf( ( "prvLinkStatusChange( %d )\n", xStatus ) );
405         xReportedStatus = xStatus;
406     }
407 }
408 
409 /***********************************************************************************************************************
410  * Function Name: InitializeNetwork ()
411  * Description  :
412  * Arguments    : none
413  * Return Value : pdTRUE, pdFALSE
414  **********************************************************************************************************************/
InitializeNetwork(void)415 static int InitializeNetwork( void )
416 {
417     ether_return_t eth_ret;
418     BaseType_t return_code = pdFALSE;
419     ether_param_t param;
420     uint8_t myethaddr[ 6 ] =
421     {
422         configMAC_ADDR0,
423         configMAC_ADDR1,
424         configMAC_ADDR2,
425         configMAC_ADDR3,
426         configMAC_ADDR4,
427         configMAC_ADDR5
428     }; /*XXX Fix me */
429 
430     R_ETHER_PinSet_CHANNEL_0();
431     R_ETHER_Initial();
432     callback_ether_regist();
433 
434     param.channel = ETHER_CHANNEL_0;
435     eth_ret = R_ETHER_Control( CONTROL_POWER_ON, param ); /* PHY mode settings, module stop cancellation */
436 
437     if( ETHER_SUCCESS != eth_ret )
438     {
439         return pdFALSE;
440     }
441 
442     eth_ret = R_ETHER_Open_ZC2( ETHER_CHANNEL_0, myethaddr, ETHER_FLAG_OFF );
443 
444     if( ETHER_SUCCESS != eth_ret )
445     {
446         return pdFALSE;
447     }
448 
449     return_code = xTaskCreate( prvEMACDeferredInterruptHandlerTask,
450                                "ETHER_RECEIVE_CHECK_TASK",
451                                512u,
452                                0,
453                                configMAX_PRIORITIES - 1,
454                                &ether_receive_check_task_handle );
455 
456     if( pdFALSE == return_code )
457     {
458         return pdFALSE;
459     }
460 
461     return pdTRUE;
462 } /* End of function InitializeNetwork() */
463 
464 
465 /***********************************************************************************************************************
466  * Function Name: SendData ()
467  * Description  :
468  * Arguments    : pucBuffer, length
469  * Return Value : 0 success, negative fail
470  **********************************************************************************************************************/
SendData(uint8_t * pucBuffer,size_t length)471 static int16_t SendData( uint8_t * pucBuffer,
472                          size_t length ) /*TODO complete stub function */
473 {
474     ether_return_t ret;
475     uint8_t * pwrite_buffer;
476     uint16_t write_buf_size;
477 
478     /* (1) Retrieve the transmit buffer location controlled by the  descriptor. */
479     ret = R_ETHER_Write_ZC2_GetBuf( ETHER_CHANNEL_0, ( void ** ) &pwrite_buffer, &write_buf_size );
480 
481     if( ETHER_SUCCESS == ret )
482     {
483         if( write_buf_size >= length )
484         {
485             memcpy( pwrite_buffer, pucBuffer, length );
486         }
487 
488         if( length < ETHER_BUFSIZE_MIN )                                             /*under minimum*/
489         {
490             memset( ( pwrite_buffer + length ), 0, ( ETHER_BUFSIZE_MIN - length ) ); /*padding*/
491             length = ETHER_BUFSIZE_MIN;                                              /*resize*/
492         }
493 
494         ret = R_ETHER_Write_ZC2_SetBuf( ETHER_CHANNEL_0, ( uint16_t ) length );
495         ret = R_ETHER_CheckWrite( ETHER_CHANNEL_0 );
496     }
497 
498     if( ETHER_SUCCESS != ret )
499     {
500         return -5; /* XXX return meaningful value */
501     }
502     else
503     {
504         return 0;
505     }
506 } /* End of function SendData() */
507 
508 
509 /***********************************************************************************************************************
510 * Function Name: EINT_Trig_isr
511 * Description  : Standard frame received interrupt handler
512 * Arguments    : ectrl - EDMAC and ETHERC control structure
513 * Return Value : None
514 * Note         : This callback function is executed when EINT0 interrupt occurred.
515 ***********************************************************************************************************************/
EINT_Trig_isr(void * ectrl)516 void EINT_Trig_isr( void * ectrl )
517 {
518     ether_cb_arg_t * pdecode;
519     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
520 
521     pdecode = ( ether_cb_arg_t * ) ectrl;
522 
523     if( pdecode->status_eesr & 0x00040000 ) /* EDMAC FR (Frame Receive Event) interrupt */
524     {
525         if( xTaskToNotify != NULL )
526         {
527             vTaskNotifyGiveFromISR( ether_receive_check_task_handle, &xHigherPriorityTaskWoken );
528         }
529 
530         /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
531          * should be performed to ensure the interrupt returns directly to the highest
532          * priority task.  The macro used for this purpose is dependent on the port in
533          * use and may be called portEND_SWITCHING_ISR(). */
534         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
535         /*TODO complete interrupt handler for other events. */
536     }
537 } /* End of function EINT_Trig_isr() */
538 
539 
clear_all_ether_rx_discriptors(uint32_t event)540 static void clear_all_ether_rx_discriptors( uint32_t event )
541 {
542     int32_t xBytesReceived;
543     uint8_t * buffer_pointer;
544 
545     /* Avoid compiler warning about unreferenced parameter. */
546     ( void ) event;
547 
548     while( 1 )
549     {
550         /* See how much data was received.  */
551         xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer );
552 
553         if( 0 > xBytesReceived )
554         {
555             /* This is an error. Ignored. */
556         }
557         else if( 0 < xBytesReceived )
558         {
559             R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 );
560             iptraceETHERNET_RX_EVENT_LOST();
561         }
562         else
563         {
564             break;
565         }
566     }
567 }
568 
569 /***********************************************************************************************************************
570  * End of file "NetworkInterface.c"
571  **********************************************************************************************************************/
572