00001 /*This file has been prepared for Doxygen automatic documentation generation.*/ 00015 /* Copyright (c) 2009 Atmel Corporation. All rights reserved. 00016 * 00017 * Redistribution and use in source and binary forms, with or without 00018 * modification, are permitted provided that the following conditions are met: 00019 * 00020 * 1. Redistributions of source code must retain the above copyright notice, this 00021 * list of conditions and the following disclaimer. 00022 * 00023 * 2. Redistributions in binary form must reproduce the above copyright notice, 00024 * this list of conditions and the following disclaimer in the documentation 00025 * and/or other materials provided with the distribution. 00026 * 00027 * 3. The name of Atmel may not be used to endorse or promote products derived 00028 * from this software without specific prior written permission. 00029 * 00030 * 4. This software may only be redistributed and used in connection with an Atmel 00031 * AVR product. 00032 * 00033 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 00034 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00035 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00036 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 00037 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00038 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00039 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00040 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00041 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00042 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 00043 * 00044 */ 00045 #include "lwip/debug.h" 00046 #include "lwip/sys.h" 00047 #include "lwip/opt.h" 00048 #include "lwip/stats.h" 00049 00050 00051 #define SYS_ARCH_BLOCKING_TICKTIMEOUT ((portTickType)10000) 00052 00053 00054 // Structure associating a thread to a struct sys_timeouts 00055 struct TimeoutlistPerThread 00056 { 00057 struct sys_timeouts timeouts; // holds a pointer to a linked list of timeouts 00058 sys_thread_t pid; // The thread id. 00059 }; 00060 00061 // Thread & struct sys_timeouts association statically allocated per thread. 00062 // Note: SYS_THREAD_MAX is the max number of thread created by sys_thread_new() 00063 // that can run simultaneously; it is defined in conf_lwip_threads.h. 00064 static struct TimeoutlistPerThread Threads_TimeoutsList[SYS_THREAD_MAX]; 00065 00066 // Number of active threads. 00067 static u16_t NbActiveThreads = 0; 00068 00069 //----------- INIT ------------------------------------------------------------- 00070 00071 // Initialize the sys_arch layer. 00072 void sys_init(void) 00073 { 00074 int i; 00075 00076 00077 // Initialize the the per-thread sys_timeouts structures 00078 // make sure there are no valid pids in the list 00079 for(i = 0; i < SYS_THREAD_MAX; i++) 00080 { 00081 Threads_TimeoutsList[i].pid = 0; 00082 Threads_TimeoutsList[i].timeouts.next = NULL; 00083 } 00084 00085 // keep track of how many threads have been created 00086 NbActiveThreads = 0; 00087 } 00088 00089 00090 00091 //----------- SEMAPHORES ------------------------------------------------------- 00092 00093 // Creates and returns a new semaphore. The "count" argument specifies the 00094 // initial state of the semaphore. 00095 sys_sem_t sys_sem_new(u8_t count) 00096 { 00097 sys_sem_t xSemaphore = SYS_SEM_NULL; 00098 00099 portENTER_CRITICAL(); 00100 00101 vSemaphoreCreateBinary( xSemaphore ); 00102 if( xSemaphore != SYS_SEM_NULL ) 00103 { 00104 #if SYS_STATS 00105 lwip_stats.sys.sem.used++; 00106 if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max) { 00107 lwip_stats.sys.sem.max = lwip_stats.sys.sem.used; 00108 } 00109 #endif /* SYS_STATS */ 00110 00111 if( 0 == count ) // Means we want the sem to be unavailable at init state. 00112 { 00113 xSemaphoreTake( xSemaphore, 1); 00114 } 00115 } 00116 00117 portEXIT_CRITICAL(); 00118 00119 return xSemaphore; 00120 } 00121 00122 00123 // Frees a semaphore created by sys_sem_new. 00124 void sys_sem_free(sys_sem_t sem) 00125 { 00126 if( SYS_SEM_NULL != sem ) 00127 { 00128 #ifdef SYS_STATS 00129 lwip_stats.sys.sem.used--; 00130 #endif /* SYS_STATS */ 00131 vQueueDelete( sem ); 00132 } 00133 } 00134 00135 00136 // Signals (or releases) a semaphore. 00137 void sys_sem_signal(sys_sem_t sem) 00138 { 00139 xSemaphoreGive( sem ); 00140 } 00141 00142 // Blocks the thread while waiting for the semaphore to be signaled. The timeout 00143 // parameter specifies how many milliseconds the function should block before 00144 // returning; if the function times out, it should return SYS_ARCH_TIMEOUT. 00145 // If timeout=0, then the function should block indefinitely. 00146 // If the function acquires the semaphore, it should return how many milliseconds 00147 // expired while waiting for the semaphore. The function may return 0 if the 00148 // semaphore was immediately available. 00149 // 00150 // Note that there is another function sys_sem_wait in sys.c, but it is a wrapper 00151 // for the sys_arch_sem_wait function. Please note that it is important for the 00152 // semaphores to return an accurate count of elapsed milliseconds, since they are 00153 // used to schedule timers in lwIP. 00154 u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) 00155 { 00156 portTickType TickStart; 00157 portTickType TickStop; 00158 portTickType TickElapsed = (portTickType)(timeout*portTICK_RATE_MS); // Express the timeout in OS tick. 00159 00160 00161 // NOTE: we assume sem != SYS_SEM_NULL; iow, we assume the calling function 00162 // takes care of checking the sem validity before calling this function. 00163 00164 // NOTE: INCLUDE_xTaskGetSchedulerState must be set to 1 in FreeRTOSConfig.h 00165 // for xTaskGetTickCount() to be available. 00166 if( 0 == TickElapsed ) 00167 { 00168 TickStart = xTaskGetTickCount(); 00169 // If timeout=0, then the function should block indefinitely. 00170 while( pdFALSE == xSemaphoreTake( sem, SYS_ARCH_BLOCKING_TICKTIMEOUT ) ); 00171 } 00172 else 00173 { 00174 TickStart = xTaskGetTickCount(); 00175 if( pdFALSE == xSemaphoreTake( sem, TickElapsed ) ) 00176 // if the function times out, it should return SYS_ARCH_TIMEOUT. 00177 return( SYS_ARCH_TIMEOUT ); 00178 } 00179 // If the function acquires the semaphore, it should return how many milliseconds 00180 // expired while waiting for the semaphore. 00181 TickStop = xTaskGetTickCount(); 00182 // Take care of wrap-around. 00183 if( TickStop >= TickStart ) 00184 TickElapsed = TickStop - TickStart; 00185 else 00186 TickElapsed = portMAX_DELAY - TickStart + TickStop ; 00187 return( TASK_DELAY_MS( TickElapsed ) ); 00188 } 00189 00190 00191 00192 //----------- MAILBOXES -------------------------------------------------------- 00193 00194 // Creates an empty mailbox for maximum "size" elements. Elements stored in 00195 // mailboxes are pointers. 00196 // Return a new mailbox, or SYS_MBOX_NULL on error. 00197 sys_mbox_t sys_mbox_new( int size ) 00198 { 00199 sys_mbox_t mBoxNew; 00200 00201 00202 mBoxNew = xQueueCreate( size, sizeof( void * ) ); 00203 #if SYS_STATS 00204 if( SYS_MBOX_NULL != mBoxNew ) 00205 { 00206 lwip_stats.sys.mbox.used++; 00207 if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max) 00208 { 00209 lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used; 00210 } 00211 } 00212 #endif /* SYS_STATS */ 00213 return( mBoxNew ); 00214 } 00215 00216 00217 // Deallocates a mailbox. 00218 // If there are messages still present in the mailbox when the mailbox is 00219 // deallocated, it is an indication of a programming error in lwIP and the 00220 // developer should be notified. 00221 void sys_mbox_free(sys_mbox_t mbox) 00222 { 00223 if( SYS_MBOX_NULL != mbox ) 00224 { 00225 #ifdef SYS_STATS 00226 lwip_stats.sys.mbox.used--; 00227 #endif /* SYS_STATS */ 00228 vQueueDelete( mbox ); 00229 } 00230 } 00231 00232 00233 // Posts the "msg" to the mailbox. This function have to block until the "msg" 00234 // is really posted. 00235 void sys_mbox_post(sys_mbox_t mbox, void *msg) 00236 { 00237 // NOTE: we assume mbox != SYS_MBOX_NULL; iow, we assume the calling function 00238 // takes care of checking the mbox validity before calling this function. 00239 while( pdTRUE != xQueueSend( mbox, &msg, SYS_ARCH_BLOCKING_TICKTIMEOUT ) ); 00240 } 00241 00242 00243 // Try to post the "msg" to the mailbox. 00244 // Returns ERR_MEM if the mailbox is full, 00245 // else, ERR_OK if the "msg" is posted. 00246 err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg) 00247 { 00248 if( errQUEUE_FULL == xQueueSend( mbox, &msg, 0 ) ) 00249 return( ERR_MEM ); 00250 else 00251 return( ERR_OK ); 00252 } 00253 00254 00255 // Blocks the thread until a message arrives in the mailbox, but does not block 00256 // the thread longer than "timeout" milliseconds (similar to the sys_arch_sem_wait() 00257 // function). 00258 // If "timeout" is 0, the thread should be blocked until a message arrives. 00259 // The "msg" argument is a result parameter that is set by the function (i.e., by 00260 // doing "*msg = ptr"). The "msg" parameter maybe NULL to indicate that the message 00261 // should be dropped. 00262 // 00263 // The return values are the same as for the sys_arch_sem_wait() function: 00264 // Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a timeout. 00265 // 00266 // Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP. 00267 u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) 00268 { 00269 portTickType TickStart; 00270 portTickType TickStop; 00271 portTickType TickElapsed = (portTickType)(timeout*portTICK_RATE_MS); // Express the timeout in OS tick. 00272 void *tempoptr; 00273 00274 00275 // NOTE: we assume mbox != SYS_MBOX_NULL; iow, we assume the calling function 00276 // takes care of checking the mbox validity before calling this function. 00277 00278 if(msg == NULL) 00279 { 00280 msg = &tempoptr; 00281 } 00282 00283 // NOTE: INCLUDE_xTaskGetSchedulerState must be set to 1 in FreeRTOSConfig.h 00284 // for xTaskGetTickCount() to be available. 00285 if( 0 == TickElapsed ) 00286 { 00287 TickStart = xTaskGetTickCount(); 00288 // If "timeout" is 0, the thread should be blocked until a message arrives. 00289 while( pdFALSE == xQueueReceive( mbox, &(*msg), SYS_ARCH_BLOCKING_TICKTIMEOUT ) ); 00290 } 00291 else 00292 { 00293 TickStart = xTaskGetTickCount(); 00294 if( pdFALSE == xQueueReceive( mbox, &(*msg), TickElapsed ) ) 00295 { 00296 *msg = NULL; 00297 // if the function times out, it should return SYS_ARCH_TIMEOUT. 00298 return( SYS_ARCH_TIMEOUT ); 00299 } 00300 } 00301 // If the function gets a msg, it should return the number of ms spent waiting. 00302 TickStop = xTaskGetTickCount(); 00303 // Take care of wrap-around. 00304 if( TickStop >= TickStart ) 00305 TickElapsed = TickStop - TickStart; 00306 else 00307 TickElapsed = portMAX_DELAY - TickStart + TickStop ; 00308 return( TASK_DELAY_MS( TickElapsed ) ); 00309 } 00310 00311 00312 // This is similar to sys_arch_mbox_fetch, however if a message is not present 00313 // in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY. 00314 // On success 0 is returned. 00315 // 00316 u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) 00317 { 00318 void *tempoptr; 00319 00320 00321 if(msg == NULL) 00322 { 00323 msg = &tempoptr; 00324 } 00325 if( pdFALSE == xQueueReceive( mbox, &(*msg), 0 ) ) 00326 // if a message is not present in the mailbox, it immediately returns with 00327 // the code SYS_MBOX_EMPTY. 00328 return( SYS_MBOX_EMPTY ); 00329 // On success 0 is returned. 00330 return( 0 ); 00331 } 00332 00333 00334 00335 //----------- LWIP TIMEOUTS ---------------------------------------------------- 00336 00337 // Returns a pointer to the per-thread sys_timeouts structure. 00338 // In lwIP, each thread has a list of timeouts which is repressented as a linked 00339 // list of sys_timeout structures. The sys_timeouts structure holds a pointer to 00340 // a linked list of timeouts. This function is called by the lwIP timeout 00341 // scheduler and must not return a NULL value. 00342 struct sys_timeouts *sys_arch_timeouts(void) 00343 { 00344 int i; 00345 sys_thread_t pid; 00346 struct TimeoutlistPerThread *tl; 00347 00348 00349 // Get the current thread id. 00350 // Note: INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 in FreeRTOSConfig.h 00351 // for xTaskGetCurrentTaskHandle() to be available. 00352 pid = xTaskGetCurrentTaskHandle( ); 00353 00354 for(i = 0; i < NbActiveThreads; i++) 00355 { 00356 tl = &(Threads_TimeoutsList[i]); 00357 if(tl->pid == pid) 00358 { 00359 return &(tl->timeouts); 00360 } 00361 } 00362 00363 // If we're here, this means the scheduler gave the focus to the task as it was 00364 // being created(because of a higher priority). Since Threads_TimeoutsList[] 00365 // update is done just after the task creation, the array is not up-to-date. 00366 // => the last array entry must be the one of the current task. 00367 return( &(Threads_TimeoutsList[NbActiveThreads].timeouts) ); 00368 } 00369 00370 00371 // Used to instantiate a thread for lwIP. 00372 // Starts a new thread named "name" with priority "prio" that will begin its 00373 // execution in the function "thread()". The "arg" argument will be passed as an 00374 // argument to the thread() function. The stack size to used for this thread is 00375 // the "stacksize" parameter. The id of the new thread is returned. Both the id 00376 // and the priority are system dependent. 00377 00378 sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) 00379 { 00380 sys_thread_t newthread; 00381 portBASE_TYPE result; 00382 SYS_ARCH_DECL_PROTECT(protectionLevel); 00383 00384 result = xTaskCreate( thread, (signed portCHAR *)name, stacksize, arg, prio, &newthread ); 00385 00386 // Need to protect this -- preemption here could be a problem! 00387 SYS_ARCH_PROTECT(protectionLevel); 00388 if( pdPASS == result ) 00389 { 00390 // For each task created, store the task handle (pid) in the timers array. 00391 // This scheme doesn't allow for threads to be deleted 00392 Threads_TimeoutsList[NbActiveThreads++].pid = newthread; 00393 } 00394 else 00395 { 00396 newthread = NULL; 00397 } 00398 SYS_ARCH_UNPROTECT(protectionLevel); 00399 00400 return( newthread ); 00401 } 00402 00403 00404 00405 //----------- PREEMPTION PROTECTION -------------------------------------------- 00406 00407 // This optional function does a "fast" critical region protection and returns 00408 // the previous protection level. This function is only called during very short 00409 // critical regions. An embedded system which supports ISR-based drivers might 00410 // want to implement this function by disabling interrupts. Task-based systems 00411 // might want to implement this by using a mutex or disabling tasking. This 00412 // function should support recursive calls from the same task or interrupt. In 00413 // other words, sys_arch_protect() could be called while already protected. In 00414 // that case the return value indicates that it is already protected. 00415 extern volatile unsigned portLONG ulCriticalNesting; 00416 sys_prot_t sys_arch_protect(void) 00417 { 00418 vPortEnterCritical(); 00419 return 1; // Not used 00420 } 00421 00422 00423 // This optional function does a "fast" set of critical region protection to the 00424 // value specified by pval. 00425 void sys_arch_unprotect(sys_prot_t pval) 00426 { 00427 vPortExitCritical(); 00428 }
1.5.5