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