]> git.sur5r.net Git - freertos/blob - Demo/lwIP_MCF5235_GCC/lwip/contrib/port/FreeRTOS/MCF5235/sys_arch.c
Add PIC24, dsPIC and Coldfire files.
[freertos] / Demo / lwIP_MCF5235_GCC / lwip / contrib / port / FreeRTOS / MCF5235 / sys_arch.c
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * Modifications Copyright (c) 2006 Christian Walter <wolti@sil.at>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification,
7  * are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
26  * OF SUCH DAMAGE.
27  *
28  * This file is part of the lwIP TCP/IP stack.
29  *
30  * Author: Adam Dunkels <adam@sics.se>
31  * Modifcations: Christian Walter <wolti@sil.at>
32  *
33  * $Id: sys_arch.c,v 1.6 2006/09/24 22:04:53 wolti Exp $
34  */
35
36 /* ------------------------ System includes ------------------------------- */
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41
42 /* ------------------------ FreeRTOS includes ----------------------------- */
43 #include "FreeRTOS.h"
44 #include "task.h"
45 #include "semphr.h"
46
47 /* ------------------------ lwIP includes --------------------------------- */
48 #include "lwip/debug.h"
49 #include "lwip/def.h"
50 #include "lwip/sys.h"
51 #include "lwip/mem.h"
52 #include "lwip/sio.h"
53 #include "lwip/stats.h"
54
55 /* ------------------------ Project includes ------------------------------ */
56
57 /* ------------------------ Defines --------------------------------------- */
58 /* This is the number of threads that can be started with sys_thead_new() */
59 #define SYS_MBOX_SIZE               ( 16 )
60 #define MS_TO_TICKS( ms )           \
61     ( portTickType )( ( portTickType ) ( ms ) / portTICK_RATE_MS )
62 #define TICKS_TO_MS( ticks )        \
63     ( unsigned portLONG )( ( portTickType ) ( ticks ) * portTICK_RATE_MS )
64 #define THREAD_STACK_SIZE           ( 1024 )
65 #define THREAD_NAME                 "lwIP"
66
67 #define THREAD_INIT( tcb ) \
68     do { \
69         tcb->next = NULL; \
70         tcb->pid = ( xTaskHandle )0; \
71         tcb->timeouts.next = NULL; \
72     } while( 0 )
73
74 /* ------------------------ Type definitions ------------------------------ */
75 typedef struct sys_tcb
76 {
77     struct sys_tcb *next;
78     struct sys_timeouts timeouts;
79     xTaskHandle     pid;
80 } sys_tcb_t;
81
82 /* ------------------------ Prototypes ------------------------------------ */
83
84 /* ------------------------ Static functions ------------------------------ */
85 sys_tcb_t      *sys_thread_current( void );
86
87 /* ------------------------ Static variables ------------------------------ */
88 static sys_tcb_t *tasks = NULL;
89
90 /* ------------------------ Start implementation -------------------------- */
91 void
92 sys_init( void )
93 {
94     LWIP_ASSERT( "sys_init: not called first", tasks == NULL );
95     tasks = NULL;
96 }
97
98 /*
99  * This optional function does a "fast" critical region protection and returns
100  * the previous protection level. This function is only called during very short
101  * critical regions. An embedded system which supports ISR-based drivers might
102  * want to implement this function by disabling interrupts. Task-based systems
103  * might want to implement this by using a mutex or disabling tasking. This
104  * function should support recursive calls from the same task or interrupt. In
105  * other words, sys_arch_protect() could be called while already protected. In
106  * that case the return value indicates that it is already protected.
107  *
108  * sys_arch_protect() is only required if your port is supporting an operating
109  * system.
110  */
111 sys_prot_t
112 sys_arch_protect( void )
113 {
114     vPortEnterCritical(  );
115     return 1;
116 }
117
118 /*
119  * This optional function does a "fast" set of critical region protection to the
120  * value specified by pval. See the documentation for sys_arch_protect() for
121  * more information. This function is only required if your port is supporting
122  * an operating system.
123  */
124 void
125 sys_arch_unprotect( sys_prot_t pval )
126 {
127     ( void )pval;
128     vPortExitCritical(  );
129 }
130
131 /*
132  * Prints an assertion messages and aborts execution.
133  */
134 void
135 sys_assert( const char *msg )
136 {
137         fputs( msg, stderr );
138         fputs( "\n\r", stderr );
139     vPortEnterCritical(  );
140     for( ;; );
141 }
142
143 void
144 sys_debug( const char *const fmt, ... )
145 {
146     va_list         ap;
147
148     va_start( ap, fmt );
149     ( void )vprintf( fmt, ap );
150     ( void )putchar( '\r' );
151     va_end( ap );
152 }
153
154 /* ------------------------ Start implementation ( Threads ) -------------- */
155
156 sys_thread_t
157 sys_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio )
158 {
159     return sys_arch_thread_new( thread, arg, prio, THREAD_STACK_SIZE );
160 }
161
162 /*
163  * Starts a new thread with priority "prio" that will begin its execution in the
164  * function "thread()". The "arg" argument will be passed as an argument to the
165  * thread() function. The argument "ssize" is the requested stack size for the
166  * new thread. The id of the new thread is returned. Both the id and the
167   * priority are system dependent.
168  */
169 sys_thread_t
170 sys_arch_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio, size_t ssize )
171 {
172     sys_thread_t    thread_hdl = SYS_THREAD_NULL;
173     int             i;
174     sys_tcb_t      *p;
175     char            thread_name[ configMAX_TASK_NAME_LEN ];
176
177     /* We disable the FreeRTOS scheduler because it might be the case that the new
178      * tasks gets scheduled inside the xTaskCreate function. To prevent this we
179      * disable the scheduling. Note that this can happen although we have interrupts
180      * disabled because xTaskCreate contains a call to taskYIELD( ).
181      */
182     vPortEnterCritical(  );
183
184     p = tasks;
185     i = 0;
186     /* We are called the first time. Initialize it. */
187     if( p == NULL )
188     {
189         p = pvPortMalloc( sizeof( sys_tcb_t ) );
190         if( p != NULL )
191         {
192             tasks = p;
193         }
194     }
195     else
196     {
197         /* First task already counter. */
198         i++;
199         /* Cycle to the end of the list. */
200         while( p->next != NULL )
201         {
202             i++;
203             p = p->next;
204         }
205         p->next = pvPortMalloc( sizeof( sys_tcb_t ) );
206         p = p->next;
207     }
208
209     if( p != NULL )
210     {
211         /* Memory allocated. Initialize the data structure. */
212         THREAD_INIT( p );
213         ( void )snprintf( thread_name, configMAX_TASK_NAME_LEN, "lwIP%d", i );
214
215         /* Now q points to a free element in the list. */
216         if( xTaskCreate( thread, thread_name, ssize, arg, prio, &p->pid ) == pdPASS )
217         {
218             thread_hdl = p;
219         }
220         else
221         {
222             vPortFree( p );
223         }
224     }
225
226     vPortExitCritical(  );
227     return thread_hdl;
228 }
229
230 void
231 sys_arch_thread_remove( sys_thread_t hdl )
232 {
233     sys_tcb_t      *current = tasks, *prev;
234     sys_tcb_t      *toremove = hdl;
235     xTaskHandle     pid = ( xTaskHandle ) 0;
236
237     LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );
238
239     /* If we have to remove the first task we must update the global "tasks"
240      * variable. */
241     vPortEnterCritical(  );
242     if( hdl != NULL )
243     {
244         prev = NULL;
245         while( ( current != NULL ) && ( current != toremove ) )
246         {
247             prev = current;
248             current = current->next;
249         }
250         /* Found it. */
251         if( current == toremove )
252         {
253             /* Not the first entry in the list. */
254             if( prev != NULL )
255             {
256                 prev->next = toremove->next;
257             }
258             else
259             {
260                 tasks = toremove->next;
261             }
262             LWIP_ASSERT( "sys_arch_thread_remove: can't remove thread with timeouts!",
263                          toremove->timeouts.next == NULL );
264             pid = toremove->pid;
265             THREAD_INIT( toremove );
266             vPortFree( toremove );
267         }
268     }
269     /* We are done with accessing the shared datastructure. Release the 
270      * resources.
271      */
272     vPortExitCritical(  );
273     if( pid != ( xTaskHandle ) 0 )
274     {
275         vTaskDelete( pid );
276         /* not reached. */
277     }
278 }
279
280 /*
281  * Returns the thread control block for the currently active task. In case
282  * of an error the functions returns NULL.
283  */
284 sys_thread_t
285 sys_arch_thread_current( void )
286 {
287     sys_tcb_t      *p = tasks;
288     xTaskHandle     pid = xTaskGetCurrentTaskHandle(  );
289
290     vPortEnterCritical(  );
291     while( ( p != NULL ) && ( p->pid != pid ) )
292     {
293         p = p->next;
294     }
295     vPortExitCritical(  );
296     return p;
297 }
298
299 /*
300  * Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
301  * each thread has a list of timeouts which is represented as a linked
302  * list of sys_timeout structures. The sys_timeouts structure holds a
303  * pointer to a linked list of timeouts. This function is called by
304  * the lwIP timeout scheduler and must not return a NULL value.
305  *
306  * In a single threaded sys_arch implementation, this function will
307  * simply return a pointer to a global sys_timeouts variable stored in
308  * the sys_arch module.
309  */
310 struct sys_timeouts *
311 sys_arch_timeouts( void )
312 {
313     sys_tcb_t      *ptask;
314
315     ptask = sys_arch_thread_current(  );
316     LWIP_ASSERT( "sys_arch_timeouts: ptask != NULL", ptask != NULL );
317     return ptask != NULL ? &( ptask->timeouts ) : NULL;
318 }
319
320 /* ------------------------ Start implementation ( Semaphores ) ----------- */
321
322 /* Creates and returns a new semaphore. The "count" argument specifies
323  * the initial state of the semaphore.
324  */
325 sys_sem_t
326 sys_sem_new( u8_t count )
327 {
328     xSemaphoreHandle xSemaphore;
329
330     vSemaphoreCreateBinary( xSemaphore );
331     if( xSemaphore != SYS_SEM_NULL )
332     {
333         if( count == 0 )
334         {
335             xSemaphoreTake( xSemaphore, 1 );
336         }
337 #ifdef SYS_STATS
338         vPortEnterCritical(  );
339         lwip_stats.sys.sem.used++;
340         if( lwip_stats.sys.sem.used > lwip_stats.sys.sem.max )
341         {
342             lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
343         }
344         vPortExitCritical(  );
345 #endif
346     }
347     else
348     {
349         LWIP_ASSERT( "sys_sem_new: xSemaphore == SYS_SEM_NULL", xSemaphore != SYS_SEM_NULL );
350     }
351
352     return xSemaphore;
353 }
354
355 /* Deallocates a semaphore */
356 void
357 sys_sem_free( sys_sem_t sem )
358 {
359     LWIP_ASSERT( "sys_sem_free: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
360     if( sem != SYS_SEM_NULL )
361     {
362 #ifdef SYS_STATS
363         vPortEnterCritical(  );
364         lwip_stats.sys.sem.used--;
365         vPortExitCritical(  );
366 #endif
367         vQueueDelete( sem );
368     }
369 }
370
371 /* Signals a semaphore */
372 void
373 sys_sem_signal( sys_sem_t sem )
374 {
375     LWIP_ASSERT( "sys_sem_signal: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
376     xSemaphoreGive( sem );
377 }
378
379 /*
380  * Blocks the thread while waiting for the semaphore to be
381  * signaled. If the "timeout" argument is non-zero, the thread should
382  * only be blocked for the specified time (measured in
383  * milliseconds).
384  *
385  * If the timeout argument is non-zero, the return value is the number of
386  * milliseconds spent waiting for the semaphore to be signaled. If the
387  * semaphore wasn't signaled within the specified time, the return value is
388  * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
389  * (i.e., it was already signaled), the function may return zero.
390  *
391  * Notice that lwIP implements a function with a similar name,
392  * sys_sem_wait(), that uses the sys_arch_sem_wait() function.
393  */
394 u32_t
395 sys_arch_sem_wait( sys_sem_t sem, u32_t timeout )
396 {
397     portBASE_TYPE   xStatus;
398     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;
399     u32_t           timespent;
400
401     LWIP_ASSERT( "sys_arch_sem_wait: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );
402     xTicksStart = xTaskGetTickCount(  );
403     if( timeout == 0 )
404     {
405         do
406         {
407             xStatus = xSemaphoreTake( sem, MS_TO_TICKS( 100 ) );
408         }
409         while( xStatus != pdTRUE );
410     }
411     else
412     {
413         xStatus = xSemaphoreTake( sem, MS_TO_TICKS( timeout ) );
414     }
415
416     /* Semaphore was signaled. */
417     if( xStatus == pdTRUE )
418     {
419         xTicksEnd = xTaskGetTickCount(  );
420         xTicksElapsed = xTicksEnd - xTicksStart;
421         timespent = TICKS_TO_MS( xTicksElapsed );
422     }
423     else
424     {
425         timespent = SYS_ARCH_TIMEOUT;
426     }
427     return timespent;
428 }
429
430
431 /* ------------------------ Start implementation ( Mailboxes ) ------------ */
432
433 /* Creates an empty mailbox. */
434 sys_mbox_t
435 sys_mbox_new( void )
436 {
437     xQueueHandle    mbox;
438
439     mbox = xQueueCreate( SYS_MBOX_SIZE, sizeof( void * ) );
440     if( mbox != SYS_MBOX_NULL )
441     {
442 #ifdef SYS_STATS
443         vPortEnterCritical(  );
444         lwip_stats.sys.mbox.used++;
445         if( lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max )
446         {
447             lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
448         }
449         vPortExitCritical(  );
450 #endif
451     }
452     return mbox;
453 }
454
455 /*
456   Deallocates a mailbox. If there are messages still present in the
457   mailbox when the mailbox is deallocated, it is an indication of a
458   programming error in lwIP and the developer should be notified.
459 */
460 void
461 sys_mbox_free( sys_mbox_t mbox )
462 {
463     void           *msg;
464
465     LWIP_ASSERT( "sys_mbox_free: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );
466     if( mbox != SYS_MBOX_NULL )
467     {
468         while( uxQueueMessagesWaiting( mbox ) != 0 )
469         {
470             if( sys_arch_mbox_fetch( mbox, &msg, 1 ) != SYS_ARCH_TIMEOUT )
471             {
472                 LWIP_ASSERT( "sys_mbox_free: memory leak (msg != NULL)", msg == NULL );
473             }
474         }
475         vQueueDelete( mbox );
476 #ifdef SYS_STATS
477         vPortEnterCritical(  );
478         lwip_stats.sys.mbox.used--;
479         vPortExitCritical(  );
480 #endif
481     }
482 }
483
484 /*
485  * This function sends a message to a mailbox. It is unusual in that no error
486  * return is made. This is because the caller is responsible for ensuring that
487  * the mailbox queue will not fail. The caller does this by limiting the number
488  * of msg structures which exist for a given mailbox.
489  */
490 void
491 sys_mbox_post( sys_mbox_t mbox, void *data )
492 {
493     portBASE_TYPE   xQueueSent;
494
495     /* Queue must not be full - Otherwise it is an error. */
496     xQueueSent = xQueueSend( mbox, &data, 0 );
497     LWIP_ASSERT( "sys_mbox_post: xQueueSent == pdPASS", xQueueSent == pdPASS );
498 }
499
500 /*
501  * Blocks the thread until a message arrives in the mailbox, but does
502  * not block the thread longer than "timeout" milliseconds (similar to
503  * the sys_arch_sem_wait() function). The "msg" argument is a result
504  * parameter that is set by the function (i.e., by doing "*msg =
505  * ptr"). The "msg" parameter maybe NULL to indicate that the message
506  * should be dropped.
507  *
508  * Note that a function with a similar name, sys_mbox_fetch(), is
509  * implemented by lwIP.
510  */
511 u32_t
512 sys_arch_mbox_fetch( sys_mbox_t mbox, void **msg, u32_t timeout )
513 {
514     void           *ret_msg;
515     portBASE_TYPE   xStatus;
516     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;
517     u32_t           timespent;
518
519     LWIP_ASSERT( "sys_arch_mbox_fetch: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );
520     xTicksStart = xTaskGetTickCount(  );
521     if( timeout == 0 )
522     {
523         do
524         {
525             xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( 100 ) );
526         }
527         while( xStatus != pdTRUE );
528     }
529     else
530     {
531         xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( timeout ) );
532     }
533
534     if( xStatus == pdTRUE )
535     {
536         if( msg )
537         {
538             *msg = ret_msg;
539         }
540         xTicksEnd = xTaskGetTickCount(  );
541         xTicksElapsed = xTicksEnd - xTicksStart;
542         timespent = TICKS_TO_MS( xTicksElapsed );
543     }
544     else
545     {
546         if( msg )
547         {
548             *msg = NULL;
549         }
550         timespent = SYS_ARCH_TIMEOUT;
551     }
552     return timespent;
553 }
554
555 u32_t
556 sys_jiffies( void )
557 {
558     portTickType    xTicks = xTaskGetTickCount(  );
559
560     return ( u32_t )TICKS_TO_MS( xTicks );
561 }