os_port_cmsis_rtos.c
Go to the documentation of this file.
1 /**
2  * @file os_port_cmsis_rtos.c
3  * @brief RTOS abstraction layer (CMSIS-RTOS)
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 "os_port.h"
36 #include "os_port_cmsis_rtos.h"
37 #include "debug.h"
38 
39 
40 /**
41  * @brief Kernel initialization
42  **/
43 
44 void osInitKernel(void)
45 {
46 #if (osCMSIS >= 0x10001)
47  //Initialize the kernel
48  osKernelInitialize();
49 #endif
50 }
51 
52 
53 /**
54  * @brief Start kernel
55  **/
56 
57 void osStartKernel(void)
58 {
59 #if (osCMSIS >= 0x10001)
60  //Start the kernel
61  osKernelStart();
62 #else
63  //Start the kernel
64  osKernelStart(NULL, NULL);
65 #endif
66 }
67 
68 
69 /**
70  * @brief Create a new task
71  * @param[in] name A name identifying the task
72  * @param[in] taskCode Pointer to the task entry function
73  * @param[in] param A pointer to a variable to be passed to the task
74  * @param[in] stackSize The initial size of the stack, in words
75  * @param[in] priority The priority at which the task should run
76  * @return If the function succeeds, the return value is a pointer to the
77  * new task. If the function fails, the return value is NULL
78  **/
79 
81  void *param, size_t stackSize, int_t priority)
82 {
83  osThreadId threadId;
84  osThreadDef_t threadDef;
85 
86 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
87  threadDef.pthread = (os_pthread) taskCode;
88  threadDef.tpriority = (osPriority) priority;
89  threadDef.instances = 1;
90  threadDef.stacksize = stackSize * sizeof(uint_t);
91 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
92  threadDef.pthread = (os_pthread) taskCode;
93  threadDef.attr.name = name;
94  threadDef.attr.attr_bits = 0;
95  threadDef.attr.cb_mem = NULL;
96  threadDef.attr.cb_size = 0;
97  threadDef.attr.stack_mem = NULL;
98  threadDef.attr.stack_size = stackSize * sizeof(uint_t);
99  threadDef.attr.priority = (osPriority_t) priority;
100  threadDef.attr.tz_module = 0;
101  threadDef.attr.reserved = 0;
102 #elif defined(osCMSIS_FreeRTOS)
103  threadDef.pthread = (os_pthread) taskCode;
104  threadDef.attr.name = name;
105  threadDef.attr.attr_bits = 0;
106  threadDef.attr.cb_mem = NULL;
107  threadDef.attr.cb_size = 0;
108  threadDef.attr.stack_mem = NULL;
109  threadDef.attr.stack_size = stackSize * sizeof(uint_t);
110  threadDef.attr.priority = (osPriority_t) priority;
111  threadDef.attr.tz_module = 0;
112  threadDef.attr.reserved = 0;
113 #else
114  threadDef.name = (char_t *) name;
115  threadDef.pthread = (os_pthread) taskCode;
116  threadDef.tpriority = (osPriority) priority;
117  threadDef.instances = 1;
118  threadDef.stacksize = stackSize;
119 #endif
120 
121  //Create a new thread
122  threadId = osThreadCreate(&threadDef, param);
123  //Return a handle to the newly created thread
124  return (OsTask *) threadId;
125 }
126 
127 
128 /**
129  * @brief Delete a task
130  * @param[in] task Pointer to the task to be deleted
131  **/
132 
133 void osDeleteTask(OsTask *task)
134 {
135 #if (osCMSIS >= 0x20000)
136  //Delete the specified thread
137  if(task == NULL)
138  osThreadExit();
139  else
140  osThreadTerminate((osThreadId_t) task);
141 #else
142  //Delete the specified thread
143  osThreadTerminate((osThreadId) task);
144 #endif
145 }
146 
147 
148 /**
149  * @brief Delay routine
150  * @param[in] delay Amount of time for which the calling task should block
151  **/
152 
154 {
155  //Delay the thread for the specified duration
156  osDelay(delay);
157 }
158 
159 
160 /**
161  * @brief Yield control to the next task
162  **/
163 
164 void osSwitchTask(void)
165 {
166  //Force a context switch
167  osThreadYield();
168 }
169 
170 
171 /**
172  * @brief Suspend scheduler activity
173  **/
174 
176 {
177 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
178  //Not implemented
179 #else
180  //Make sure the operating system is running
181  if(osKernelRunning())
182  {
183  //Suspend all threads
184  osThreadSuspendAll();
185  }
186 #endif
187 }
188 
189 
190 /**
191  * @brief Resume scheduler activity
192  **/
193 
195 {
196 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
197  //Not implemented
198 #else
199  //Make sure the operating system is running
200  if(osKernelRunning())
201  {
202  //Resume all threads
203  osThreadResumeAll();
204  }
205 #endif
206 }
207 
208 
209 /**
210  * @brief Create an event object
211  * @param[in] event Pointer to the event object
212  * @return The function returns TRUE if the event object was successfully
213  * created. Otherwise, FALSE is returned
214  **/
215 
217 {
218  osSemaphoreDef_t semaphoreDef;
219 
220 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
221  semaphoreDef.semaphore = event->cb;
222 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
223  semaphoreDef.name = NULL;
224  semaphoreDef.attr_bits = 0;
225  semaphoreDef.cb_mem = NULL;
226  semaphoreDef.cb_size = 0;
227 #elif defined(osCMSIS_FreeRTOS)
228  semaphoreDef.name = NULL;
229  semaphoreDef.attr_bits = 0;
230  semaphoreDef.cb_mem = NULL;
231  semaphoreDef.cb_size = 0;
232 #else
233  semaphoreDef.dummy = 0;
234 #endif
235 
236  //Create a binary semaphore object
237  event->id = osSemaphoreCreate(&semaphoreDef, 1);
238 
239  //Check whether the returned semaphore ID is valid
240  if(event->id != NULL)
241  {
242  //Force the specified event to the nonsignaled state
243  osSemaphoreWait(event->id, 0);
244  //Event successfully created
245  return TRUE;
246  }
247  else
248  {
249  //Failed to create event object
250  return FALSE;
251  }
252 }
253 
254 
255 /**
256  * @brief Delete an event object
257  * @param[in] event Pointer to the event object
258  **/
259 
260 void osDeleteEvent(OsEvent *event)
261 {
262  //Make sure the semaphore ID is valid
263  if(event->id != NULL)
264  {
265  //Properly dispose the event object
266  osSemaphoreDelete(event->id);
267  }
268 }
269 
270 
271 /**
272  * @brief Set the specified event object to the signaled state
273  * @param[in] event Pointer to the event object
274  **/
275 
276 void osSetEvent(OsEvent *event)
277 {
278  //Set the specified event to the signaled state
279  osSemaphoreRelease(event->id);
280 }
281 
282 
283 /**
284  * @brief Set the specified event object to the nonsignaled state
285  * @param[in] event Pointer to the event object
286  **/
287 
288 void osResetEvent(OsEvent *event)
289 {
290 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
291  //Force the specified event to the nonsignaled state
292  while(osSemaphoreWait(event->id, 0) > 0);
293 #else
294  //Force the specified event to the nonsignaled state
295  osSemaphoreWait(event->id, 0);
296 #endif
297 }
298 
299 
300 /**
301  * @brief Wait until the specified event is in the signaled state
302  * @param[in] event Pointer to the event object
303  * @param[in] timeout Timeout interval
304  * @return The function returns TRUE if the state of the specified object is
305  * signaled. FALSE is returned if the timeout interval elapsed
306  **/
307 
309 {
310  int32_t ret;
311 
312  //Wait until the specified event is in the signaled
313  //state or the timeout interval elapses
314  if(timeout == INFINITE_DELAY)
315  {
316  //Infinite timeout period
317  ret = osSemaphoreWait(event->id, osWaitForever);
318  }
319  else
320  {
321 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
322  systime_t n;
323 
324  //Loop until the assigned time period has elapsed
325  do
326  {
327  //Limit the timeout value
328  n = MIN(timeout, 10000);
329  //Wait for the specified time interval
330  ret = osSemaphoreWait(event->id, n);
331  //Decrement timeout value
332  timeout -= n;
333 
334  //Check timeout value
335  } while(ret == 0 && timeout > 0);
336 #else
337  //Wait for the specified time interval
338  ret = osSemaphoreWait(event->id, timeout);
339 #endif
340  }
341 
342 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
343  //Check return value
344  if(ret > 0)
345  {
346  //Force the event back to the nonsignaled state
347  while(osSemaphoreWait(event->id, 0) > 0);
348 
349  //The specified event is in the signaled state
350  return TRUE;
351  }
352  else
353  {
354  //The timeout interval elapsed
355  return FALSE;
356  }
357 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
358  //Check return value
359  if(ret > 0)
360  return TRUE;
361  else
362  return FALSE;
363 #elif defined(osCMSIS_FreeRTOS)
364  //Check return value
365  if(ret > 0)
366  return TRUE;
367  else
368  return FALSE;
369 #else
370  //Check return value
371  if(ret == osOK)
372  return TRUE;
373  else
374  return FALSE;
375 #endif
376 }
377 
378 
379 /**
380  * @brief Set an event object to the signaled state from an interrupt service routine
381  * @param[in] event Pointer to the event object
382  * @return TRUE if setting the event to signaled state caused a task to unblock
383  * and the unblocked task has a priority higher than the currently running task
384  **/
385 
387 {
388  //Set the specified event to the signaled state
389  osSemaphoreRelease(event->id);
390 
391  //The return value is not relevant
392  return FALSE;
393 }
394 
395 
396 /**
397  * @brief Create a semaphore object
398  * @param[in] semaphore Pointer to the semaphore object
399  * @param[in] count The maximum count for the semaphore object. This value
400  * must be greater than zero
401  * @return The function returns TRUE if the semaphore was successfully
402  * created. Otherwise, FALSE is returned
403  **/
404 
406 {
407  osSemaphoreDef_t semaphoreDef;
408 
409 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
410  semaphoreDef.semaphore = semaphore->cb;
411 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
412  semaphoreDef.name = NULL;
413  semaphoreDef.attr_bits = 0;
414  semaphoreDef.cb_mem = NULL;
415  semaphoreDef.cb_size = 0;
416 #elif defined(osCMSIS_FreeRTOS)
417  semaphoreDef.name = NULL;
418  semaphoreDef.attr_bits = 0;
419  semaphoreDef.cb_mem = NULL;
420  semaphoreDef.cb_size = 0;
421 #else
422  semaphoreDef.dummy = 0;
423 #endif
424 
425  //Create a semaphore object
426  semaphore->id = osSemaphoreCreate(&semaphoreDef, count);
427 
428  //Check whether the returned semaphore ID is valid
429  if(semaphore->id != NULL)
430  return TRUE;
431  else
432  return FALSE;
433 }
434 
435 
436 /**
437  * @brief Delete a semaphore object
438  * @param[in] semaphore Pointer to the semaphore object
439  **/
440 
442 {
443  //Make sure the semaphore ID is valid
444  if(semaphore->id != NULL)
445  {
446  //Properly dispose the specified semaphore
447  osSemaphoreDelete(semaphore->id);
448  }
449 }
450 
451 
452 /**
453  * @brief Wait for the specified semaphore to be available
454  * @param[in] semaphore Pointer to the semaphore object
455  * @param[in] timeout Timeout interval
456  * @return The function returns TRUE if the semaphore is available. FALSE is
457  * returned if the timeout interval elapsed
458  **/
459 
461 {
462  int32_t ret;
463 
464  //Wait until the semaphore is available or the timeout interval elapses
465  if(timeout == INFINITE_DELAY)
466  {
467  //Infinite timeout period
468  ret = osSemaphoreWait(semaphore->id, osWaitForever);
469  }
470  else
471  {
472 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
473  systime_t n;
474 
475  //Loop until the assigned time period has elapsed
476  do
477  {
478  //Limit the timeout value
479  n = MIN(timeout, 10000);
480  //Wait for the specified time interval
481  ret = osSemaphoreWait(semaphore->id, n);
482  //Decrement timeout value
483  timeout -= n;
484 
485  //Check timeout value
486  } while(ret == 0 && timeout > 0);
487 #else
488  //Wait for the specified time interval
489  ret = osSemaphoreWait(semaphore->id, timeout);
490 #endif
491  }
492 
493 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
494  //Check return value
495  if(ret > 0)
496  return TRUE;
497  else
498  return FALSE;
499 #else
500  //Check return value
501  if(ret == osOK)
502  return TRUE;
503  else
504  return FALSE;
505 #endif
506 }
507 
508 
509 /**
510  * @brief Release the specified semaphore object
511  * @param[in] semaphore Pointer to the semaphore object
512  **/
513 
515 {
516  //Release the semaphore
517  osSemaphoreRelease(semaphore->id);
518 }
519 
520 
521 /**
522  * @brief Create a mutex object
523  * @param[in] mutex Pointer to the mutex object
524  * @return The function returns TRUE if the mutex was successfully
525  * created. Otherwise, FALSE is returned
526  **/
527 
529 {
530  osMutexDef_t mutexDef;
531 
532 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
533  mutexDef.mutex = mutex->cb;
534 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
535  mutexDef.name = NULL;
536  mutexDef.attr_bits = 0;
537  mutexDef.cb_mem = NULL;
538  mutexDef.cb_size = 0;
539 #elif defined(osCMSIS_FreeRTOS)
540  mutexDef.name = NULL;
541  mutexDef.attr_bits = 0;
542  mutexDef.cb_mem = NULL;
543  mutexDef.cb_size = 0;
544 #else
545  mutexDef.dummy = 0;
546 #endif
547 
548  //Create a mutex object
549  mutex->id = osMutexCreate(&mutexDef);
550 
551  //Check whether the returned mutex ID is valid
552  if(mutex->id != NULL)
553  return TRUE;
554  else
555  return FALSE;
556 }
557 
558 
559 /**
560  * @brief Delete a mutex object
561  * @param[in] mutex Pointer to the mutex object
562  **/
563 
564 void osDeleteMutex(OsMutex *mutex)
565 {
566  //Make sure the mutex ID is valid
567  if(mutex->id != NULL)
568  {
569  //Properly dispose the specified mutex
570  osMutexDelete(mutex->id);
571  }
572 }
573 
574 
575 /**
576  * @brief Acquire ownership of the specified mutex object
577  * @param[in] mutex Pointer to the mutex object
578  **/
579 
581 {
582  //Obtain ownership of the mutex object
583  osMutexWait(mutex->id, osWaitForever);
584 }
585 
586 
587 /**
588  * @brief Release ownership of the specified mutex object
589  * @param[in] mutex Pointer to the mutex object
590  **/
591 
593 {
594  //Release ownership of the mutex object
595  osMutexRelease(mutex->id);
596 }
597 
598 
599 /**
600  * @brief Retrieve system time
601  * @return Number of milliseconds elapsed since the system was last started
602  **/
603 
605 {
606  systime_t time;
607 
608 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
609  //Forward function declaration
610  extern uint32_t rt_time_get(void);
611 
612  //Get current tick count
613  time = rt_time_get();
614 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
615  time = osKernelGetTickCount();
616 #elif defined(osCMSIS_FreeRTOS)
617  time = osKernelGetTickCount();
618 #else
619  //Get current tick count
620  time = osKernelSysTick();
621 #endif
622 
623  //Convert system ticks to milliseconds
624  return OS_SYSTICKS_TO_MS(time);
625 }
626 
627 
628 /**
629  * @brief Allocate a memory block
630  * @param[in] size Bytes to allocate
631  * @return A pointer to the allocated memory block or NULL if
632  * there is insufficient memory available
633  **/
634 
635 void *osAllocMem(size_t size)
636 {
637  void *p;
638 
639  //Enter critical section
641  //Allocate a memory block
642  p = malloc(size);
643  //Leave critical section
645 
646  //Debug message
647  TRACE_DEBUG("Allocating %u bytes at 0x%08X\r\n", size, (uint_t) p);
648 
649  //Return a pointer to the newly allocated memory block
650  return p;
651 }
652 
653 
654 /**
655  * @brief Release a previously allocated memory block
656  * @param[in] p Previously allocated memory block to be freed
657  **/
658 
659 void osFreeMem(void *p)
660 {
661  //Make sure the pointer is valid
662  if(p != NULL)
663  {
664  //Debug message
665  TRACE_DEBUG("Freeing memory at 0x%08X\r\n", (uint_t) p);
666 
667  //Enter critical section
669  //Free memory block
670  free(p);
671  //Leave critical section
673  }
674 }
RTOS abstraction layer (CMSIS-RTOS)
int bool_t
Definition: compiler_port.h:49
signed int int_t
Definition: compiler_port.h:44
void osSwitchTask(void)
Yield control to the next task.
uint8_t p
Definition: ndp.h:298
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
#define TRUE
Definition: os_port.h:50
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
Event object.
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
char_t name[]
osSemaphoreId id
Semaphore object.
void osResumeAllTasks(void)
Resume scheduler activity.
#define FALSE
Definition: os_port.h:46
void osSuspendAllTasks(void)
Suspend scheduler activity.
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
Task object.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
osSemaphoreId id
#define OS_SYSTICKS_TO_MS(n)
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
osMutexId id
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
#define MIN(a, b)
Definition: os_port.h:62
systime_t osGetSystemTime(void)
Retrieve system time.
Mutex object.
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
#define TRACE_DEBUG(...)
Definition: debug.h:106
void osDeleteTask(OsTask *task)
Delete a task.
char char_t
Definition: compiler_port.h:43
void * osAllocMem(size_t size)
Allocate a memory block.
uint32_t time
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void(* OsTaskCode)(void *param)
Task routine.
uint8_t n
void osInitKernel(void)
Kernel initialization.
void osDeleteEvent(OsEvent *event)
Delete an event object.
void osFreeMem(void *p)
Release a previously allocated memory block.
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osDelayTask(systime_t delay)
Delay routine.
unsigned int uint_t
Definition: compiler_port.h:45
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
void osStartKernel(void)
Start kernel.
uint16_t priority
Definition: dns_common.h:221
RTOS abstraction layer.
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
uint32_t systime_t
Definition: compiler_port.h:46
Debugging facilities.
OsTask * osCreateTask(const char_t *name, OsTaskCode taskCode, void *param, size_t stackSize, int_t priority)
Create a new task.
#define INFINITE_DELAY
Definition: os_port.h:74