2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /******************************************************************************
\r
60 * See the following web page for essential buffer allocation scheme usage and
\r
61 * configuration details:
\r
62 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
\r
64 ******************************************************************************/
\r
66 /* Standard includes. */
\r
69 /* FreeRTOS includes. */
\r
70 #include "FreeRTOS.h"
\r
75 /* FreeRTOS+TCP includes. */
\r
76 #include "FreeRTOS_IP.h"
\r
77 #include "FreeRTOS_IP_Private.h"
\r
78 #include "NetworkInterface.h"
\r
79 #include "NetworkBufferManagement.h"
\r
81 /* For an Ethernet interrupt to be able to obtain a network buffer there must
\r
82 be at least this number of buffers available. */
\r
83 #define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 )
\r
85 /* A list of free (available) NetworkBufferDescriptor_t structures. */
\r
86 static List_t xFreeBuffersList;
\r
88 /* Some statistics about the use of buffers. */
\r
89 static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;
\r
91 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
\r
92 to the system. All the network buffers referenced from xFreeBuffersList exist
\r
93 in this array. The array is not accessed directly except during initialisation,
\r
94 when the xFreeBuffersList is filled (as all the buffers are free when the system
\r
96 static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
\r
98 /* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the
\r
99 network buffers have constant size, large enough to hold the biggest Ethernet
\r
100 packet. No resizing will be done. */
\r
101 const BaseType_t xBufferAllocFixedSize = pdTRUE;
\r
103 /* The semaphore used to obtain network buffers. */
\r
104 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
\r
106 #if( ipconfigTCP_IP_SANITY != 0 )
\r
107 static char cIsLow = pdFALSE;
\r
108 UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
\r
110 static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
\r
111 #endif /* ipconfigTCP_IP_SANITY */
\r
113 static void prvShowWarnings( void );
\r
115 /* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and
\r
116 ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these
\r
117 are not defined then default them to call the normal enter/exit critical
\r
119 #if !defined( ipconfigBUFFER_ALLOC_LOCK )
\r
121 #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)
\r
122 #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \
\r
123 UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
126 #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \
\r
127 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
130 #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL()
\r
131 #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL()
\r
133 #endif /* ipconfigBUFFER_ALLOC_LOCK */
\r
135 /*-----------------------------------------------------------*/
\r
137 #if( ipconfigTCP_IP_SANITY != 0 )
\r
139 /* HT: SANITY code will be removed as soon as the library is stable
\r
140 * and and ready to become public
\r
141 * Function below gives information about the use of buffers */
\r
142 #define WARN_LOW ( 2 )
\r
143 #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )
\r
145 #endif /* ipconfigTCP_IP_SANITY */
\r
147 /*-----------------------------------------------------------*/
\r
149 #if( ipconfigTCP_IP_SANITY != 0 )
\r
151 BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )
\r
153 return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&
\r
154 ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );
\r
156 /*-----------------------------------------------------------*/
\r
158 static void prvShowWarnings( void )
\r
160 UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );
\r
161 if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )
\r
164 FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );
\r
167 /*-----------------------------------------------------------*/
\r
169 UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
\r
171 uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );
\r
172 if( ( offset >= sizeof( xNetworkBuffers ) ) ||
\r
173 ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )
\r
175 return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;
\r
177 /*-----------------------------------------------------------*/
\r
180 static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)
\r
183 return ( UBaseType_t ) pdTRUE;
\r
185 /*-----------------------------------------------------------*/
\r
187 static void prvShowWarnings( void )
\r
190 /*-----------------------------------------------------------*/
\r
192 #endif /* ipconfigTCP_IP_SANITY */
\r
194 BaseType_t xNetworkBuffersInitialise( void )
\r
196 BaseType_t xReturn, x;
\r
198 /* Only initialise the buffers and their associated kernel objects if they
\r
199 have not been initialised before. */
\r
200 if( xNetworkBufferSemaphore == NULL )
\r
202 /* In case alternative locking is used, the mutexes can be initialised
\r
204 ipconfigBUFFER_ALLOC_INIT();
\r
206 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
\r
207 configASSERT( xNetworkBufferSemaphore );
\r
209 if( xNetworkBufferSemaphore != NULL )
\r
211 vListInitialise( &xFreeBuffersList );
\r
213 /* Initialise all the network buffers. The buffer storage comes
\r
214 from the network interface, and different hardware has different
\r
216 vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );
\r
217 for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
\r
219 /* Initialise and set the owner of the buffer list items. */
\r
220 vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );
\r
221 listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );
\r
223 /* Currently, all buffers are available for use. */
\r
224 vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );
\r
227 uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
\r
231 if( xNetworkBufferSemaphore == NULL )
\r
242 /*-----------------------------------------------------------*/
\r
244 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
\r
246 NetworkBufferDescriptor_t *pxReturn = NULL;
\r
247 BaseType_t xInvalid = pdFALSE;
\r
248 UBaseType_t uxCount;
\r
250 /* The current implementation only has a single size memory block, so
\r
251 the requested size parameter is not used (yet). */
\r
252 ( void ) xRequestedSizeBytes;
\r
254 if( xNetworkBufferSemaphore != NULL )
\r
256 /* If there is a semaphore available, there is a network buffer
\r
258 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
\r
260 /* Protect the structure as it is accessed from tasks and
\r
262 ipconfigBUFFER_ALLOC_LOCK();
\r
264 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
\r
266 if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&
\r
267 listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )
\r
269 uxListRemove( &( pxReturn->xBufferListItem ) );
\r
276 ipconfigBUFFER_ALLOC_UNLOCK();
\r
278 if( xInvalid == pdTRUE )
\r
280 /* _RB_ Can printf() be called from an interrupt? (comment
\r
281 above says this can be called from an interrupt too) */
\r
282 /* _HT_ The function shall not be called from an ISR. Comment
\r
283 was indeed misleading. Hopefully clear now?
\r
284 So the printf()is OK here. */
\r
285 FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",
\r
286 pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );
\r
291 /* Reading UBaseType_t, no critical section needed. */
\r
292 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
294 /* For stats, latch the lowest number of network buffers since
\r
296 if( uxMinimumFreeNetworkBuffers > uxCount )
\r
298 uxMinimumFreeNetworkBuffers = uxCount;
\r
301 pxReturn->xDataLength = xRequestedSizeBytes;
\r
303 #if( ipconfigTCP_IP_SANITY != 0 )
\r
307 #endif /* ipconfigTCP_IP_SANITY */
\r
309 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
311 /* make sure the buffer is not linked */
\r
312 pxReturn->pxNextBuffer = NULL;
\r
314 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
\r
316 if( xTCPWindowLoggingLevel > 3 )
\r
318 FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n",
\r
319 bIsValidNetworkDescriptor( pxReturn ),
\r
320 pxReturn, pxReturn->pucEthernetBuffer ) );
\r
323 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
\r
327 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
\r
333 /*-----------------------------------------------------------*/
\r
335 NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )
\r
337 NetworkBufferDescriptor_t *pxReturn = NULL;
\r
339 /* The current implementation only has a single size memory block, so
\r
340 the requested size parameter is not used (yet). */
\r
341 ( void ) xRequestedSizeBytes;
\r
343 /* If there is a semaphore available then there is a buffer available, but,
\r
344 as this is called from an interrupt, only take a buffer if there are at
\r
345 least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents,
\r
346 to a certain degree at least, a rapidly executing interrupt exhausting
\r
347 buffer and in so doing preventing tasks from continuing. */
\r
348 if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )
\r
350 if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )
\r
352 /* Protect the structure as it is accessed from tasks and interrupts. */
\r
353 ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
\r
355 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
\r
356 uxListRemove( &( pxReturn->xBufferListItem ) );
\r
358 ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
\r
360 iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );
\r
364 if( pxReturn == NULL )
\r
366 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();
\r
371 /*-----------------------------------------------------------*/
\r
373 BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
375 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
377 /* Ensure the buffer is returned to the list of free buffers before the
\r
378 counting semaphore is 'given' to say a buffer is available. */
\r
379 ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
\r
381 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
383 ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
\r
385 xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );
\r
386 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
388 return xHigherPriorityTaskWoken;
\r
390 /*-----------------------------------------------------------*/
\r
392 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
394 BaseType_t xListItemAlreadyInFreeList;
\r
396 if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )
\r
398 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );
\r
401 /* Ensure the buffer is returned to the list of free buffers before the
\r
402 counting semaphore is 'given' to say a buffer is available. */
\r
403 ipconfigBUFFER_ALLOC_LOCK();
\r
406 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
408 if( xListItemAlreadyInFreeList == pdFALSE )
\r
410 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
414 ipconfigBUFFER_ALLOC_UNLOCK();
\r
416 if( xListItemAlreadyInFreeList )
\r
418 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",
\r
419 pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );
\r
421 if( xListItemAlreadyInFreeList == pdFALSE )
\r
423 xSemaphoreGive( xNetworkBufferSemaphore );
\r
425 if( xTCPWindowLoggingLevel > 3 )
\r
426 FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n",
\r
427 bIsValidNetworkDescriptor( pxNetworkBuffer ),
\r
428 pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer,
\r
429 uxGetNumberOfFreeNetworkBuffers( ) ) );
\r
431 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
433 /*-----------------------------------------------------------*/
\r
435 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
\r
437 return uxMinimumFreeNetworkBuffers;
\r
439 /*-----------------------------------------------------------*/
\r
441 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
\r
443 return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
446 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
\r
448 /* In BufferAllocation_1.c all network buffer are allocated with a
\r
449 maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
\r
451 ( void ) xNewSizeBytes;
\r
452 return pxNetworkBuffer;
\r
455 /*#endif */ /* ipconfigINCLUDE_TEST_CODE */
\r