]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c
6b926c8119141b8cbf3658884f137921bea87923
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / M487 / NetworkInterface.c
1 /*
2 FreeRTOS+TCP V2.0.11
3 Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy of
6 this software and associated documentation files (the "Software"), to deal in
7 the Software without restriction, including without limitation the rights to
8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 the Software, and to permit persons to whom the Software is furnished to do so,
10 subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22  http://aws.amazon.com/freertos
23  http://www.FreeRTOS.org
24 */
25
26 /* FreeRTOS includes. */
27 #include "FreeRTOS.h"
28 #include "list.h"
29 #include "queue.h"
30 #include "semphr.h"
31 #include "task.h"
32
33 /* FreeRTOS+TCP includes. */
34 #include "FreeRTOS_IP.h"
35 #include "FreeRTOS_Sockets.h"
36 #include "FreeRTOS_IP_Private.h"
37 #include "NetworkBufferManagement.h"
38 #include "NetworkInterface.h"
39
40
41 #include "m480_eth.h"
42
43 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
44 driver will filter incoming packets and only pass the stack those packets it
45 considers need processing. */
46 #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
47 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
48 #else
49 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
50 #endif
51
52 /* Default the size of the stack used by the EMAC deferred handler task to twice
53 the size of the stack used by the idle task - but allow this to be overridden in
54 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
55 #ifndef configEMAC_TASK_STACK_SIZE
56     #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
57 #endif
58
59
60 static SemaphoreHandle_t xTXMutex = NULL;
61
62 /* The handle of the task that processes Rx packets.  The handle is required so
63 the task can be notified when new packets arrive. */
64 static TaskHandle_t xRxHanderTask = NULL;
65 static TimerHandle_t xPhyHandlerTask = NULL;
66 /*
67  * A task that processes received frames.
68  */
69 static void prvEMACHandlerTask( void *pvParameters );
70 static void prvPhyTmrCallback( TimerHandle_t xTimer );
71
72 /* The size of each buffer when BufferAllocation_1 is used:
73 http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
74
75 #define niBUFFER_1_PACKET_SIZE        1536
76 #ifdef __ICCARM__
77 #pragma data_alignment=4
78 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ]
79 #else
80 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ((aligned(4)));
81 #endif
82
83 BaseType_t xNetworkInterfaceInitialise( void )
84 {
85     uint8_t hwaddr[6];
86     BaseType_t xReturn = pdPASS;
87
88     /* Init ETH */
89     numaker_mac_address(hwaddr);
90     FreeRTOS_UpdateMACAddress(hwaddr);
91     FreeRTOS_printf( ("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[0], hwaddr[1],hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5]) );
92     /* Enable clock & set EMAC configuration         */
93     /* Enable MAC and DMA transmission and reception */
94     if( numaker_eth_init(hwaddr) < 0)
95     {
96         xReturn = pdFAIL;
97     } else {
98         xReturn = pdPASS;
99         /* Guard against the task being created more than once and the
100         descriptors being initialized more than once. */
101         /* Timer task to monitor PHY Link status */
102         if( xPhyHandlerTask == NULL )
103         {
104             xPhyHandlerTask = xTimerCreate( "TimerPhy",  pdMS_TO_TICKS( 1000 ), pdTRUE, 0, prvPhyTmrCallback );
105             configASSERT(xPhyHandlerTask);
106             xReturn = xTimerStart( xPhyHandlerTask, 0 ) ;
107             configASSERT( xReturn );
108         }
109         /* Rx task */
110         if( xRxHanderTask == NULL )
111         {
112             xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );
113             configASSERT( xReturn );
114         }
115         
116         if( xTXMutex == NULL )
117         {
118             xTXMutex = xSemaphoreCreateMutex();
119             configASSERT( xTXMutex );
120         }        
121     }
122
123         NVIC_SetPriority( EMAC_RX_IRQn, configMAC_INTERRUPT_PRIORITY );
124         NVIC_SetPriority( EMAC_TX_IRQn, configMAC_INTERRUPT_PRIORITY );
125
126         numaker_eth_enable_interrupts();
127
128         FreeRTOS_printf( ("ETH-RX priority:%d\n",NVIC_GetPriority( EMAC_RX_IRQn)) );
129
130     return xReturn;
131 }
132
133 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t xReleaseAfterSend )
134 {
135     uint8_t *buffer=NULL;
136 //    FreeRTOS_printf(("<-- dataLength=%d\n",pxDescriptor->xDataLength));
137     if( pxDescriptor->xDataLength >= PACKET_BUFFER_SIZE )
138     {
139         FreeRTOS_printf(("TX buffer length %d over %d\n", pxDescriptor->xDataLength, PACKET_BUFFER_SIZE));
140         return pdFALSE;
141     }
142     
143     buffer = numaker_eth_get_tx_buf();
144     if( buffer == NULL )
145     {
146         NU_DEBUGF(("Eth TX slots are busy\n"));
147         return pdFALSE;
148     }    
149     
150     /* Get exclusive access */
151     xSemaphoreTake(xTXMutex, portMAX_DELAY);
152     NU_DEBUGF(("%s ... buffer=0x%x\r\n",__FUNCTION__, buffer));   
153     //SendData: pt = pxDescriptor->pucBuffer, length = pxDescriptor->xDataLength
154     memcpy(buffer, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength);
155     numaker_eth_trigger_tx(pxDescriptor->xDataLength, NULL);
156     /* Call the standard trace macro to log the send event. */
157     iptraceNETWORK_INTERFACE_TRANSMIT();
158
159     if( xReleaseAfterSend != pdFALSE )
160     {
161         /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
162         buffer.  The Ethernet buffer is therefore no longer needed, and must be
163         freed for re-use. */
164         vReleaseNetworkBufferAndDescriptor( pxDescriptor );
165     }
166
167     xSemaphoreGive(xTXMutex);
168     
169     return pdTRUE;
170 }
171
172
173 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
174 {
175
176     uint8_t *ucRAMBuffer = ucNetworkPackets;
177     uint32_t ul;
178
179     for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
180     {
181         pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
182         *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
183         ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
184     }
185 }
186
187
188 BaseType_t xGetPhyLinkStatus( void )
189 {
190     BaseType_t xReturn;
191
192     if( numaker_eth_link_ok() )
193     {
194         xReturn = pdPASS;
195     }
196     else
197     {
198         xReturn = pdFAIL;
199     }
200
201     return xReturn;
202 }
203
204 static void prvPhyTmrCallback( TimerHandle_t xTimer )
205 {
206     IPStackEvent_t xRxEvent;
207     static BaseType_t lastLink = pdFAIL;
208     BaseType_t currLink = xGetPhyLinkStatus();
209     if( currLink != lastLink )
210     {
211         FreeRTOS_printf(("PHY Link %s\n", (currLink) ? "Up" : "Down"));
212         if( !currLink )
213         {
214             xRxEvent.eEventType = eNetworkDownEvent;
215             xSendEventStructToIPTask( &xRxEvent, 0 );
216         }
217         lastLink = currLink;
218     }
219
220 }    
221
222     
223 static void prvEMACHandlerTask( void *pvParameters )
224 {
225     TimeOut_t xPhyTime;
226     TickType_t xPhyRemTime;
227     UBaseType_t uxLastMinBufferCount = 0;
228     UBaseType_t uxCurrentCount;
229     BaseType_t xResult = 0;
230     uint32_t ulStatus;
231     uint16_t dataLength = 0;
232     uint8_t *buffer = NULL;
233     NetworkBufferDescriptor_t *pxBufferDescriptor = NULL;
234     IPStackEvent_t xRxEvent;
235     const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );
236     
237     /* Remove compiler warnings about unused parameters. */
238     ( void ) pvParameters;
239     /* A possibility to set some additional task properties. */
240     
241     for( ;; )
242     {
243         uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
244         if( uxLastMinBufferCount != uxCurrentCount )
245         {
246             /* The logging produced below may be helpful
247             while tuning +TCP: see how many buffers are in use. */
248             uxLastMinBufferCount = uxCurrentCount;
249             FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
250                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
251         }
252         
253         /* No events to process now, wait for the next. */
254         ulTaskNotifyTake( pdFALSE, portMAX_DELAY ); 
255         while(1)
256         {    
257             /* get received frame */
258             if ( numaker_eth_get_rx_buf(&dataLength, &buffer) != 0) {
259             /* The event was lost because a network buffer was not available.
260             Call the standard trace macro to log the occurrence. */
261                 iptraceETHERNET_RX_EVENT_LOST();
262                 break;
263             }        
264
265             /* Allocate a network buffer descriptor that points to a buffer
266             large enough to hold the received frame.  As this is the simple
267             rather than efficient example the received data will just be copied
268             into this buffer. */
269
270             pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( PACKET_BUFFER_SIZE, 0 );
271
272             if( pxBufferDescriptor != NULL )
273             {        
274                 memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer, dataLength );
275 //                          FreeRTOS_printf(("--> dataLength=%d\n",dataLength));
276                 pxBufferDescriptor->xDataLength = dataLength;            
277             } else {
278                 numaker_eth_rx_next();
279                 iptraceETHERNET_RX_EVENT_LOST();
280                 break;
281             }
282             /* The event about to be sent to the TCP/IP is an Rx event. */
283             xRxEvent.eEventType = eNetworkRxEvent;
284
285             /* pvData is used to point to the network buffer descriptor that
286                 now references the received data. */
287             xRxEvent.pvData = ( void * ) pxBufferDescriptor;
288
289             /* Send the data to the TCP/IP stack. */
290             if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
291             {
292                 /* The buffer could not be sent to the IP task so the buffer
293                  must be released. */
294                 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
295
296                 /* Make a call to the standard trace macro to log the
297                         occurrence. */
298
299                 iptraceETHERNET_RX_EVENT_LOST();
300             } else
301             {
302                 /* The message was successfully sent to the TCP/IP stack.
303                 Call the standard trace macro to log the occurrence. */
304                 iptraceNETWORK_INTERFACE_RECEIVE();
305             } 
306                 numaker_eth_rx_next();
307         }    
308         numaker_eth_trigger_rx();
309     }
310 }
311
312 void xNetworkCallback(char event)
313 {
314     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
315     switch (event)
316     {
317       case 'R': //For RX event
318     /* Wakeup the prvEMACHandlerTask. */
319         if( xRxHanderTask != NULL )
320         {
321             vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
322             portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
323         }
324         break;
325       case 'T': //For TX event
326         // ack of tx done, no-op in this stage
327         break;
328       default:
329         break;
330     }
331 }