os_port_ucos2.c
Go to the documentation of this file.
1 /**
2  * @file os_port_ucos2.c
3  * @brief RTOS abstraction layer (Micrium uC/OS-II)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2020 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.8
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_ucos2.h"
38 #include "debug.h"
39 
40 //Variables
41 static OsTask tcbTable[OS_LOWEST_PRIO];
42 
43 
44 /**
45  * @brief Kernel initialization
46  **/
47 
48 void osInitKernel(void)
49 {
50  //Initialize table
51  osMemset(tcbTable, 0, sizeof(tcbTable));
52 
53  //Scheduler initialization
54  OSInit();
55 }
56 
57 
58 /**
59  * @brief Start kernel
60  **/
61 
62 void osStartKernel(void)
63 {
64  //Start the scheduler
65  OSStart();
66 }
67 
68 
69 /**
70  * @brief Create a static task
71  * @param[out] task Pointer to the task structure
72  * @param[in] name A name identifying the task
73  * @param[in] taskCode Pointer to the task entry function
74  * @param[in] param A pointer to a variable to be passed to the task
75  * @param[in] stack Pointer to the stack
76  * @param[in] stackSize The initial size of the stack, in words
77  * @param[in] priority The priority at which the task should run
78  * @return The function returns TRUE if the task was successfully
79  * created. Otherwise, FALSE is returned
80  **/
81 
83  void *param, void *stack, size_t stackSize, int_t priority)
84 {
85  INT8U err;
86  OS_STK *stackTop;
87 
88  //Check stack size
89  if(stackSize == 0)
90  return FALSE;
91 
92  //Top of the stack
93  stackTop = (OS_STK *) stack + (stackSize - 1);
94 
95  //Search for a free TCB
96  while(priority < (OS_LOWEST_PRIO - 3) && OSTCBPrioTbl[priority] != 0)
97  priority++;
98 
99  //No more TCB available?
100  if(priority >= (OS_LOWEST_PRIO - 3))
101  return FALSE;
102 
103  //Create a new task
104  err = OSTaskCreateExt(taskCode, param, stackTop, priority, priority,
105  stack, stackSize, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
106 
107  //Check whether the task was successfully created
108  if(err == OS_ERR_NONE)
109  {
110  //Save task priority
111  task->prio = priority;
112  //The task was successfully created
113  return TRUE;
114  }
115  else
116  {
117  //Report an error
118  return FALSE;
119  }
120 }
121 
122 
123 /**
124  * @brief Create a new task
125  * @param[in] name A name identifying the task
126  * @param[in] taskCode Pointer to the task entry function
127  * @param[in] param A pointer to a variable to be passed to the task
128  * @param[in] stackSize The initial size of the stack, in words
129  * @param[in] priority The priority at which the task should run
130  * @return If the function succeeds, the return value is a pointer to the
131  * new task. If the function fails, the return value is NULL
132  **/
133 
135  void *param, size_t stackSize, int_t priority)
136 {
137  //INT8U i;
138  OS_STK *stack;
139 
140  //Allocate a memory block to hold the task's stack
141  stack = osAllocMem(stackSize * sizeof(OS_STK));
142 
143  //Successful memory allocation?
144  if(stack != NULL)
145  {
146  //Create task
147  if(osCreateStaticTask(&tcbTable[priority], name,
148  taskCode, param, stack, stackSize, priority))
149  {
150  //Return a valid handle
151  return &tcbTable[priority];
152  }
153  else
154  {
155  //Clean up side effects
156  osFreeMem(stack);
157  //Report an error
158  return NULL;
159  }
160  }
161  else
162  {
163  //Memory allocation failed
164  return NULL;
165  }
166 }
167 
168 
169 /**
170  * @brief Delete a task
171  * @param[in] task Pointer to the task to be deleted
172  **/
173 
174 void osDeleteTask(OsTask *task)
175 {
176  //Delete the specified task
177  OSTaskDel(task->prio);
178 }
179 
180 
181 /**
182  * @brief Delay routine
183  * @param[in] delay Amount of time for which the calling task should block
184  **/
185 
187 {
188  INT16U n;
189 
190  //Convert milliseconds to system ticks
191  delay = OS_MS_TO_SYSTICKS(delay);
192 
193  //Delay the task for the specified duration
194  while(delay > 0)
195  {
196  //The maximum delay is 65535 clock ticks
197  n = MIN(delay, 65535);
198  //Wait for the specified amount of time
199  OSTimeDly(n);
200  //Decrement delay value
201  delay -= n;
202  }
203 }
204 
205 
206 /**
207  * @brief Yield control to the next task
208  **/
209 
210 void osSwitchTask(void)
211 {
212  //Not implemented
213 }
214 
215 
216 /**
217  * @brief Suspend scheduler activity
218  **/
219 
221 {
222  //Make sure the operating system is running
223  if(OSRunning == OS_TRUE)
224  {
225  //Suspend scheduler activity
226  OSSchedLock();
227  }
228 }
229 
230 
231 /**
232  * @brief Resume scheduler activity
233  **/
234 
236 {
237  //Make sure the operating system is running
238  if(OSRunning == OS_TRUE)
239  {
240  //Resume scheduler activity
241  OSSchedUnlock();
242  }
243 }
244 
245 
246 /**
247  * @brief Create an event object
248  * @param[in] event Pointer to the event object
249  * @return The function returns TRUE if the event object was successfully
250  * created. Otherwise, FALSE is returned
251  **/
252 
254 {
255  INT8U err;
256 
257  //Create an event flag group
258  event->p = OSFlagCreate(0, &err);
259 
260  //Check whether the event flag group was successfully created
261  if(event->p != NULL && err == OS_ERR_NONE)
262  return TRUE;
263  else
264  return FALSE;
265 }
266 
267 
268 /**
269  * @brief Delete an event object
270  * @param[in] event Pointer to the event object
271  **/
272 
273 void osDeleteEvent(OsEvent *event)
274 {
275  INT8U err;
276 
277  //Make sure the operating system is running
278  if(OSRunning == OS_TRUE)
279  {
280  //Properly dispose the event object
281  OSFlagDel(event->p, OS_DEL_ALWAYS, &err);
282  }
283 }
284 
285 
286 /**
287  * @brief Set the specified event object to the signaled state
288  * @param[in] event Pointer to the event object
289  **/
290 
291 void osSetEvent(OsEvent *event)
292 {
293  INT8U err;
294 
295  //Set the specified event to the signaled state
296  OSFlagPost(event->p, 1, OS_FLAG_SET, &err);
297 }
298 
299 
300 /**
301  * @brief Set the specified event object to the nonsignaled state
302  * @param[in] event Pointer to the event object
303  **/
304 
305 void osResetEvent(OsEvent *event)
306 {
307  INT8U err;
308 
309  //Force the specified event to the nonsignaled state
310  OSFlagPost(event->p, 1, OS_FLAG_CLR, &err);
311 }
312 
313 
314 /**
315  * @brief Wait until the specified event is in the signaled state
316  * @param[in] event Pointer to the event object
317  * @param[in] timeout Timeout interval
318  * @return The function returns TRUE if the state of the specified object is
319  * signaled. FALSE is returned if the timeout interval elapsed
320  **/
321 
323 {
324  INT8U err;
325  INT16U n;
326 
327  //Wait until the specified event is in the signaled
328  //state or the timeout interval elapses
329  if(timeout == 0)
330  {
331  //Non-blocking call
332  OSFlagAccept(event->p, 1, OS_FLAG_WAIT_SET_ANY | OS_FLAG_CONSUME, &err);
333  }
334  else if(timeout == INFINITE_DELAY)
335  {
336  //Infinite timeout period
337  OSFlagPend(event->p, 1, OS_FLAG_WAIT_SET_ANY | OS_FLAG_CONSUME, 0, &err);
338  }
339  else
340  {
341  //Convert milliseconds to system ticks
342  timeout = OS_MS_TO_SYSTICKS(timeout);
343 
344  //Loop until the assigned time period has elapsed
345  do
346  {
347  //The maximum timeout is 65535 clock ticks
348  n = MIN(timeout, 65535);
349  //Wait for the specified time interval
350  OSFlagPend(event->p, 1, OS_FLAG_WAIT_SET_ANY | OS_FLAG_CONSUME, n, &err);
351  //Decrement timeout value
352  timeout -= n;
353 
354  //Check timeout value
355  } while(err == OS_ERR_TIMEOUT && timeout > 0);
356  }
357 
358  //Check whether the specified event is set
359  if(err == OS_ERR_NONE)
360  return TRUE;
361  else
362  return FALSE;
363 }
364 
365 
366 /**
367  * @brief Set an event object to the signaled state from an interrupt service routine
368  * @param[in] event Pointer to the event object
369  * @return TRUE if setting the event to signaled state caused a task to unblock
370  * and the unblocked task has a priority higher than the currently running task
371  **/
372 
374 {
375  INT8U err;
376 
377  //Set the specified event to the signaled state
378  OSFlagPost(event->p, 1, OS_FLAG_SET, &err);
379 
380  //The return value is not relevant
381  return FALSE;
382 }
383 
384 
385 /**
386  * @brief Create a semaphore object
387  * @param[in] semaphore Pointer to the semaphore object
388  * @param[in] count The maximum count for the semaphore object. This value
389  * must be greater than zero
390  * @return The function returns TRUE if the semaphore was successfully
391  * created. Otherwise, FALSE is returned
392  **/
393 
395 {
396  //Create a semaphore
397  semaphore->p = OSSemCreate(count);
398 
399  //Check whether the semaphore was successfully created
400  if(semaphore->p != NULL)
401  return TRUE;
402  else
403  return FALSE;
404 }
405 
406 
407 /**
408  * @brief Delete a semaphore object
409  * @param[in] semaphore Pointer to the semaphore object
410  **/
411 
413 {
414  INT8U err;
415 
416  //Make sure the operating system is running
417  if(OSRunning == OS_TRUE)
418  {
419  //Properly dispose the specified semaphore
420  OSSemDel(semaphore->p, OS_DEL_ALWAYS, &err);
421  }
422 }
423 
424 
425 /**
426  * @brief Wait for the specified semaphore to be available
427  * @param[in] semaphore Pointer to the semaphore object
428  * @param[in] timeout Timeout interval
429  * @return The function returns TRUE if the semaphore is available. FALSE is
430  * returned if the timeout interval elapsed
431  **/
432 
434 {
435  INT8U err;
436  INT16U n;
437 
438  //Wait until the semaphore is available or the timeout interval elapses
439  if(timeout == 0)
440  {
441  //Non-blocking call
442  if(OSSemAccept(semaphore->p) > 0)
443  err = OS_ERR_NONE;
444  else
445  err = OS_ERR_TIMEOUT;
446  }
447  else if(timeout == INFINITE_DELAY)
448  {
449  //Infinite timeout period
450  OSSemPend(semaphore->p, 0, &err);
451  }
452  else
453  {
454  //Convert milliseconds to system ticks
455  timeout = OS_MS_TO_SYSTICKS(timeout);
456 
457  //Loop until the assigned time period has elapsed
458  do
459  {
460  //The maximum timeout is 65535 clock ticks
461  n = MIN(timeout, 65535);
462  //Wait for the specified time interval
463  OSSemPend(semaphore->p, n, &err);
464  //Decrement timeout value
465  timeout -= n;
466 
467  //Check timeout value
468  } while(err == OS_ERR_TIMEOUT && timeout > 0);
469  }
470 
471  //Check whether the specified semaphore is available
472  if(err == OS_ERR_NONE)
473  return TRUE;
474  else
475  return FALSE;
476 }
477 
478 
479 /**
480  * @brief Release the specified semaphore object
481  * @param[in] semaphore Pointer to the semaphore object
482  **/
483 
485 {
486  //Release the semaphore
487  OSSemPost(semaphore->p);
488 }
489 
490 
491 /**
492  * @brief Create a mutex object
493  * @param[in] mutex Pointer to the mutex object
494  * @return The function returns TRUE if the mutex was successfully
495  * created. Otherwise, FALSE is returned
496  **/
497 
499 {
500 #if 1
501  bool_t status;
502 
503  //Create an event object
504  status = osCreateEvent((OsEvent *) mutex);
505 
506  //Check whether the event object was successfully created
507  if(status)
508  {
509  //Set event
510  osSetEvent((OsEvent *) mutex);
511  }
512 
513  //Return status
514  return status;
515 #else
516  INT8U err;
517 
518  //Create a mutex
519  mutex->p = OSMutexCreate(10, &err);
520 
521  //Check whether the mutex was successfully created
522  if(mutex->p != NULL && err == OS_ERR_NONE)
523  return TRUE;
524  else
525  return FALSE;
526 #endif
527 }
528 
529 
530 /**
531  * @brief Delete a mutex object
532  * @param[in] mutex Pointer to the mutex object
533  **/
534 
535 void osDeleteMutex(OsMutex *mutex)
536 {
537 #if 1
538  //Delete event object
539  osDeleteEvent((OsEvent *) mutex);
540 #else
541  INT8U err;
542 
543  //Make sure the operating system is running
544  if(OSRunning == OS_TRUE)
545  {
546  //Properly dispose the specified mutex
547  OSMutexDel(mutex->p, OS_DEL_ALWAYS, &err);
548  }
549 #endif
550 }
551 
552 
553 /**
554  * @brief Acquire ownership of the specified mutex object
555  * @param[in] mutex Pointer to the mutex object
556  **/
557 
559 {
560 #if 1
561  //Wait for event
563 #else
564  INT8U err;
565 
566  //Obtain ownership of the mutex object
567  OSMutexPend(mutex->p, 0, &err);
568 #endif
569 }
570 
571 
572 /**
573  * @brief Release ownership of the specified mutex object
574  * @param[in] mutex Pointer to the mutex object
575  **/
576 
578 {
579 #if 1
580  //Set event
581  osSetEvent((OsEvent *) mutex);
582 #else
583  //Release ownership of the mutex object
584  OSMutexPost(mutex->p);
585 #endif
586 }
587 
588 
589 /**
590  * @brief Retrieve system time
591  * @return Number of milliseconds elapsed since the system was last started
592  **/
593 
595 {
596  systime_t time;
597 
598  //Get current tick count
599  time = OSTimeGet();
600 
601  //Convert system ticks to milliseconds
602  return OS_SYSTICKS_TO_MS(time);
603 }
604 
605 
606 /**
607  * @brief Allocate a memory block
608  * @param[in] size Bytes to allocate
609  * @return A pointer to the allocated memory block or NULL if
610  * there is insufficient memory available
611  **/
612 
613 void *osAllocMem(size_t size)
614 {
615  void *p;
616 
617  //Enter critical section
619  //Allocate a memory block
620  p = malloc(size);
621  //Leave critical section
623 
624  //Debug message
625  TRACE_DEBUG("Allocating %" PRIuSIZE " bytes at 0x%08" PRIXPTR "\r\n", size, (uintptr_t) p);
626 
627  //Return a pointer to the newly allocated memory block
628  return p;
629 }
630 
631 
632 /**
633  * @brief Release a previously allocated memory block
634  * @param[in] p Previously allocated memory block to be freed
635  **/
636 
637 void osFreeMem(void *p)
638 {
639  //Make sure the pointer is valid
640  if(p != NULL)
641  {
642  //Debug message
643  TRACE_DEBUG("Freeing memory at 0x%08" PRIXPTR "\r\n", (uintptr_t) p);
644 
645  //Enter critical section
647  //Free memory block
648  free(p);
649  //Leave critical section
651  }
652 }
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
int bool_t
Definition: compiler_port.h:49
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
void osDelayTask(systime_t delay)
Delay routine.
signed int int_t
Definition: compiler_port.h:44
RTOS abstraction layer (Micrium uC/OS-II)
void osStartKernel(void)
Start kernel.
Definition: os_port_ucos2.c:62
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
uint8_t p
Definition: ndp.h:298
#define TRUE
Definition: os_port.h:50
void * osAllocMem(size_t size)
Allocate a memory block.
Event object.
void osSwitchTask(void)
Yield control to the next task.
char_t name[]
Semaphore object.
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
OS_EVENT * p
#define FALSE
Definition: os_port.h:46
void osFreeMem(void *p)
Release a previously allocated memory block.
void osInitKernel(void)
Kernel initialization.
Definition: os_port_ucos2.c:48
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
Task object.
#define OS_SYSTICKS_TO_MS(n)
#define OS_MS_TO_SYSTICKS(n)
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osResumeAllTasks(void)
Resume scheduler activity.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
#define MIN(a, b)
Definition: os_port.h:62
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
void osSuspendAllTasks(void)
Suspend scheduler activity.
OsTask * osCreateTask(const char_t *name, OsTaskCode taskCode, void *param, size_t stackSize, int_t priority)
Create a new task.
Mutex object.
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:43
void osDeleteEvent(OsEvent *event)
Delete an event object.
uint32_t time
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_ucos2.c:82
OS_FLAG_GRP * p
Definition: os_port_ucos2.h:91
void(* OsTaskCode)(void *param)
Task routine.
uint8_t n
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
#define osMemset(p, value, length)
Definition: os_port.h:128
systime_t osGetSystemTime(void)
Retrieve system time.
uint16_t priority
Definition: dns_common.h:221
RTOS abstraction layer.
uint32_t systime_t
Definition: compiler_port.h:46
void osDeleteTask(OsTask *task)
Delete a task.
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:74
INT8U prio
Definition: os_port_ucos2.h:81