]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / LPC17xx / NetworkInterface.c
1 /*\r
2  * FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.\r
3  * Authors include Hein Tibosch and Richard Barry\r
4  *\r
5  *******************************************************************************\r
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
7  ***                                                                         ***\r
8  ***                                                                         ***\r
9  ***   FREERTOS+TCP IS STILL IN THE LAB:                                     ***\r
10  ***                                                                         ***\r
11  ***   This product is functional and is already being used in commercial    ***\r
12  ***   products.  Be aware however that we are still refining its design,    ***\r
13  ***   the source code does not yet fully conform to the strict coding and   ***\r
14  ***   style standards mandated by Real Time Engineers ltd., and the         ***\r
15  ***   documentation and testing is not necessarily complete.                ***\r
16  ***                                                                         ***\r
17  ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***\r
18  ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***\r
19  ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***\r
20  ***   under a license other than that described below.                      ***\r
21  ***                                                                         ***\r
22  ***                                                                         ***\r
23  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
24  *******************************************************************************\r
25  *\r
26  * - Open source licensing -\r
27  * While FreeRTOS+TCP is in the lab it is provided only under version two of the\r
28  * GNU General Public License (GPL) (which is different to the standard FreeRTOS\r
29  * license).  FreeRTOS+TCP is free to download, use and distribute under the\r
30  * terms of that license provided the copyright notice and this text are not\r
31  * altered or removed from the source files.  The GPL V2 text is available on\r
32  * the gnu.org web site, and on the following\r
33  * URL: http://www.FreeRTOS.org/gpl-2.0.txt.  Active early adopters may, and\r
34  * solely at the discretion of Real Time Engineers Ltd., be offered versions\r
35  * under a license other then the GPL.\r
36  *\r
37  * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot\r
38  * use FreeRTOS+TCP unless you agree that you use the software 'as is'.\r
39  * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied\r
40  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
41  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
42  * implied, expressed, or statutory.\r
43  *\r
44  * 1 tab == 4 spaces!\r
45  *\r
46  * http://www.FreeRTOS.org\r
47  * http://www.FreeRTOS.org/plus\r
48  * http://www.FreeRTOS.org/labs\r
49  *\r
50  */\r
51 \r
52 /* Standard includes. */\r
53 #include <stdint.h>\r
54 \r
55 /* FreeRTOS includes. */\r
56 #include "FreeRTOS.h"\r
57 #include "task.h"\r
58 #include "queue.h"\r
59 #include "semphr.h"\r
60 \r
61 /* Hardware abstraction. */\r
62 #include "FreeRTOS_IO.h"\r
63 \r
64 /* FreeRTOS+TCP includes. */\r
65 #include "FreeRTOS_UDP_IP.h"\r
66 #include "FreeRTOS_Sockets.h"\r
67 #include "NetworkBufferManagement.h"\r
68 \r
69 /* Driver includes. */\r
70 #include "lpc17xx_emac.h"\r
71 #include "lpc17xx_pinsel.h"\r
72 \r
73 /* Demo includes. */\r
74 #include "NetworkInterface.h"\r
75 \r
76 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1\r
77         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
78 #else\r
79         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
80 #endif\r
81 \r
82 /* When a packet is ready to be sent, if it cannot be sent immediately then the\r
83 task performing the transmit will block for niTX_BUFFER_FREE_WAIT\r
84 milliseconds.  It will do this a maximum of niMAX_TX_ATTEMPTS before giving\r
85 up. */\r
86 #define niTX_BUFFER_FREE_WAIT   ( pdMS_TO_TICKS( 2UL ) )\r
87 #define niMAX_TX_ATTEMPTS               ( 5 )\r
88 \r
89 /* The length of the queue used to send interrupt status words from the\r
90 interrupt handler to the deferred handler task. */\r
91 #define niINTERRUPT_QUEUE_LENGTH        ( 10 )\r
92 \r
93 /*-----------------------------------------------------------*/\r
94 \r
95 /*\r
96  * A deferred interrupt handler task that processes\r
97  */\r
98 static void prvEMACHandlerTask( void *pvParameters );\r
99 \r
100 /*-----------------------------------------------------------*/\r
101 \r
102 /* The queue used to communicate Ethernet events with the IP task. */\r
103 extern QueueHandle_t xNetworkEventQueue;\r
104 \r
105 /* The semaphore used to wake the deferred interrupt handler task when an Rx\r
106 interrupt is received. */\r
107 static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;\r
108 /*-----------------------------------------------------------*/\r
109 \r
110 BaseType_t xNetworkInterfaceInitialise( void )\r
111 {\r
112 EMAC_CFG_Type Emac_Config;\r
113 PINSEL_CFG_Type xPinConfig;\r
114 BaseType_t xStatus, xReturn;\r
115 extern uint8_t ucMACAddress[ 6 ];\r
116 \r
117         /* Enable Ethernet Pins */\r
118         boardCONFIGURE_ENET_PINS( xPinConfig );\r
119 \r
120         Emac_Config.Mode = EMAC_MODE_AUTO;\r
121         Emac_Config.pbEMAC_Addr = ucMACAddress;\r
122         xStatus = EMAC_Init( &Emac_Config );\r
123 \r
124         LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );\r
125 \r
126         if( xStatus != ERROR )\r
127         {\r
128                 vSemaphoreCreateBinary( xEMACRxEventSemaphore );\r
129                 configASSERT( xEMACRxEventSemaphore );\r
130 \r
131                 /* The handler task is created at the highest possible priority to\r
132                 ensure the interrupt handler can return directly to it. */\r
133                 xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );\r
134 \r
135                 /* Enable the interrupt and set its priority to the minimum\r
136                 interrupt priority.  */\r
137                 NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
138                 NVIC_EnableIRQ( ENET_IRQn );\r
139 \r
140                 xReturn = pdPASS;\r
141         }\r
142         else\r
143         {\r
144                 xReturn = pdFAIL;\r
145         }\r
146 \r
147         configASSERT( xStatus != ERROR );\r
148 \r
149         return xReturn;\r
150 }\r
151 /*-----------------------------------------------------------*/\r
152 \r
153 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
154 {\r
155 BaseType_t xReturn = pdFAIL;\r
156 int32_t x;\r
157 extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );\r
158 extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );\r
159 \r
160 \r
161         /* Attempt to obtain access to a Tx buffer. */\r
162         for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )\r
163         {\r
164                 if( EMAC_CheckTransmitIndex() == TRUE )\r
165                 {\r
166                         /* Will the data fit in the Tx buffer? */\r
167                         if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */\r
168                         {\r
169                                 /* Assign the buffer to the Tx descriptor that is now known to\r
170                                 be free. */\r
171                                 EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );\r
172 \r
173                                 /* The EMAC now owns the buffer. */\r
174                                 pxNetworkBuffer->pucBuffer = NULL;\r
175 \r
176                                 /* Initiate the Tx. */\r
177                                 EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );\r
178                                 iptraceNETWORK_INTERFACE_TRANSMIT();\r
179 \r
180                                 /* The Tx has been initiated. */\r
181                                 xReturn = pdPASS;\r
182                         }\r
183                         break;\r
184                 }\r
185                 else\r
186                 {\r
187                         vTaskDelay( niTX_BUFFER_FREE_WAIT );\r
188                 }\r
189         }\r
190 \r
191         /* Finished with the network buffer. */\r
192         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
193 \r
194         return xReturn;\r
195 }\r
196 /*-----------------------------------------------------------*/\r
197 \r
198 void ENET_IRQHandler( void )\r
199 {\r
200 uint32_t ulInterruptCause;\r
201 \r
202         while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )\r
203         {\r
204                 /* Clear the interrupt. */\r
205                 LPC_EMAC->IntClear = ulInterruptCause;\r
206 \r
207                 /* Clear fatal error conditions.  NOTE:  The driver does not clear all\r
208                 errors, only those actually experienced.  For future reference, range\r
209                 errors are not actually errors so can be ignored. */\r
210                 if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )\r
211                 {\r
212                         LPC_EMAC->Command |= EMAC_CR_TX_RES;\r
213                 }\r
214 \r
215                 /* Unblock the deferred interrupt handler task if the event was an\r
216                 Rx. */\r
217                 if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )\r
218                 {\r
219                         xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );\r
220                 }\r
221         }\r
222 \r
223         /* ulInterruptCause is used for convenience here.  A context switch is\r
224         wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a\r
225         compiler warning. */\r
226         portEND_SWITCHING_ISR( ulInterruptCause );\r
227 }\r
228 /*-----------------------------------------------------------*/\r
229 \r
230 static void prvEMACHandlerTask( void *pvParameters )\r
231 {\r
232 size_t xDataLength;\r
233 const uint16_t usCRCLength = 4;\r
234 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
235 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
236 \r
237 /* This is not included in the header file for some reason. */\r
238 extern uint8_t *EMAC_NextPacketToRead( void );\r
239 \r
240         ( void ) pvParameters;\r
241         configASSERT( xEMACRxEventSemaphore );\r
242 \r
243         for( ;; )\r
244         {\r
245                 /* Wait for the EMAC interrupt to indicate that another packet has been\r
246                 received.  The while() loop is only needed if INCLUDE_vTaskSuspend is\r
247                 set to 0 in FreeRTOSConfig.h. */\r
248                 while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );\r
249 \r
250                 /* At least one packet has been received. */\r
251                 while( EMAC_CheckReceiveIndex() != FALSE )\r
252                 {\r
253                         /* Obtain the length, minus the CRC.  The CRC is four bytes\r
254                         but the length is already minus 1. */\r
255                         xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );\r
256 \r
257                         if( xDataLength > 0U )\r
258                         {\r
259                                 /* Obtain a network buffer to pass this data into the\r
260                                 stack.  No storage is required as the network buffer\r
261                                 will point directly to the buffer that already holds\r
262                                 the     received data. */\r
263                                 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );\r
264 \r
265                                 if( pxNetworkBuffer != NULL )\r
266                                 {\r
267                                         pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();\r
268                                         pxNetworkBuffer->xDataLength = xDataLength;\r
269                                         xRxEvent.pvData = ( void * ) pxNetworkBuffer;\r
270 \r
271                                         /* Data was received and stored.  Send a message to the IP\r
272                                         task to let it know. */\r
273                                         if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )\r
274                                         {\r
275                                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
276                                                 iptraceETHERNET_RX_EVENT_LOST();\r
277                                         }\r
278                                 }\r
279                                 else\r
280                                 {\r
281                                         iptraceETHERNET_RX_EVENT_LOST();\r
282                                 }\r
283 \r
284                                 iptraceNETWORK_INTERFACE_RECEIVE();\r
285                         }\r
286 \r
287                         /* Release the frame. */\r
288                         EMAC_UpdateRxConsumeIndex();\r
289                 }\r
290         }\r
291 }\r
292 /*-----------------------------------------------------------*/\r
293 \r