lwip operating system abstraction layer implementation based on CMSIS-RTOS
Dependents: LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more
sys_arch.c
00001 /* Copyright (C) 2012 mbed.org, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00005 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00006 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00007 * furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 #include <string.h> 00019 00020 /* mbed includes */ 00021 #include "mbed_error.h" 00022 #include "mbed_interface.h" 00023 #include "us_ticker_api.h" 00024 00025 /* lwIP includes. */ 00026 #include "lwip/opt.h" 00027 #include "lwip/debug.h" 00028 #include "lwip/def.h" 00029 #include "lwip/sys.h" 00030 #include "lwip/mem.h" 00031 00032 #if NO_SYS==1 00033 #include "cmsis.h" 00034 00035 /* Saved total time in ms since timer was enabled */ 00036 static volatile u32_t systick_timems; 00037 00038 /* Enable systick rate and interrupt */ 00039 void SysTick_Init(void) { 00040 if (SysTick_Config(SystemCoreClock / 1000)) { 00041 while (1); /* Capture error */ 00042 } 00043 } 00044 00045 /** \brief SysTick IRQ handler and timebase management 00046 * 00047 * This function keeps a timebase for the sysTick that can be 00048 * used for other functions. It also calls an external function 00049 * (SysTick_User) that must be defined outside this handler. 00050 */ 00051 void SysTick_Handler(void) { 00052 systick_timems++; 00053 } 00054 00055 /* Delay for the specified number of milliSeconds */ 00056 void osDelay(uint32_t ms) { 00057 uint32_t to = ms + systick_timems; 00058 while (to > systick_timems); 00059 } 00060 00061 /* Returns the current time in mS. This is needed for the LWIP timers */ 00062 u32_t sys_now(void) { 00063 return (u32_t) systick_timems; 00064 } 00065 00066 #else 00067 /* CMSIS-RTOS implementation of the lwip operating system abstraction */ 00068 #include "arch/sys_arch.h" 00069 00070 /*---------------------------------------------------------------------------* 00071 * Routine: sys_mbox_new 00072 *---------------------------------------------------------------------------* 00073 * Description: 00074 * Creates a new mailbox 00075 * Inputs: 00076 * sys_mbox_t mbox -- Handle of mailbox 00077 * int queue_sz -- Size of elements in the mailbox 00078 * Outputs: 00079 * err_t -- ERR_OK if message posted, else ERR_MEM 00080 *---------------------------------------------------------------------------*/ 00081 err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) { 00082 if (queue_sz > MB_SIZE) 00083 error("sys_mbox_new size error\n"); 00084 00085 #ifdef CMSIS_OS_RTX 00086 memset(mbox->queue, 0, sizeof(mbox->queue)); 00087 mbox->def.pool = mbox->queue; 00088 mbox->def.queue_sz = queue_sz; 00089 #endif 00090 mbox->id = osMessageCreate(&mbox->def, NULL); 00091 return (mbox->id == NULL) ? (ERR_MEM) : (ERR_OK); 00092 } 00093 00094 /*---------------------------------------------------------------------------* 00095 * Routine: sys_mbox_free 00096 *---------------------------------------------------------------------------* 00097 * Description: 00098 * Deallocates a mailbox. If there are messages still present in the 00099 * mailbox when the mailbox is deallocated, it is an indication of a 00100 * programming error in lwIP and the developer should be notified. 00101 * Inputs: 00102 * sys_mbox_t *mbox -- Handle of mailbox 00103 *---------------------------------------------------------------------------*/ 00104 void sys_mbox_free(sys_mbox_t *mbox) { 00105 osEvent event = osMessageGet(mbox->id, 0); 00106 if (event.status == osEventMessage) 00107 error("sys_mbox_free error\n"); 00108 } 00109 00110 /*---------------------------------------------------------------------------* 00111 * Routine: sys_mbox_post 00112 *---------------------------------------------------------------------------* 00113 * Description: 00114 * Post the "msg" to the mailbox. 00115 * Inputs: 00116 * sys_mbox_t mbox -- Handle of mailbox 00117 * void *msg -- Pointer to data to post 00118 *---------------------------------------------------------------------------*/ 00119 void sys_mbox_post(sys_mbox_t *mbox, void *msg) { 00120 if (osMessagePut(mbox->id, (uint32_t)msg, osWaitForever) != osOK) 00121 error("sys_mbox_post error\n"); 00122 } 00123 00124 /*---------------------------------------------------------------------------* 00125 * Routine: sys_mbox_trypost 00126 *---------------------------------------------------------------------------* 00127 * Description: 00128 * Try to post the "msg" to the mailbox. Returns immediately with 00129 * error if cannot. 00130 * Inputs: 00131 * sys_mbox_t mbox -- Handle of mailbox 00132 * void *msg -- Pointer to data to post 00133 * Outputs: 00134 * err_t -- ERR_OK if message posted, else ERR_MEM 00135 * if not. 00136 *---------------------------------------------------------------------------*/ 00137 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { 00138 osStatus status = osMessagePut(mbox->id, (uint32_t)msg, 0); 00139 return (status == osOK) ? (ERR_OK) : (ERR_MEM); 00140 } 00141 00142 /*---------------------------------------------------------------------------* 00143 * Routine: sys_arch_mbox_fetch 00144 *---------------------------------------------------------------------------* 00145 * Description: 00146 * Blocks the thread until a message arrives in the mailbox, but does 00147 * not block the thread longer than "timeout" milliseconds (similar to 00148 * the sys_arch_sem_wait() function). The "msg" argument is a result 00149 * parameter that is set by the function (i.e., by doing "*msg = 00150 * ptr"). The "msg" parameter maybe NULL to indicate that the message 00151 * should be dropped. 00152 * 00153 * The return values are the same as for the sys_arch_sem_wait() function: 00154 * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a 00155 * timeout. 00156 * 00157 * Note that a function with a similar name, sys_mbox_fetch(), is 00158 * implemented by lwIP. 00159 * Inputs: 00160 * sys_mbox_t mbox -- Handle of mailbox 00161 * void **msg -- Pointer to pointer to msg received 00162 * u32_t timeout -- Number of milliseconds until timeout 00163 * Outputs: 00164 * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number 00165 * of milliseconds until received. 00166 *---------------------------------------------------------------------------*/ 00167 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { 00168 u32_t start = us_ticker_read(); 00169 00170 osEvent event = osMessageGet(mbox->id, (timeout != 0)?(timeout):(osWaitForever)); 00171 if (event.status != osEventMessage) 00172 return SYS_ARCH_TIMEOUT; 00173 00174 *msg = (void *)event.value.v; 00175 00176 return (us_ticker_read() - start) / 1000; 00177 } 00178 00179 /*---------------------------------------------------------------------------* 00180 * Routine: sys_arch_mbox_tryfetch 00181 *---------------------------------------------------------------------------* 00182 * Description: 00183 * Similar to sys_arch_mbox_fetch, but if message is not ready 00184 * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is 00185 * returned. 00186 * Inputs: 00187 * sys_mbox_t mbox -- Handle of mailbox 00188 * void **msg -- Pointer to pointer to msg received 00189 * Outputs: 00190 * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise, 00191 * return ERR_OK. 00192 *---------------------------------------------------------------------------*/ 00193 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) { 00194 osEvent event = osMessageGet(mbox->id, 0); 00195 if (event.status != osEventMessage) 00196 return SYS_MBOX_EMPTY; 00197 00198 *msg = (void *)event.value.v; 00199 00200 return ERR_OK; 00201 } 00202 00203 /*---------------------------------------------------------------------------* 00204 * Routine: sys_sem_new 00205 *---------------------------------------------------------------------------* 00206 * Description: 00207 * Creates and returns a new semaphore. The "ucCount" argument specifies 00208 * the initial state of the semaphore. 00209 * NOTE: Currently this routine only creates counts of 1 or 0 00210 * Inputs: 00211 * sys_sem_t sem -- Handle of semaphore 00212 * u8_t count -- Initial count of semaphore 00213 * Outputs: 00214 * err_t -- ERR_OK if semaphore created 00215 *---------------------------------------------------------------------------*/ 00216 err_t sys_sem_new(sys_sem_t *sem, u8_t count) { 00217 #ifdef CMSIS_OS_RTX 00218 memset(sem->data, 0, sizeof(uint32_t)*2); 00219 sem->def.semaphore = sem->data; 00220 #endif 00221 sem->id = osSemaphoreCreate(&sem->def, count); 00222 if (sem->id == NULL) 00223 error("sys_sem_new create error\n"); 00224 00225 return ERR_OK; 00226 } 00227 00228 /*---------------------------------------------------------------------------* 00229 * Routine: sys_arch_sem_wait 00230 *---------------------------------------------------------------------------* 00231 * Description: 00232 * Blocks the thread while waiting for the semaphore to be 00233 * signaled. If the "timeout" argument is non-zero, the thread should 00234 * only be blocked for the specified time (measured in 00235 * milliseconds). 00236 * 00237 * If the timeout argument is non-zero, the return value is the number of 00238 * milliseconds spent waiting for the semaphore to be signaled. If the 00239 * semaphore wasn't signaled within the specified time, the return value is 00240 * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore 00241 * (i.e., it was already signaled), the function may return zero. 00242 * 00243 * Notice that lwIP implements a function with a similar name, 00244 * sys_sem_wait(), that uses the sys_arch_sem_wait() function. 00245 * Inputs: 00246 * sys_sem_t sem -- Semaphore to wait on 00247 * u32_t timeout -- Number of milliseconds until timeout 00248 * Outputs: 00249 * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT. 00250 *---------------------------------------------------------------------------*/ 00251 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { 00252 u32_t start = us_ticker_read(); 00253 00254 if (osSemaphoreWait(sem->id, (timeout != 0)?(timeout):(osWaitForever)) < 1) 00255 return SYS_ARCH_TIMEOUT; 00256 00257 return (us_ticker_read() - start) / 1000; 00258 } 00259 00260 /*---------------------------------------------------------------------------* 00261 * Routine: sys_sem_signal 00262 *---------------------------------------------------------------------------* 00263 * Description: 00264 * Signals (releases) a semaphore 00265 * Inputs: 00266 * sys_sem_t sem -- Semaphore to signal 00267 *---------------------------------------------------------------------------*/ 00268 void sys_sem_signal(sys_sem_t *data) { 00269 if (osSemaphoreRelease(data->id) != osOK) 00270 mbed_die(); /* Can be called by ISR do not use printf */ 00271 } 00272 00273 /*---------------------------------------------------------------------------* 00274 * Routine: sys_sem_free 00275 *---------------------------------------------------------------------------* 00276 * Description: 00277 * Deallocates a semaphore 00278 * Inputs: 00279 * sys_sem_t sem -- Semaphore to free 00280 *---------------------------------------------------------------------------*/ 00281 void sys_sem_free(sys_sem_t *sem) {} 00282 00283 /** Create a new mutex 00284 * @param mutex pointer to the mutex to create 00285 * @return a new mutex */ 00286 err_t sys_mutex_new(sys_mutex_t *mutex) { 00287 #ifdef CMSIS_OS_RTX 00288 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM) 00289 memset(mutex->data, 0, sizeof(int32_t)*4); 00290 #else 00291 memset(mutex->data, 0, sizeof(int32_t)*3); 00292 #endif 00293 mutex->def.mutex = mutex->data; 00294 #endif 00295 mutex->id = osMutexCreate(&mutex->def); 00296 if (mutex->id == NULL) 00297 return ERR_MEM; 00298 00299 return ERR_OK; 00300 } 00301 00302 /** Lock a mutex 00303 * @param mutex the mutex to lock */ 00304 void sys_mutex_lock(sys_mutex_t *mutex) { 00305 if (osMutexWait(mutex->id, osWaitForever) != osOK) 00306 error("sys_mutex_lock error\n"); 00307 } 00308 00309 /** Unlock a mutex 00310 * @param mutex the mutex to unlock */ 00311 void sys_mutex_unlock(sys_mutex_t *mutex) { 00312 if (osMutexRelease(mutex->id) != osOK) 00313 error("sys_mutex_unlock error\n"); 00314 } 00315 00316 /** Delete a mutex 00317 * @param mutex the mutex to delete */ 00318 void sys_mutex_free(sys_mutex_t *mutex) {} 00319 00320 /*---------------------------------------------------------------------------* 00321 * Routine: sys_init 00322 *---------------------------------------------------------------------------* 00323 * Description: 00324 * Initialize sys arch 00325 *---------------------------------------------------------------------------*/ 00326 osMutexId lwip_sys_mutex; 00327 osMutexDef(lwip_sys_mutex); 00328 00329 void sys_init(void) { 00330 us_ticker_read(); // Init sys tick 00331 lwip_sys_mutex = osMutexCreate(osMutex(lwip_sys_mutex)); 00332 if (lwip_sys_mutex == NULL) 00333 error("sys_init error\n"); 00334 } 00335 00336 /*---------------------------------------------------------------------------* 00337 * Routine: sys_jiffies 00338 *---------------------------------------------------------------------------* 00339 * Description: 00340 * Used by PPP as a timestamp-ish value 00341 *---------------------------------------------------------------------------*/ 00342 u32_t sys_jiffies(void) { 00343 static u32_t jiffies = 0; 00344 jiffies += 1 + (us_ticker_read()/10000); 00345 return jiffies; 00346 } 00347 00348 /*---------------------------------------------------------------------------* 00349 * Routine: sys_arch_protect 00350 *---------------------------------------------------------------------------* 00351 * Description: 00352 * This optional function does a "fast" critical region protection and 00353 * returns the previous protection level. This function is only called 00354 * during very short critical regions. An embedded system which supports 00355 * ISR-based drivers might want to implement this function by disabling 00356 * interrupts. Task-based systems might want to implement this by using 00357 * a mutex or disabling tasking. This function should support recursive 00358 * calls from the same task or interrupt. In other words, 00359 * sys_arch_protect() could be called while already protected. In 00360 * that case the return value indicates that it is already protected. 00361 * 00362 * sys_arch_protect() is only required if your port is supporting an 00363 * operating system. 00364 * Outputs: 00365 * sys_prot_t -- Previous protection level (not used here) 00366 *---------------------------------------------------------------------------*/ 00367 sys_prot_t sys_arch_protect(void) { 00368 if (osMutexWait(lwip_sys_mutex, osWaitForever) != osOK) 00369 error("sys_arch_protect error\n"); 00370 return (sys_prot_t) 1; 00371 } 00372 00373 /*---------------------------------------------------------------------------* 00374 * Routine: sys_arch_unprotect 00375 *---------------------------------------------------------------------------* 00376 * Description: 00377 * This optional function does a "fast" set of critical region 00378 * protection to the value specified by pval. See the documentation for 00379 * sys_arch_protect() for more information. This function is only 00380 * required if your port is supporting an operating system. 00381 * Inputs: 00382 * sys_prot_t -- Previous protection level (not used here) 00383 *---------------------------------------------------------------------------*/ 00384 void sys_arch_unprotect(sys_prot_t p) { 00385 if (osMutexRelease(lwip_sys_mutex) != osOK) 00386 error("sys_arch_unprotect error\n"); 00387 } 00388 00389 u32_t sys_now(void) { 00390 return us_ticker_read() / 1000; 00391 } 00392 00393 void sys_msleep(u32_t ms) { 00394 osDelay(ms); 00395 } 00396 00397 // Keep a pool of thread structures 00398 static int thread_pool_index = 0; 00399 static sys_thread_data_t thread_pool[SYS_THREAD_POOL_N]; 00400 00401 /*---------------------------------------------------------------------------* 00402 * Routine: sys_thread_new 00403 *---------------------------------------------------------------------------* 00404 * Description: 00405 * Starts a new thread with priority "prio" that will begin its 00406 * execution in the function "thread()". The "arg" argument will be 00407 * passed as an argument to the thread() function. The id of the new 00408 * thread is returned. Both the id and the priority are system 00409 * dependent. 00410 * Inputs: 00411 * char *name -- Name of thread 00412 * void (*thread)(void *arg) -- Pointer to function to run. 00413 * void *arg -- Argument passed into function 00414 * int stacksize -- Required stack amount in bytes 00415 * int priority -- Thread priority 00416 * Outputs: 00417 * sys_thread_t -- Pointer to thread handle. 00418 *---------------------------------------------------------------------------*/ 00419 sys_thread_t sys_thread_new(const char *pcName, 00420 void (*thread)(void *arg), 00421 void *arg, int stacksize, int priority) { 00422 LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName)); 00423 00424 if (thread_pool_index >= SYS_THREAD_POOL_N) 00425 error("sys_thread_new number error\n"); 00426 sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index]; 00427 thread_pool_index++; 00428 00429 #ifdef CMSIS_OS_RTX 00430 t->def.pthread = (os_pthread)thread; 00431 t->def.tpriority = (osPriority)priority; 00432 t->def.stacksize = stacksize; 00433 t->def.stack_pointer = (uint32_t*)malloc(stacksize); 00434 if (t->def.stack_pointer == NULL) { 00435 error("Error allocating the stack memory"); 00436 } 00437 #endif 00438 t->id = osThreadCreate(&t->def, arg); 00439 if (t->id == NULL) 00440 error("sys_thread_new create error\n"); 00441 00442 return t; 00443 } 00444 00445 #endif 00446 00447 #ifdef LWIP_DEBUG 00448 00449 /** \brief Displays an error message on assertion 00450 00451 This function will display an error message on an assertion 00452 to the debug output. 00453 00454 \param[in] msg Error message to display 00455 \param[in] line Line number in file with error 00456 \param[in] file Filename with error 00457 */ 00458 void assert_printf(char *msg, int line, char *file) { 00459 if (msg) 00460 error("%s:%d in file %s\n", msg, line, file); 00461 else 00462 error("LWIP ASSERT\n"); 00463 } 00464 00465 #endif /* LWIP_DEBUG */
Generated on Tue Jul 12 2022 18:38:06 by
