2 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
\r
3 * Modifications Copyright (c) 2006 Christian Walter <wolti@sil.at>
\r
4 * All rights reserved.
\r
6 * Redistribution and use in source and binary forms, with or without modification,
\r
7 * are permitted provided that the following conditions are met:
\r
9 * 1. Redistributions of source code must retain the above copyright notice,
\r
10 * this list of conditions and the following disclaimer.
\r
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
12 * this list of conditions and the following disclaimer in the documentation
\r
13 * and/or other materials provided with the distribution.
\r
14 * 3. The name of the author may not be used to endorse or promote products
\r
15 * derived from this software without specific prior written permission.
\r
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
\r
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
\r
20 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
\r
22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
\r
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
\r
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
\r
28 * This file is part of the lwIP TCP/IP stack.
\r
30 * Author: Adam Dunkels <adam@sics.se>
\r
31 * Modifcations: Christian Walter <wolti@sil.at>
\r
33 * $Id: sys_arch.c,v 1.1 2008/08/05 00:10:49 b06862 Exp $
\r
36 /* ------------------------ System includes ------------------------------- */
\r
40 /* ------------------------ FreeRTOS includes ----------------------------- */
\r
41 #include "FreeRTOS.h"
\r
45 /* ------------------------ lwIP includes --------------------------------- */
\r
46 #include "lwip/debug.h"
\r
47 #include "lwip/def.h"
\r
48 #include "lwip/sys.h"
\r
49 #include "lwip/mem.h"
\r
50 #include "lwip/sio.h"
\r
51 #include "lwip/stats.h"
\r
53 /* ------------------------ Project includes ------------------------------ */
\r
55 /* ------------------------ Defines --------------------------------------- */
\r
56 /* This is the number of threads that can be started with sys_thead_new() */
\r
57 #define SYS_MBOX_SIZE ( 16 )
\r
58 #define MS_TO_TICKS( ms ) \
\r
59 ( portTickType )( ( portTickType ) ( ms ) / portTICK_RATE_MS )
\r
60 #define TICKS_TO_MS( ticks ) \
\r
61 ( unsigned long )( ( portTickType ) ( ticks ) * portTICK_RATE_MS )
\r
62 #define THREAD_STACK_SIZE ( 256 /*FSL:1024*/ )
\r
63 #define THREAD_NAME "lwIP"
\r
65 #define THREAD_INIT( tcb ) \
\r
68 tcb->pid = ( xTaskHandle )0; \
\r
69 tcb->timeouts.next = NULL; \
\r
72 /* ------------------------ Type definitions ------------------------------ */
\r
73 typedef struct sys_tcb
\r
75 struct sys_tcb *next;
\r
76 struct sys_timeouts timeouts;
\r
80 /* ------------------------ Prototypes ------------------------------------ */
\r
82 /* ------------------------ Static functions ------------------------------ */
\r
83 sys_tcb_t *sys_thread_current( void );
\r
85 /* ------------------------ Static variables ------------------------------ */
\r
86 static sys_tcb_t *tasks = NULL;
\r
88 /* ------------------------ Start implementation -------------------------- */
\r
92 LWIP_ASSERT( "sys_init: not called first", tasks == NULL );
\r
97 * This optional function does a "fast" critical region protection and returns
\r
98 * the previous protection level. This function is only called during very short
\r
99 * critical regions. An embedded system which supports ISR-based drivers might
\r
100 * want to implement this function by disabling interrupts. Task-based systems
\r
101 * might want to implement this by using a mutex or disabling tasking. This
\r
102 * function should support recursive calls from the same task or interrupt. In
\r
103 * other words, sys_arch_protect() could be called while already protected. In
\r
104 * that case the return value indicates that it is already protected.
\r
106 * sys_arch_protect() is only required if your port is supporting an operating
\r
110 sys_arch_protect( void )
\r
112 vPortEnterCritical( );
\r
117 * This optional function does a "fast" set of critical region protection to the
\r
118 * value specified by pval. See the documentation for sys_arch_protect() for
\r
119 * more information. This function is only required if your port is supporting
\r
120 * an operating system.
\r
123 sys_arch_unprotect( sys_prot_t pval )
\r
126 vPortExitCritical( );
\r
130 * Prints an assertion messages and aborts execution.
\r
133 sys_assert( const char *msg )
\r
135 /*FSL:only needed for debugging
\r
139 vPortEnterCritical( );
\r
145 sys_debug( const char *const fmt, ... )
\r
147 /*FSL: same implementation as printf*/
\r
149 /*FSL: removed due to lack of space*/
\r
153 /* ------------------------ Start implementation ( Threads ) -------------- */
\r
156 * Starts a new thread with priority "prio" that will begin its execution in the
\r
157 * function "thread()". The "arg" argument will be passed as an argument to the
\r
158 * thread() function. The argument "ssize" is the requested stack size for the
\r
159 * new thread. The id of the new thread is returned. Both the id and the
\r
160 * priority are system dependent.
\r
163 sys_thread_new(char *name, void ( *thread ) ( void *arg ), void *arg, int /*size_t*/ stacksize, int prio )
\r
165 sys_thread_t thread_hdl = SYS_THREAD_NULL;
\r
169 /* We disable the FreeRTOS scheduler because it might be the case that the new
\r
170 * tasks gets scheduled inside the xTaskCreate function. To prevent this we
\r
171 * disable the scheduling. Note that this can happen although we have interrupts
\r
172 * disabled because xTaskCreate contains a call to taskYIELD( ).
\r
174 vPortEnterCritical( );
\r
178 /* We are called the first time. Initialize it. */
\r
181 p = (sys_tcb_t *)pvPortMalloc( sizeof( sys_tcb_t ) );
\r
189 /* First task already counter. */
\r
191 /* Cycle to the end of the list. */
\r
192 while( p->next != NULL )
\r
197 p->next = (sys_tcb_t *)pvPortMalloc( sizeof( sys_tcb_t ) );
\r
203 /* Memory allocated. Initialize the data structure. */
\r
206 /* Now q points to a free element in the list. */
\r
207 if( xTaskCreate( thread, (const signed char *const)name, stacksize, arg, prio, &p->pid ) == pdPASS )
\r
217 vPortExitCritical( );
\r
222 sys_arch_thread_remove( sys_thread_t hdl )
\r
224 sys_tcb_t *current = tasks, *prev;
\r
225 sys_tcb_t *toremove = hdl;
\r
226 xTaskHandle pid = ( xTaskHandle ) 0;
\r
228 LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );
\r
230 /* If we have to remove the first task we must update the global "tasks"
\r
232 vPortEnterCritical( );
\r
236 while( ( current != NULL ) && ( current != toremove ) )
\r
239 current = current->next;
\r
242 if( current == toremove )
\r
244 /* Not the first entry in the list. */
\r
247 prev->next = toremove->next;
\r
251 tasks = toremove->next;
\r
253 LWIP_ASSERT( "sys_arch_thread_remove: can't remove thread with timeouts!",
\r
254 toremove->timeouts.next == NULL );
\r
255 pid = toremove->pid;
\r
256 THREAD_INIT( toremove );
\r
257 vPortFree( toremove );
\r
260 /* We are done with accessing the shared datastructure. Release the
\r
263 vPortExitCritical( );
\r
264 if( pid != ( xTaskHandle ) 0 )
\r
266 vTaskDelete( pid );
\r
272 * Returns the thread control block for the currently active task. In case
\r
273 * of an error the functions returns NULL.
\r
276 sys_arch_thread_current( void )
\r
278 sys_tcb_t *p = tasks;
\r
279 xTaskHandle pid = xTaskGetCurrentTaskHandle( );
\r
281 vPortEnterCritical( );
\r
282 while( ( p != NULL ) && ( p->pid != pid ) )
\r
286 vPortExitCritical( );
\r
291 * Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
\r
292 * each thread has a list of timeouts which is represented as a linked
\r
293 * list of sys_timeout structures. The sys_timeouts structure holds a
\r
294 * pointer to a linked list of timeouts. This function is called by
\r
295 * the lwIP timeout scheduler and must not return a NULL value.
\r
297 * In a single threaded sys_arch implementation, this function will
\r
298 * simply return a pointer to a global sys_timeouts variable stored in
\r
299 * the sys_arch module.
\r
301 struct sys_timeouts *
\r
302 sys_arch_timeouts( void )
\r
306 ptask = sys_arch_thread_current( );
\r
307 LWIP_ASSERT( "sys_arch_timeouts: ptask != NULL", ptask != NULL );
\r
308 return ptask != NULL ? &( ptask->timeouts ) : NULL;
\r
311 /* ------------------------ Start implementation ( Semaphores ) ----------- */
\r
313 /* Creates and returns a new semaphore. The "count" argument specifies
\r
314 * the initial state of the semaphore.
\r
317 sys_sem_new( u8_t count )
\r
319 xSemaphoreHandle xSemaphore;
\r
321 vSemaphoreCreateBinary( xSemaphore );
\r
322 if( xSemaphore != SYS_SEM_NULL )
\r
326 xSemaphoreTake( xSemaphore, 1 );
\r
329 vPortEnterCritical( );
\r
330 lwip_stats.sys.sem.used++;
\r
331 if( lwip_stats.sys.sem.used > lwip_stats.sys.sem.max )
\r
333 lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
\r
335 vPortExitCritical( );
\r
340 LWIP_ASSERT( "sys_sem_new: xSemaphore == SYS_SEM_NULL", xSemaphore != SYS_SEM_NULL );
\r
346 /* Deallocates a semaphore */
\r
348 sys_sem_free( sys_sem_t sem )
\r
350 LWIP_ASSERT( "sys_sem_free: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
\r
351 if( sem != SYS_SEM_NULL )
\r
354 vPortEnterCritical( );
\r
355 lwip_stats.sys.sem.used--;
\r
356 vPortExitCritical( );
\r
358 vQueueDelete( sem );
\r
362 /* Signals a semaphore */
\r
364 sys_sem_signal( sys_sem_t sem )
\r
366 LWIP_ASSERT( "sys_sem_signal: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
\r
367 xSemaphoreGive( sem );
\r
371 * Blocks the thread while waiting for the semaphore to be
\r
372 * signaled. If the "timeout" argument is non-zero, the thread should
\r
373 * only be blocked for the specified time (measured in
\r
376 * If the timeout argument is non-zero, the return value is the number of
\r
377 * milliseconds spent waiting for the semaphore to be signaled. If the
\r
378 * semaphore wasn't signaled within the specified time, the return value is
\r
379 * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
\r
380 * (i.e., it was already signaled), the function may return zero.
\r
382 * Notice that lwIP implements a function with a similar name,
\r
383 * sys_sem_wait(), that uses the sys_arch_sem_wait() function.
\r
386 sys_arch_sem_wait( sys_sem_t sem, u32_t timeout )
\r
388 portBASE_TYPE xStatus;
\r
389 portTickType xTicksStart, xTicksEnd, xTicksElapsed;
\r
392 LWIP_ASSERT( "sys_arch_sem_wait: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
\r
393 xTicksStart = xTaskGetTickCount( );
\r
398 xStatus = xSemaphoreTake( sem, MS_TO_TICKS( 100 ) );
\r
400 while( xStatus != pdTRUE );
\r
404 xStatus = xSemaphoreTake( sem, MS_TO_TICKS( timeout ) );
\r
407 /* Semaphore was signaled. */
\r
408 if( xStatus == pdTRUE )
\r
410 xTicksEnd = xTaskGetTickCount( );
\r
411 xTicksElapsed = xTicksEnd - xTicksStart;
\r
412 timespent = TICKS_TO_MS( xTicksElapsed );
\r
416 timespent = SYS_ARCH_TIMEOUT;
\r
422 /* ------------------------ Start implementation ( Mailboxes ) ------------ */
\r
424 /* Creates an empty mailbox. */
\r
426 sys_mbox_new( /*paolo:void*/int size )
\r
430 mbox = xQueueCreate( SYS_MBOX_SIZE/*size*/, sizeof( void * ) );
\r
431 if( mbox != SYS_MBOX_NULL )
\r
434 vPortEnterCritical( );
\r
435 lwip_stats.sys.mbox.used++;
\r
436 if( lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max )
\r
438 lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
\r
440 vPortExitCritical( );
\r
447 Deallocates a mailbox. If there are messages still present in the
\r
448 mailbox when the mailbox is deallocated, it is an indication of a
\r
449 programming error in lwIP and the developer should be notified.
\r
452 sys_mbox_free( sys_mbox_t mbox )
\r
456 LWIP_ASSERT( "sys_mbox_free: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );
\r
457 if( mbox != SYS_MBOX_NULL )
\r
459 while( uxQueueMessagesWaiting( mbox ) != 0 )
\r
461 if( sys_arch_mbox_fetch( mbox, &msg, 1 ) != SYS_ARCH_TIMEOUT )
\r
463 LWIP_ASSERT( "sys_mbox_free: memory leak (msg != NULL)", msg == NULL );
\r
466 vQueueDelete( mbox );
\r
468 vPortEnterCritical( );
\r
469 lwip_stats.sys.mbox.used--;
\r
470 vPortExitCritical( );
\r
476 * This function sends a message to a mailbox. It is unusual in that no error
\r
477 * return is made. This is because the caller is responsible for ensuring that
\r
478 * the mailbox queue will not fail. The caller does this by limiting the number
\r
479 * of msg structures which exist for a given mailbox.
\r
482 sys_mbox_post( sys_mbox_t mbox, void *data )
\r
484 portBASE_TYPE xQueueSent;
\r
486 /* Queue must not be full - Otherwise it is an error. */
\r
487 xQueueSent = xQueueSend( mbox, &data, 0 );
\r
488 LWIP_ASSERT( "sys_mbox_post: xQueueSent == pdPASS", xQueueSent == pdPASS );
\r
493 *Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
\r
494 *is full, else, ERR_OK if the "msg" is posted.
\r
497 sys_mbox_trypost( sys_mbox_t mbox, void *data )
\r
499 /* Queue must not be full - Otherwise it is an error. */
\r
500 if(xQueueSend( mbox, &data, 0 ) == pdPASS)
\r
511 * Blocks the thread until a message arrives in the mailbox, but does
\r
512 * not block the thread longer than "timeout" milliseconds (similar to
\r
513 * the sys_arch_sem_wait() function). The "msg" argument is a result
\r
514 * parameter that is set by the function (i.e., by doing "*msg =
\r
515 * ptr"). The "msg" parameter maybe NULL to indicate that the message
\r
516 * should be dropped.
\r
518 * Note that a function with a similar name, sys_mbox_fetch(), is
\r
519 * implemented by lwIP.
\r
522 sys_arch_mbox_fetch( sys_mbox_t mbox, void **msg, u32_t timeout )
\r
525 portBASE_TYPE xStatus;
\r
526 portTickType xTicksStart, xTicksEnd, xTicksElapsed;
\r
529 LWIP_ASSERT( "sys_arch_mbox_fetch: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );
\r
530 xTicksStart = xTaskGetTickCount( );
\r
535 xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( 100 ) );
\r
537 while( xStatus != pdTRUE );
\r
541 xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( timeout ) );
\r
544 if( xStatus == pdTRUE )
\r
550 xTicksEnd = xTaskGetTickCount( );
\r
551 xTicksElapsed = xTicksEnd - xTicksStart;
\r
552 timespent = TICKS_TO_MS( xTicksElapsed );
\r
560 timespent = SYS_ARCH_TIMEOUT;
\r
566 sys_jiffies( void )
\r
568 portTickType xTicks = xTaskGetTickCount( );
\r
570 return ( u32_t )TICKS_TO_MS( xTicks );
\r