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