os_port_ucos3.c
Go to the documentation of this file.
1 /**
2  * @file os_port_ucos3.c
3  * @brief RTOS abstraction layer (Micrium uC/OS-III)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.6
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL TRACE_LEVEL_OFF
31 
32 //Dependencies
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include "os_port.h"
37 #include "os_port_ucos3.h"
38 #include "debug.h"
39 
40 //Forward declaration of functions
41 void osIdleTaskHook(void);
42 
43 //Variables
44 static OS_TCB *tcbTable[OS_PORT_MAX_TASKS];
45 static CPU_STK *stkTable[OS_PORT_MAX_TASKS];
46 
47 
48 /**
49  * @brief Kernel initialization
50  **/
51 
52 void osInitKernel(void)
53 {
54  OS_ERR err;
55 
56  //Initialize tables
57  memset(tcbTable, 0, sizeof(tcbTable));
58  memset(stkTable, 0, sizeof(stkTable));
59 
60  //Scheduler initialization
61  OSInit(&err);
62 
63  //Set idle task hook
64  OS_AppIdleTaskHookPtr = osIdleTaskHook;
65 }
66 
67 
68 /**
69  * @brief Start kernel
70  **/
71 
72 void osStartKernel(void)
73 {
74  OS_ERR err;
75 
76  //Start the scheduler
77  OSStart(&err);
78 }
79 
80 
81 /**
82  * @brief Create a static task
83  * @param[out] task Pointer to the task structure
84  * @param[in] name A name identifying the task
85  * @param[in] taskCode Pointer to the task entry function
86  * @param[in] param A pointer to a variable to be passed to the task
87  * @param[in] stack Pointer to the stack
88  * @param[in] stackSize The initial size of the stack, in words
89  * @param[in] priority The priority at which the task should run
90  * @return The function returns TRUE if the task was successfully
91  * created. Otherwise, FALSE is returned
92  **/
93 
95  void *param, void *stack, size_t stackSize, int_t priority)
96 {
97  OS_ERR err;
98  CPU_STK stackLimit;
99 
100  //The watermark limit is used to monitor and ensure that the stack does not overflow
101  stackLimit = stackSize / 10;
102 
103  //Create a new task
104  OSTaskCreate(task, (CPU_CHAR *) name, taskCode, param,
105  priority, stack, stackLimit, stackSize, 0, 1, NULL,
106  OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err);
107 
108  //Check whether the task was successfully created
109  if(err == OS_ERR_NONE)
110  return TRUE;
111  else
112  return FALSE;
113 }
114 
115 
116 /**
117  * @brief Create a new task
118  * @param[in] name A name identifying the task
119  * @param[in] taskCode Pointer to the task entry function
120  * @param[in] param A pointer to a variable to be passed to the task
121  * @param[in] stackSize The initial size of the stack, in words
122  * @param[in] priority The priority at which the task should run
123  * @return If the function succeeds, the return value is a pointer to the
124  * new task. If the function fails, the return value is NULL
125  **/
126 
128  void *param, size_t stackSize, int_t priority)
129 {
130  OS_ERR err;
131  CPU_INT32U i;
132  CPU_STK stackLimit;
133  OS_TCB *task;
134  CPU_STK *stack;
135 
136  //The watermark limit is used to monitor and ensure that the stack does not overflow
137  stackLimit = stackSize / 10;
138 
139  //Enter critical section
141 
142  //Loop through TCB table
143  for(i = 0; i < OS_PORT_MAX_TASKS; i++)
144  {
145  //Check whether the current entry is free
146  if(tcbTable[i] == NULL)
147  break;
148  }
149 
150  //Any entry available in the table?
151  if(i < OS_PORT_MAX_TASKS)
152  {
153  //Allocate a memory block to hold the task's control block
154  task = osAllocMem(sizeof(OS_TCB));
155 
156  //Successful memory allocation?
157  if(task != NULL)
158  {
159  //Allocate a memory block to hold the task's stack
160  stack = osAllocMem(stackSize * sizeof(CPU_STK));
161 
162  //Successful memory allocation?
163  if(stack != NULL)
164  {
165  //Create a new task
166  OSTaskCreate(task, (CPU_CHAR *) name, taskCode, param,
167  priority, stack, stackLimit, stackSize, 0, 1, NULL,
168  OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err);
169 
170  //Check the return value
171  if(err == OS_ERR_NONE)
172  {
173  //Save TCB base address
174  tcbTable[i] = task;
175  //Save stack base address
176  stkTable[i] = stack;
177  }
178  else
179  {
180  //Clean up side effects
181  osFreeMem(task);
182  osFreeMem(stack);
183  }
184  }
185  else
186  {
187  //Memory allocation failed
188  err = OS_ERR_MEM_FULL;
189  //Clean up side effects
190  osFreeMem(task);
191  }
192  }
193  else
194  {
195  //Memory allocation failed
196  err = OS_ERR_MEM_FULL;
197  }
198  }
199  else
200  {
201  //No entry available in the table
202  err = OS_ERR_MEM_FULL;
203  }
204 
205  //Leave critical section
207 
208  //Check whether the task was successfully created
209  if(err == OS_ERR_NONE)
210  return task;
211  else
212  return NULL;
213 }
214 
215 
216 /**
217  * @brief Delete a task
218  * @param[in] task Pointer to the task to be deleted
219  **/
220 
221 void osDeleteTask(OsTask *task)
222 {
223  OS_ERR err;
224 
225  //Delete the specified task
226  OSTaskDel(task, &err);
227 }
228 
229 
230 /**
231  * @brief Delay routine
232  * @param[in] delay Amount of time for which the calling task should block
233  **/
234 
236 {
237  OS_ERR err;
238 
239  //Delay the task for the specified duration
240  OSTimeDly(OS_MS_TO_SYSTICKS(delay), OS_OPT_TIME_DLY, &err);
241 }
242 
243 
244 /**
245  * @brief Yield control to the next task
246  **/
247 
248 void osSwitchTask(void)
249 {
250  //Force a context switch
251  OSSched();
252 }
253 
254 
255 /**
256  * @brief Suspend scheduler activity
257  **/
258 
260 {
261  OS_ERR err;
262 
263  //Make sure the operating system is running
264  if(OSRunning == OS_STATE_OS_RUNNING)
265  {
266  //Suspend scheduler activity
267  OSSchedLock(&err);
268  }
269 }
270 
271 
272 /**
273  * @brief Resume scheduler activity
274  **/
275 
277 {
278  OS_ERR err;
279 
280  //Make sure the operating system is running
281  if(OSRunning == OS_STATE_OS_RUNNING)
282  {
283  //Resume scheduler activity
284  OSSchedUnlock(&err);
285  }
286 }
287 
288 
289 /**
290  * @brief Create an event object
291  * @param[in] event Pointer to the event object
292  * @return The function returns TRUE if the event object was successfully
293  * created. Otherwise, FALSE is returned
294  **/
295 
297 {
298  OS_ERR err;
299 
300  //Create an event flag group
301  OSFlagCreate(event, "EVENT", 0, &err);
302 
303  //Check whether the event flag group was successfully created
304  if(err == OS_ERR_NONE)
305  return TRUE;
306  else
307  return FALSE;
308 }
309 
310 
311 /**
312  * @brief Delete an event object
313  * @param[in] event Pointer to the event object
314  **/
315 
316 void osDeleteEvent(OsEvent *event)
317 {
318  OS_ERR err;
319 
320  //Make sure the operating system is running
321  if(OSRunning == OS_STATE_OS_RUNNING)
322  {
323  //Properly dispose the event object
324  OSFlagDel(event, OS_OPT_DEL_ALWAYS, &err);
325  }
326 }
327 
328 
329 /**
330  * @brief Set the specified event object to the signaled state
331  * @param[in] event Pointer to the event object
332  **/
333 
334 void osSetEvent(OsEvent *event)
335 {
336  OS_ERR err;
337 
338  //Set the specified event to the signaled state
339  OSFlagPost(event, 1, OS_OPT_POST_FLAG_SET, &err);
340 }
341 
342 
343 /**
344  * @brief Set the specified event object to the nonsignaled state
345  * @param[in] event Pointer to the event object
346  **/
347 
348 void osResetEvent(OsEvent *event)
349 {
350  OS_ERR err;
351 
352  //Force the specified event to the nonsignaled state
353  OSFlagPost(event, 1, OS_OPT_POST_FLAG_CLR, &err);
354 }
355 
356 
357 /**
358  * @brief Wait until the specified event is in the signaled state
359  * @param[in] event Pointer to the event object
360  * @param[in] timeout Timeout interval
361  * @return The function returns TRUE if the state of the specified object is
362  * signaled. FALSE is returned if the timeout interval elapsed
363  **/
364 
366 {
367  OS_ERR err;
368 
369  //Wait until the specified event is in the signaled
370  //state or the timeout interval elapses
371  if(timeout == 0)
372  {
373  //Non-blocking call
374  OSFlagPend(event, 1, 0, OS_OPT_PEND_FLAG_SET_ANY |
375  OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING, NULL, &err);
376  }
377  else if(timeout == INFINITE_DELAY)
378  {
379  //Infinite timeout period
380  OSFlagPend(event, 1, 0, OS_OPT_PEND_FLAG_SET_ANY |
381  OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING, NULL, &err);
382  }
383  else
384  {
385  //Wait until the specified event becomes set
386  OSFlagPend(event, 1, OS_MS_TO_SYSTICKS(timeout), OS_OPT_PEND_FLAG_SET_ANY |
387  OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING, NULL, &err);
388  }
389 
390  //Check whether the specified event is set
391  if(err == OS_ERR_NONE)
392  return TRUE;
393  else
394  return FALSE;
395 }
396 
397 
398 /**
399  * @brief Set an event object to the signaled state from an interrupt service routine
400  * @param[in] event Pointer to the event object
401  * @return TRUE if setting the event to signaled state caused a task to unblock
402  * and the unblocked task has a priority higher than the currently running task
403  **/
404 
406 {
407  OS_ERR err;
408 
409  //Set the specified event to the signaled state
410  OSFlagPost(event, 1, OS_OPT_POST_FLAG_SET, &err);
411 
412  //The return value is not relevant
413  return FALSE;
414 }
415 
416 
417 /**
418  * @brief Create a semaphore object
419  * @param[in] semaphore Pointer to the semaphore object
420  * @param[in] count The maximum count for the semaphore object. This value
421  * must be greater than zero
422  * @return The function returns TRUE if the semaphore was successfully
423  * created. Otherwise, FALSE is returned
424  **/
425 
427 {
428  OS_ERR err;
429 
430  //Create a semaphore
431  OSSemCreate(semaphore, "SEMAPHORE", count, &err);
432 
433  //Check whether the semaphore was successfully created
434  if(err == OS_ERR_NONE)
435  return TRUE;
436  else
437  return FALSE;
438 }
439 
440 
441 /**
442  * @brief Delete a semaphore object
443  * @param[in] semaphore Pointer to the semaphore object
444  **/
445 
447 {
448  OS_ERR err;
449 
450  //Make sure the operating system is running
451  if(OSRunning == OS_STATE_OS_RUNNING)
452  {
453  //Properly dispose the specified semaphore
454  OSSemDel(semaphore, OS_OPT_DEL_ALWAYS, &err);
455  }
456 }
457 
458 
459 /**
460  * @brief Wait for the specified semaphore to be available
461  * @param[in] semaphore Pointer to the semaphore object
462  * @param[in] timeout Timeout interval
463  * @return The function returns TRUE if the semaphore is available. FALSE is
464  * returned if the timeout interval elapsed
465  **/
466 
468 {
469  OS_ERR err;
470 
471  //Wait until the semaphore is available or the timeout interval elapses
472  if(timeout == 0)
473  {
474  //Non-blocking call
475  OSSemPend(semaphore, 0, OS_OPT_PEND_NON_BLOCKING, NULL, &err);
476  }
477  else if(timeout == INFINITE_DELAY)
478  {
479  //Infinite timeout period
480  OSSemPend(semaphore, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
481  }
482  else
483  {
484  //Wait until the specified semaphore becomes available
485  OSSemPend(semaphore, OS_MS_TO_SYSTICKS(timeout),
486  OS_OPT_PEND_BLOCKING, NULL, &err);
487  }
488 
489  //Check whether the specified semaphore is available
490  if(err == OS_ERR_NONE)
491  return TRUE;
492  else
493  return FALSE;
494 }
495 
496 
497 /**
498  * @brief Release the specified semaphore object
499  * @param[in] semaphore Pointer to the semaphore object
500  **/
501 
503 {
504  OS_ERR err;
505 
506  //Release the semaphore
507  OSSemPost(semaphore, OS_OPT_POST_1, &err);
508 }
509 
510 
511 /**
512  * @brief Create a mutex object
513  * @param[in] mutex Pointer to the mutex object
514  * @return The function returns TRUE if the mutex was successfully
515  * created. Otherwise, FALSE is returned
516  **/
517 
519 {
520  OS_ERR err;
521 
522  //Create a mutex
523  OSMutexCreate(mutex, "MUTEX", &err);
524 
525  //Check whether the mutex was successfully created
526  if(err == OS_ERR_NONE)
527  return TRUE;
528  else
529  return FALSE;
530 }
531 
532 
533 /**
534  * @brief Delete a mutex object
535  * @param[in] mutex Pointer to the mutex object
536  **/
537 
538 void osDeleteMutex(OsMutex *mutex)
539 {
540  OS_ERR err;
541 
542  //Make sure the operating system is running
543  if(OSRunning == OS_STATE_OS_RUNNING)
544  {
545  //Properly dispose the specified mutex
546  OSMutexDel(mutex, OS_OPT_DEL_ALWAYS, &err);
547  }
548 }
549 
550 
551 /**
552  * @brief Acquire ownership of the specified mutex object
553  * @param[in] mutex Pointer to the mutex object
554  **/
555 
557 {
558  OS_ERR err;
559 
560  //Obtain ownership of the mutex object
561  OSMutexPend(mutex, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
562 }
563 
564 
565 /**
566  * @brief Release ownership of the specified mutex object
567  * @param[in] mutex Pointer to the mutex object
568  **/
569 
571 {
572  OS_ERR err;
573 
574  //Release ownership of the mutex object
575  OSMutexPost(mutex, OS_OPT_POST_NONE, &err);
576 }
577 
578 
579 /**
580  * @brief Retrieve system time
581  * @return Number of milliseconds elapsed since the system was last started
582  **/
583 
585 {
586  OS_ERR err;
587  systime_t time;
588 
589  //Get current tick count
590  time = OSTimeGet(&err);
591 
592  //Convert system ticks to milliseconds
593  return OS_SYSTICKS_TO_MS(time);
594 }
595 
596 
597 /**
598  * @brief Allocate a memory block
599  * @param[in] size Bytes to allocate
600  * @return A pointer to the allocated memory block or NULL if
601  * there is insufficient memory available
602  **/
603 
604 void *osAllocMem(size_t size)
605 {
606  void *p;
607 
608  //Enter critical section
610  //Allocate a memory block
611  p = malloc(size);
612  //Leave critical section
614 
615  //Debug message
616  TRACE_DEBUG("Allocating %" PRIuSIZE " bytes at 0x%08" PRIXPTR "\r\n", size, (uintptr_t) p);
617 
618  //Return a pointer to the newly allocated memory block
619  return p;
620 }
621 
622 
623 /**
624  * @brief Release a previously allocated memory block
625  * @param[in] p Previously allocated memory block to be freed
626  **/
627 
628 void osFreeMem(void *p)
629 {
630  //Make sure the pointer is valid
631  if(p != NULL)
632  {
633  //Debug message
634  TRACE_DEBUG("Freeing memory at 0x%08" PRIXPTR "\r\n", (uintptr_t) p);
635 
636  //Enter critical section
638  //Free memory block
639  free(p);
640  //Leave critical section
642  }
643 }
644 
645 
646 /**
647  * @brief Idle task hook
648  **/
649 
650 void osIdleTaskHook(void)
651 {
652  uint_t i;
653 
654  //Loop through TCB table
655  for(i = 0; i < OS_PORT_MAX_TASKS; i++)
656  {
657  //Check whether current entry is used
658  if(tcbTable[i] != NULL)
659  {
660  //Wait for task termination
661  if(tcbTable[i]->TaskState == OS_TASK_STATE_DEL)
662  {
663  //Free previously allocated resources
664  osFreeMem(stkTable[i]);
665  osFreeMem(tcbTable[i]);
666 
667  //Mark the entry as free
668  stkTable[i] = NULL;
669  tcbTable[i] = NULL;
670  }
671  }
672  }
673 }
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
void osFreeMem(void *p)
Release a previously allocated memory block.
int bool_t
Definition: compiler_port.h:49
signed int int_t
Definition: compiler_port.h:44
void osDelayTask(systime_t delay)
Delay routine.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint8_t p
Definition: ndp.h:298
#define TRUE
Definition: os_port.h:50
Event object.
void osResumeAllTasks(void)
Resume scheduler activity.
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
char_t name[]
Semaphore object.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define FALSE
Definition: os_port.h:46
OsTask * osCreateTask(const char_t *name, OsTaskCode taskCode, void *param, size_t stackSize, int_t priority)
Create a new task.
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
systime_t osGetSystemTime(void)
Retrieve system time.
void osInitKernel(void)
Kernel initialization.
Definition: os_port_ucos3.c:52
Task object.
#define OS_SYSTICKS_TO_MS(n)
void osDeleteEvent(OsEvent *event)
Delete an event object.
#define OS_MS_TO_SYSTICKS(n)
void osSuspendAllTasks(void)
Suspend scheduler activity.
void osSwitchTask(void)
Yield control to the next task.
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
void osDeleteTask(OsTask *task)
Delete a task.
Mutex object.
#define TRACE_DEBUG(...)
Definition: debug.h:106
char char_t
Definition: compiler_port.h:43
uint32_t time
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
void(* OsTaskCode)(void *param)
Task routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void * osAllocMem(size_t size)
Allocate a memory block.
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
bool_t osCreateStaticTask(OsTask *task, const char_t *name, OsTaskCode taskCode, void *param, void *stack, size_t stackSize, int_t priority)
Create a static task.
Definition: os_port_ucos3.c:94
void osIdleTaskHook(void)
Idle task hook.
RTOS abstraction layer (Micrium uC/OS-III)
#define OS_PORT_MAX_TASKS
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
void osStartKernel(void)
Start kernel.
Definition: os_port_ucos3.c:72
uint16_t priority
Definition: dns_common.h:221
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
RTOS abstraction layer.
uint32_t systime_t
Definition: compiler_port.h:46
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:74