1 | /*
|
2 | * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
3 | * All rights reserved.
|
4 | *
|
5 | * Redistribution and use in source and binary forms, with or without modification,
|
6 | * are permitted provided that the following conditions are met:
|
7 | *
|
8 | * 1. Redistributions of source code must retain the above copyright notice,
|
9 | * this list of conditions and the following disclaimer.
|
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
|
11 | * this list of conditions and the following disclaimer in the documentation
|
12 | * and/or other materials provided with the distribution.
|
13 | * 3. The name of the author may not be used to endorse or promote products
|
14 | * derived from this software without specific prior written permission.
|
15 | *
|
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
19 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
21 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
25 | * OF SUCH DAMAGE.
|
26 | *
|
27 | * This file is part of the lwIP TCP/IP stack.
|
28 | *
|
29 | * Author: Adam Dunkels <adam@sics.se>
|
30 | *
|
31 | */
|
32 |
|
33 | /* lwIP includes. */
|
34 | #include "lwip/debug.h"
|
35 | #include "lwip/def.h"
|
36 | #include "lwip/sys.h"
|
37 | #include "lwip/mem.h"
|
38 | #include "lwip/stats.h"
|
39 | #include "FreeRTOS.h"
|
40 | #include "task.h"
|
41 |
|
42 |
|
43 | xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
44 |
|
45 | /* This is the number of threads that can be started with sys_thread_new() */
|
46 | #define SYS_THREAD_MAX 6
|
47 |
|
48 | static u16_t s_nextthread = 0;
|
49 |
|
50 |
|
51 | /*-----------------------------------------------------------------------------------*/
|
52 | // Creates an empty mailbox.
|
53 | err_t sys_mbox_new(sys_mbox_t *mbox, int size)
|
54 | {
|
55 | (void ) size;
|
56 |
|
57 | *mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );
|
58 |
|
59 | #if SYS_STATS
|
60 | ++lwip_stats.sys.mbox.used;
|
61 | if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
|
62 | lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
|
63 | }
|
64 | #endif /* SYS_STATS */
|
65 | if (*mbox == NULL)
|
66 | return ERR_MEM;
|
67 |
|
68 | return ERR_OK;
|
69 | }
|
70 |
|
71 | /*-----------------------------------------------------------------------------------*/
|
72 | /*
|
73 | Deallocates a mailbox. If there are messages still present in the
|
74 | mailbox when the mailbox is deallocated, it is an indication of a
|
75 | programming error in lwIP and the developer should be notified.
|
76 | */
|
77 | void sys_mbox_free(sys_mbox_t *mbox)
|
78 | {
|
79 | if( uxQueueMessagesWaiting( *mbox ) )
|
80 | {
|
81 | /* Line for breakpoint. Should never break here! */
|
82 | portNOP();
|
83 | #if SYS_STATS
|
84 | lwip_stats.sys.mbox.err++;
|
85 | #endif /* SYS_STATS */
|
86 |
|
87 | // TODO notify the user of failure.
|
88 | }
|
89 |
|
90 | vQueueDelete( *mbox );
|
91 |
|
92 | #if SYS_STATS
|
93 | --lwip_stats.sys.mbox.used;
|
94 | #endif /* SYS_STATS */
|
95 | }
|
96 |
|
97 | /*-----------------------------------------------------------------------------------*/
|
98 | // Posts the "msg" to the mailbox.
|
99 | void sys_mbox_post(sys_mbox_t *mbox, void *data)
|
100 | {
|
101 | while ( xQueueSendToBack(*mbox, &data, portMAX_DELAY ) != pdTRUE ){}
|
102 | }
|
103 |
|
104 |
|
105 | /*-----------------------------------------------------------------------------------*/
|
106 | // Try to post the "msg" to the mailbox.
|
107 | err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
108 | {
|
109 | err_t result;
|
110 |
|
111 | if ( xQueueSend( *mbox, &msg, 0 ) == pdPASS )
|
112 | {
|
113 | result = ERR_OK;
|
114 | }
|
115 | else {
|
116 | // could not post, queue must be full
|
117 | result = ERR_MEM;
|
118 |
|
119 | #if SYS_STATS
|
120 | lwip_stats.sys.mbox.err++;
|
121 | #endif /* SYS_STATS */
|
122 |
|
123 | }
|
124 |
|
125 | return result;
|
126 | }
|
127 |
|
128 | /*-----------------------------------------------------------------------------------*/
|
129 | /*
|
130 | Blocks the thread until a message arrives in the mailbox, but does
|
131 | not block the thread longer than "timeout" milliseconds (similar to
|
132 | the sys_arch_sem_wait() function). The "msg" argument is a result
|
133 | parameter that is set by the function (i.e., by doing "*msg =
|
134 | ptr"). The "msg" parameter maybe NULL to indicate that the message
|
135 | should be dropped.
|
136 |
|
137 | The return values are the same as for the sys_arch_sem_wait() function:
|
138 | Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
139 | timeout.
|
140 |
|
141 | Note that a function with a similar name, sys_mbox_fetch(), is
|
142 | implemented by lwIP.
|
143 | */
|
144 | u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
145 | {
|
146 | void *dummyptr;
|
147 | portTickType StartTime, EndTime, Elapsed;
|
148 |
|
149 | StartTime = xTaskGetTickCount();
|
150 |
|
151 | if ( msg == NULL )
|
152 | {
|
153 | msg = &dummyptr;
|
154 | }
|
155 |
|
156 | if ( timeout != 0 )
|
157 | {
|
158 | if ( pdTRUE == xQueueReceive( *mbox, &(*msg), timeout / portTICK_RATE_MS ) )
|
159 | {
|
160 | EndTime = xTaskGetTickCount();
|
161 | Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
162 |
|
163 | return ( Elapsed );
|
164 | }
|
165 | else // timed out blocking for message
|
166 | {
|
167 | *msg = NULL;
|
168 |
|
169 | return SYS_ARCH_TIMEOUT;
|
170 | }
|
171 | }
|
172 | else // block forever for a message.
|
173 | {
|
174 | //debug_blink(100);
|
175 | while( pdTRUE != xQueueReceive( *mbox, &(*msg), portMAX_DELAY ) ){} // time is arbitrary
|
176 | debug_blink(100);
|
177 | EndTime = xTaskGetTickCount();
|
178 | Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
179 |
|
180 | return ( Elapsed ); // return time blocked TODO test
|
181 | }
|
182 | }
|
183 |
|
184 | /*-----------------------------------------------------------------------------------*/
|
185 | /*
|
186 | Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll
|
187 | return with SYS_MBOX_EMPTY. On success, 0 is returned.
|
188 | */
|
189 | u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
190 | {
|
191 | void *dummyptr;
|
192 |
|
193 | if ( msg == NULL )
|
194 | {
|
195 | msg = &dummyptr;
|
196 | }
|
197 |
|
198 | if ( pdTRUE == xQueueReceive( *mbox, &(*msg), 0 ) )
|
199 | {
|
200 | return ERR_OK;
|
201 | }
|
202 | else
|
203 | {
|
204 | return SYS_MBOX_EMPTY;
|
205 | }
|
206 | }
|
207 | /*----------------------------------------------------------------------------------*/
|
208 | int sys_mbox_valid(sys_mbox_t *mbox)
|
209 | {
|
210 | if (*mbox == SYS_MBOX_NULL)
|
211 | return 0;
|
212 | else
|
213 | return 1;
|
214 | }
|
215 | /*-----------------------------------------------------------------------------------*/
|
216 | void sys_mbox_set_invalid(sys_mbox_t *mbox)
|
217 | {
|
218 | *mbox = SYS_MBOX_NULL;
|
219 | }
|
220 |
|
221 | /*-----------------------------------------------------------------------------------*/
|
222 | // Creates a new semaphore. The "count" argument specifies
|
223 | // the initial state of the semaphore.
|
224 | err_t sys_sem_new(sys_sem_t *sem, u8_t count)
|
225 | {
|
226 | vSemaphoreCreateBinary(*sem );
|
227 | if(*sem == NULL)
|
228 | {
|
229 | #if SYS_STATS
|
230 | ++lwip_stats.sys.sem.err;
|
231 | #endif /* SYS_STATS */
|
232 | return ERR_MEM;
|
233 | }
|
234 |
|
235 | if(count == 0) // Means it can't be taken
|
236 | {
|
237 | xSemaphoreTake(*sem,1);
|
238 | }
|
239 |
|
240 | #if SYS_STATS
|
241 | ++lwip_stats.sys.sem.used;
|
242 | if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
|
243 | lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
|
244 | }
|
245 | #endif /* SYS_STATS */
|
246 |
|
247 | return ERR_OK;
|
248 | }
|
249 |
|
250 | /*-----------------------------------------------------------------------------------*/
|
251 | /*
|
252 | Blocks the thread while waiting for the semaphore to be
|
253 | signaled. If the "timeout" argument is non-zero, the thread should
|
254 | only be blocked for the specified time (measured in
|
255 | milliseconds).
|
256 |
|
257 | If the timeout argument is non-zero, the return value is the number of
|
258 | milliseconds spent waiting for the semaphore to be signaled. If the
|
259 | semaphore wasn't signaled within the specified time, the return value is
|
260 | SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
261 | (i.e., it was already signaled), the function may return zero.
|
262 |
|
263 | Notice that lwIP implements a function with a similar name,
|
264 | sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
265 | */
|
266 | u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
267 | {
|
268 | portTickType StartTime, EndTime, Elapsed;
|
269 |
|
270 | StartTime = xTaskGetTickCount();
|
271 |
|
272 | if( timeout != 0)
|
273 | {
|
274 | if( xSemaphoreTake( *sem, timeout / portTICK_RATE_MS ) == pdTRUE )
|
275 | {
|
276 | EndTime = xTaskGetTickCount();
|
277 | Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
278 |
|
279 | return (Elapsed); // return time blocked TODO test
|
280 | }
|
281 | else
|
282 | {
|
283 | return SYS_ARCH_TIMEOUT;
|
284 | }
|
285 | }
|
286 | else // must block without a timeout
|
287 | {
|
288 | while( xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE){}
|
289 | EndTime = xTaskGetTickCount();
|
290 | Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
291 |
|
292 | return ( Elapsed ); // return time blocked
|
293 |
|
294 | }
|
295 | }
|
296 |
|
297 | /*-----------------------------------------------------------------------------------*/
|
298 | // Signals a semaphore
|
299 | void sys_sem_signal(sys_sem_t *sem)
|
300 | {
|
301 | xSemaphoreGive(*sem);
|
302 | }
|
303 |
|
304 | /*-----------------------------------------------------------------------------------*/
|
305 | // Deallocates a semaphore
|
306 | void sys_sem_free(sys_sem_t *sem)
|
307 | {
|
308 | #if SYS_STATS
|
309 | --lwip_stats.sys.sem.used;
|
310 | #endif /* SYS_STATS */
|
311 |
|
312 | vQueueDelete(*sem);
|
313 | }
|
314 | /*-----------------------------------------------------------------------------------*/
|
315 | int sys_sem_valid(sys_sem_t *sem)
|
316 | {
|
317 | if (*sem == SYS_SEM_NULL)
|
318 | return 0;
|
319 | else
|
320 | return 1;
|
321 | }
|
322 |
|
323 | /*-----------------------------------------------------------------------------------*/
|
324 | void sys_sem_set_invalid(sys_sem_t *sem)
|
325 | {
|
326 | *sem = SYS_SEM_NULL;
|
327 | }
|
328 |
|
329 | /*-----------------------------------------------------------------------------------*/
|
330 | // Initialize sys arch
|
331 | void sys_init(void)
|
332 | {
|
333 | // keep track of how many threads have been created
|
334 | s_nextthread = 0;
|
335 | }
|
336 | /*-----------------------------------------------------------------------------------*/
|
337 | /* Mutexes*/
|
338 | /*-----------------------------------------------------------------------------------*/
|
339 | /*-----------------------------------------------------------------------------------*/
|
340 | #if LWIP_COMPAT_MUTEX == 0
|
341 | /* Create a new mutex*/
|
342 | err_t sys_mutex_new(sys_mutex_t *mutex) {
|
343 |
|
344 | *mutex = xSemaphoreCreateMutex();
|
345 | if(*mutex == NULL)
|
346 | {
|
347 | #if SYS_STATS
|
348 | ++lwip_stats.sys.mutex.err;
|
349 | #endif /* SYS_STATS */
|
350 | return ERR_MEM;
|
351 | }
|
352 |
|
353 | #if SYS_STATS
|
354 | ++lwip_stats.sys.mutex.used;
|
355 | if (lwip_stats.sys.mutex.max < lwip_stats.sys.mutex.used) {
|
356 | lwip_stats.sys.mutex.max = lwip_stats.sys.mutex.used;
|
357 | }
|
358 | #endif /* SYS_STATS */
|
359 | return ERR_OK;
|
360 | }
|
361 | /*-----------------------------------------------------------------------------------*/
|
362 | /* Deallocate a mutex*/
|
363 | void sys_mutex_free(sys_mutex_t *mutex)
|
364 | {
|
365 | #if SYS_STATS
|
366 | --lwip_stats.sys.mutex.used;
|
367 | #endif /* SYS_STATS */
|
368 |
|
369 | vQueueDelete(*mutex);
|
370 | }
|
371 | /*-----------------------------------------------------------------------------------*/
|
372 | /* Lock a mutex*/
|
373 | void sys_mutex_lock(sys_mutex_t *mutex)
|
374 | {
|
375 | sys_arch_sem_wait(mutex, 0);
|
376 | }
|
377 |
|
378 | /*-----------------------------------------------------------------------------------*/
|
379 | /* Unlock a mutex*/
|
380 | void sys_mutex_unlock(sys_mutex_t *mutex)
|
381 | {
|
382 | xSemaphoreGive(*mutex);
|
383 | }
|
384 | #endif /*LWIP_COMPAT_MUTEX*/
|
385 | /*-----------------------------------------------------------------------------------*/
|
386 | // TODO
|
387 | /*-----------------------------------------------------------------------------------*/
|
388 | /*
|
389 | Starts a new thread with priority "prio" that will begin its execution in the
|
390 | function "thread()". The "arg" argument will be passed as an argument to the
|
391 | thread() function. The id of the new thread is returned. Both the id and
|
392 | the priority are system dependent.
|
393 | */
|
394 | sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
|
395 | {
|
396 | xTaskHandle CreatedTask;
|
397 | int result;
|
398 |
|
399 | if ( s_nextthread < SYS_THREAD_MAX )
|
400 | {
|
401 | result = xTaskCreate( thread, ( portCHAR * ) name, stacksize, arg, prio, &CreatedTask );
|
402 |
|
403 | // For each task created, store the task handle (pid) in the timers array.
|
404 | // This scheme doesn't allow for threads to be deleted
|
405 | //s_timeoutlist[s_nextthread++].pid = CreatedTask;
|
406 |
|
407 | if(result == pdPASS)
|
408 | {
|
409 | return CreatedTask;
|
410 | }
|
411 | else
|
412 | {
|
413 | return NULL;
|
414 | }
|
415 | }
|
416 | else
|
417 | {
|
418 | return NULL;
|
419 | }
|
420 | }
|
421 |
|
422 | /*
|
423 | This optional function does a "fast" critical region protection and returns
|
424 | the previous protection level. This function is only called during very short
|
425 | critical regions. An embedded system which supports ISR-based drivers might
|
426 | want to implement this function by disabling interrupts. Task-based systems
|
427 | might want to implement this by using a mutex or disabling tasking. This
|
428 | function should support recursive calls from the same task or interrupt. In
|
429 | other words, sys_arch_protect() could be called while already protected. In
|
430 | that case the return value indicates that it is already protected.
|
431 |
|
432 | sys_arch_protect() is only required if your port is supporting an operating
|
433 | system.
|
434 | */
|
435 | sys_prot_t sys_arch_protect(void)
|
436 | {
|
437 | vPortEnterCritical();
|
438 | return 1;
|
439 | }
|
440 |
|
441 | /*
|
442 | This optional function does a "fast" set of critical region protection to the
|
443 | value specified by pval. See the documentation for sys_arch_protect() for
|
444 | more information. This function is only required if your port is supporting
|
445 | an operating system.
|
446 | */
|
447 | void sys_arch_unprotect(sys_prot_t pval)
|
448 | {
|
449 | ( void ) pval;
|
450 | vPortExitCritical();
|
451 | }
|
452 |
|
453 | /*
|
454 | * Prints an assertion messages and aborts execution.
|
455 | */
|
456 | void sys_assert( const char *msg )
|
457 | {
|
458 | ( void ) msg;
|
459 | /*FSL:only needed for debugging
|
460 | printf(msg);
|
461 | printf("\n\r");
|
462 | */
|
463 | vPortEnterCritical( );
|
464 | for(;;)
|
465 | ;
|
466 | }
|