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