1 /* Copyright (C) 2012 mbed.org, MIT License
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 #include "mbed_error.h"
22 #include "mbed_interface.h"
23 #include "us_ticker_api.h"
27 #include "lwip/debug.h"
35 /* Saved total time in ms since timer was enabled */
36 static volatile u32_t systick_timems
;
38 /* Enable systick rate and interrupt */
39 void SysTick_Init(void) {
40 if (SysTick_Config(SystemCoreClock
/ 1000)) {
41 while (1); /* Capture error */
45 /** \brief SysTick IRQ handler and timebase management
47 * This function keeps a timebase for the sysTick that can be
48 * used for other functions. It also calls an external function
49 * (SysTick_User) that must be defined outside this handler.
51 void SysTick_Handler(void) {
55 /* Delay for the specified number of milliSeconds */
56 void osDelay(uint32_t ms
) {
57 uint32_t to
= ms
+ systick_timems
;
58 while (to
> systick_timems
);
61 /* Returns the current time in mS. This is needed for the LWIP timers */
63 return (u32_t
) systick_timems
;
67 /* CMSIS-RTOS implementation of the lwip operating system abstraction */
68 #include "arch/sys_arch.h"
70 /*---------------------------------------------------------------------------*
71 * Routine: sys_mbox_new
72 *---------------------------------------------------------------------------*
74 * Creates a new mailbox
76 * sys_mbox_t mbox -- Handle of mailbox
77 * int queue_sz -- Size of elements in the mailbox
79 * err_t -- ERR_OK if message posted, else ERR_MEM
80 *---------------------------------------------------------------------------*/
81 err_t
sys_mbox_new(sys_mbox_t
*mbox
, int queue_sz
) {
82 if (queue_sz
> MB_SIZE
)
83 error("sys_mbox_new size error\n");
86 memset(mbox
->queue
, 0, sizeof(mbox
->queue
));
87 mbox
->def
.pool
= mbox
->queue
;
88 mbox
->def
.queue_sz
= queue_sz
;
90 mbox
->id
= osMessageCreate(&mbox
->def
, NULL
);
91 return (mbox
->id
== NULL
) ? (ERR_MEM
) : (ERR_OK
);
94 /*---------------------------------------------------------------------------*
95 * Routine: sys_mbox_free
96 *---------------------------------------------------------------------------*
98 * Deallocates a mailbox. If there are messages still present in the
99 * mailbox when the mailbox is deallocated, it is an indication of a
100 * programming error in lwIP and the developer should be notified.
102 * sys_mbox_t *mbox -- Handle of mailbox
103 *---------------------------------------------------------------------------*/
104 void sys_mbox_free(sys_mbox_t
*mbox
) {
105 osEvent event
= osMessageGet(mbox
->id
, 0);
106 if (event
.status
== osEventMessage
)
107 error("sys_mbox_free error\n");
110 /*---------------------------------------------------------------------------*
111 * Routine: sys_mbox_post
112 *---------------------------------------------------------------------------*
114 * Post the "msg" to the mailbox.
116 * sys_mbox_t mbox -- Handle of mailbox
117 * void *msg -- Pointer to data to post
118 *---------------------------------------------------------------------------*/
119 void sys_mbox_post(sys_mbox_t
*mbox
, void *msg
) {
120 if (osMessagePut(mbox
->id
, (uint32_t)msg
, osWaitForever
) != osOK
)
121 error("sys_mbox_post error\n");
124 /*---------------------------------------------------------------------------*
125 * Routine: sys_mbox_trypost
126 *---------------------------------------------------------------------------*
128 * Try to post the "msg" to the mailbox. Returns immediately with
131 * sys_mbox_t mbox -- Handle of mailbox
132 * void *msg -- Pointer to data to post
134 * err_t -- ERR_OK if message posted, else ERR_MEM
136 *---------------------------------------------------------------------------*/
137 err_t
sys_mbox_trypost(sys_mbox_t
*mbox
, void *msg
) {
138 osStatus status
= osMessagePut(mbox
->id
, (uint32_t)msg
, 0);
139 return (status
== osOK
) ? (ERR_OK
) : (ERR_MEM
);
142 /*---------------------------------------------------------------------------*
143 * Routine: sys_arch_mbox_fetch
144 *---------------------------------------------------------------------------*
146 * Blocks the thread until a message arrives in the mailbox, but does
147 * not block the thread longer than "timeout" milliseconds (similar to
148 * the sys_arch_sem_wait() function). The "msg" argument is a result
149 * parameter that is set by the function (i.e., by doing "*msg =
150 * ptr"). The "msg" parameter maybe NULL to indicate that the message
153 * The return values are the same as for the sys_arch_sem_wait() function:
154 * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
157 * Note that a function with a similar name, sys_mbox_fetch(), is
158 * implemented by lwIP.
160 * sys_mbox_t mbox -- Handle of mailbox
161 * void **msg -- Pointer to pointer to msg received
162 * u32_t timeout -- Number of milliseconds until timeout
164 * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number
165 * of milliseconds until received.
166 *---------------------------------------------------------------------------*/
167 u32_t
sys_arch_mbox_fetch(sys_mbox_t
*mbox
, void **msg
, u32_t timeout
) {
168 u32_t start
= us_ticker_read();
170 osEvent event
= osMessageGet(mbox
->id
, (timeout
!= 0)?(timeout
):(osWaitForever
));
171 if (event
.status
!= osEventMessage
)
172 return SYS_ARCH_TIMEOUT
;
174 *msg
= (void *)event
.value
.v
;
176 return (us_ticker_read() - start
) / 1000;
179 /*---------------------------------------------------------------------------*
180 * Routine: sys_arch_mbox_tryfetch
181 *---------------------------------------------------------------------------*
183 * Similar to sys_arch_mbox_fetch, but if message is not ready
184 * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is
187 * sys_mbox_t mbox -- Handle of mailbox
188 * void **msg -- Pointer to pointer to msg received
190 * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,
192 *---------------------------------------------------------------------------*/
193 u32_t
sys_arch_mbox_tryfetch(sys_mbox_t
*mbox
, void **msg
) {
194 osEvent event
= osMessageGet(mbox
->id
, 0);
195 if (event
.status
!= osEventMessage
)
196 return SYS_MBOX_EMPTY
;
198 *msg
= (void *)event
.value
.v
;
203 /*---------------------------------------------------------------------------*
204 * Routine: sys_sem_new
205 *---------------------------------------------------------------------------*
207 * Creates and returns a new semaphore. The "ucCount" argument specifies
208 * the initial state of the semaphore.
209 * NOTE: Currently this routine only creates counts of 1 or 0
211 * sys_sem_t sem -- Handle of semaphore
212 * u8_t count -- Initial count of semaphore
214 * err_t -- ERR_OK if semaphore created
215 *---------------------------------------------------------------------------*/
216 err_t
sys_sem_new(sys_sem_t
*sem
, u8_t count
) {
218 memset(sem
->data
, 0, sizeof(uint32_t)*2);
219 sem
->def
.semaphore
= sem
->data
;
221 sem
->id
= osSemaphoreCreate(&sem
->def
, count
);
223 error("sys_sem_new create error\n");
228 /*---------------------------------------------------------------------------*
229 * Routine: sys_arch_sem_wait
230 *---------------------------------------------------------------------------*
232 * Blocks the thread while waiting for the semaphore to be
233 * signaled. If the "timeout" argument is non-zero, the thread should
234 * only be blocked for the specified time (measured in
237 * If the timeout argument is non-zero, the return value is the number of
238 * milliseconds spent waiting for the semaphore to be signaled. If the
239 * semaphore wasn't signaled within the specified time, the return value is
240 * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
241 * (i.e., it was already signaled), the function may return zero.
243 * Notice that lwIP implements a function with a similar name,
244 * sys_sem_wait(), that uses the sys_arch_sem_wait() function.
246 * sys_sem_t sem -- Semaphore to wait on
247 * u32_t timeout -- Number of milliseconds until timeout
249 * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.
250 *---------------------------------------------------------------------------*/
251 u32_t
sys_arch_sem_wait(sys_sem_t
*sem
, u32_t timeout
) {
252 u32_t start
= us_ticker_read();
254 if (osSemaphoreWait(sem
->id
, (timeout
!= 0)?(timeout
):(osWaitForever
)) < 1)
255 return SYS_ARCH_TIMEOUT
;
257 return (us_ticker_read() - start
) / 1000;
260 /*---------------------------------------------------------------------------*
261 * Routine: sys_sem_signal
262 *---------------------------------------------------------------------------*
264 * Signals (releases) a semaphore
266 * sys_sem_t sem -- Semaphore to signal
267 *---------------------------------------------------------------------------*/
268 void sys_sem_signal(sys_sem_t
*data
) {
269 if (osSemaphoreRelease(data
->id
) != osOK
)
270 mbed_die(); /* Can be called by ISR do not use printf */
273 /*---------------------------------------------------------------------------*
274 * Routine: sys_sem_free
275 *---------------------------------------------------------------------------*
277 * Deallocates a semaphore
279 * sys_sem_t sem -- Semaphore to free
280 *---------------------------------------------------------------------------*/
281 void sys_sem_free(sys_sem_t
*sem
) {}
283 /** Create a new mutex
284 * @param mutex pointer to the mutex to create
285 * @return a new mutex */
286 err_t
sys_mutex_new(sys_mutex_t
*mutex
) {
288 memset(mutex
->data
, 0, sizeof(int32_t)*3);
289 mutex
->def
.mutex
= mutex
->data
;
291 mutex
->id
= osMutexCreate(&mutex
->def
);
292 if (mutex
->id
== NULL
)
299 * @param mutex the mutex to lock */
300 void sys_mutex_lock(sys_mutex_t
*mutex
) {
301 if (osMutexWait(mutex
->id
, osWaitForever
) != osOK
)
302 error("sys_mutex_lock error\n");
306 * @param mutex the mutex to unlock */
307 void sys_mutex_unlock(sys_mutex_t
*mutex
) {
308 if (osMutexRelease(mutex
->id
) != osOK
)
309 error("sys_mutex_unlock error\n");
313 * @param mutex the mutex to delete */
314 void sys_mutex_free(sys_mutex_t
*mutex
) {}
316 /*---------------------------------------------------------------------------*
318 *---------------------------------------------------------------------------*
320 * Initialize sys arch
321 *---------------------------------------------------------------------------*/
322 osMutexId lwip_sys_mutex
;
323 osMutexDef(lwip_sys_mutex
);
325 void sys_init(void) {
326 us_ticker_read(); // Init sys tick
327 lwip_sys_mutex
= osMutexCreate(osMutex(lwip_sys_mutex
));
328 if (lwip_sys_mutex
== NULL
)
329 error("sys_init error\n");
332 /*---------------------------------------------------------------------------*
333 * Routine: sys_jiffies
334 *---------------------------------------------------------------------------*
336 * Used by PPP as a timestamp-ish value
337 *---------------------------------------------------------------------------*/
338 u32_t
sys_jiffies(void) {
339 static u32_t jiffies
= 0;
340 jiffies
+= 1 + (us_ticker_read()/10000);
344 /*---------------------------------------------------------------------------*
345 * Routine: sys_arch_protect
346 *---------------------------------------------------------------------------*
348 * This optional function does a "fast" critical region protection and
349 * returns the previous protection level. This function is only called
350 * during very short critical regions. An embedded system which supports
351 * ISR-based drivers might want to implement this function by disabling
352 * interrupts. Task-based systems might want to implement this by using
353 * a mutex or disabling tasking. This function should support recursive
354 * calls from the same task or interrupt. In other words,
355 * sys_arch_protect() could be called while already protected. In
356 * that case the return value indicates that it is already protected.
358 * sys_arch_protect() is only required if your port is supporting an
361 * sys_prot_t -- Previous protection level (not used here)
362 *---------------------------------------------------------------------------*/
363 sys_prot_t
sys_arch_protect(void) {
364 if (osMutexWait(lwip_sys_mutex
, osWaitForever
) != osOK
)
365 error("sys_arch_protect error\n");
366 return (sys_prot_t
) 1;
369 /*---------------------------------------------------------------------------*
370 * Routine: sys_arch_unprotect
371 *---------------------------------------------------------------------------*
373 * This optional function does a "fast" set of critical region
374 * protection to the value specified by pval. See the documentation for
375 * sys_arch_protect() for more information. This function is only
376 * required if your port is supporting an operating system.
378 * sys_prot_t -- Previous protection level (not used here)
379 *---------------------------------------------------------------------------*/
380 void sys_arch_unprotect(sys_prot_t p
) {
381 if (osMutexRelease(lwip_sys_mutex
) != osOK
)
382 error("sys_arch_unprotect error\n");
385 u32_t
sys_now(void) {
386 return us_ticker_read() / 1000;
389 void sys_msleep(u32_t ms
) {
393 // Keep a pool of thread structures
394 static int thread_pool_index
= 0;
395 static sys_thread_data_t thread_pool
[SYS_THREAD_POOL_N
];
397 /*---------------------------------------------------------------------------*
398 * Routine: sys_thread_new
399 *---------------------------------------------------------------------------*
401 * Starts a new thread with priority "prio" that will begin its
402 * execution in the function "thread()". The "arg" argument will be
403 * passed as an argument to the thread() function. The id of the new
404 * thread is returned. Both the id and the priority are system
407 * char *name -- Name of thread
408 * void (*thread)(void *arg) -- Pointer to function to run.
409 * void *arg -- Argument passed into function
410 * int stacksize -- Required stack amount in bytes
411 * int priority -- Thread priority
413 * sys_thread_t -- Pointer to thread handle.
414 *---------------------------------------------------------------------------*/
415 sys_thread_t
sys_thread_new(const char *pcName
,
416 void (*thread
)(void *arg
),
417 void *arg
, int stacksize
, int priority
) {
418 LWIP_DEBUGF(SYS_DEBUG
, ("New Thread: %s\n", pcName
));
420 if (thread_pool_index
>= SYS_THREAD_POOL_N
)
421 error("sys_thread_new number error\n");
422 sys_thread_t t
= (sys_thread_t
)&thread_pool
[thread_pool_index
];
426 t
->def
.pthread
= (os_pthread
)thread
;
427 t
->def
.tpriority
= (osPriority
)priority
;
428 t
->def
.stacksize
= stacksize
;
429 #ifndef __MBED_CMSIS_RTOS_CA9
430 t
->def
.stack_pointer
= (uint32_t*)malloc(stacksize
);
431 if (t
->def
.stack_pointer
== NULL
) {
432 error("Error allocating the stack memory");
436 t
->id
= osThreadCreate(&t
->def
, arg
);
438 error("sys_thread_new create error\n");
447 /** \brief Displays an error message on assertion
449 This function will display an error message on an assertion
452 \param[in] msg Error message to display
453 \param[in] line Line number in file with error
454 \param[in] file Filename with error
456 void assert_printf(char *msg
, int line
, char *file
) {
458 error("%s:%d in file %s\n", msg
, line
, file
);
460 error("LWIP ASSERT\n");
463 #endif /* LWIP_DEBUG */