os_port_rtx.c
Go to the documentation of this file.
1 /**
2  * @file os_port_rtx.c
3  * @brief RTOS abstraction layer (Keil RTX)
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 <string.h>
36 #include "os_port.h"
37 #include "os_port_rtx.h"
38 #include "debug.h"
39 
40 //Variables
41 static bool_t running = FALSE;
42 
43 //Default task parameters
45 {
46  NULL, //Stack
47  256, //Size of the stack
48  1 //Task priority
49 };
50 
51 
52 /**
53  * @brief Kernel initialization
54  **/
55 
56 void osInitKernel(void)
57 {
58  //The scheduler is not running
59  running = FALSE;
60 }
61 
62 
63 /**
64  * @brief Start kernel
65  * @param[in] task Pointer to the task function to start after the kernel is initialized
66  **/
67 
69 {
70  //The scheduler is now running
71  running = TRUE;
72  //Start the scheduler
73  os_sys_init(task);
74 }
75 
76 
77 /**
78  * @brief Create a task
79  * @param[in] name NULL-terminated string identifying the task
80  * @param[in] taskCode Pointer to the task entry function
81  * @param[in] arg Argument passed to the task function
82  * @param[in] params Task parameters
83  * @return Task identifier referencing the newly created task
84  **/
85 
86 OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg,
87  const OsTaskParameters *params)
88 {
89  OS_TID taskId;
90 
91  //Static allocation?
92  if(params->stack != NULL)
93  {
94  //Create a new task
95  taskId = os_tsk_create_user_ex(taskCode, params->priority, params->stack,
96  params->stackSize * sizeof(uint32_t), arg);
97  }
98  else
99  {
100  //Create a new task
101  taskId = os_tsk_create_ex(taskCode, params->priority, arg);
102  }
103 
104  //Return the handle referencing the newly created task
105  return (OsTaskId) taskId;
106 }
107 
108 
109 /**
110  * @brief Delete a task
111  * @param[in] taskId Task identifier referencing the task to be deleted
112  **/
113 
114 void osDeleteTask(OsTaskId taskId)
115 {
116  //Delete the currently running task?
117  if(taskId == OS_SELF_TASK_ID)
118  {
119  //Kill ourselves
120  os_tsk_delete_self();
121  }
122  else
123  {
124  //Delete the specified task
125  os_tsk_delete((OS_TID) taskId);
126  }
127 }
128 
129 
130 /**
131  * @brief Delay routine
132  * @param[in] delay Amount of time for which the calling task should block
133  **/
134 
136 {
137  uint16_t n;
138 
139  //Convert milliseconds to system ticks
140  delay = OS_MS_TO_SYSTICKS(delay);
141 
142  //Delay the task for the specified duration
143  while(delay > 0)
144  {
145  //The delay value cannot be higher than 0xFFFE...
146  n = MIN(delay, 0xFFFE);
147  //Wait for the specified amount of time
148  os_dly_wait(n);
149  //Decrement delay value
150  delay -= n;
151  }
152 }
153 
154 
155 /**
156  * @brief Yield control to the next task
157  **/
158 
159 void osSwitchTask(void)
160 {
161  //Pass control to the next task
162  os_tsk_pass();
163 }
164 
165 
166 /**
167  * @brief Suspend scheduler activity
168  **/
169 
171 {
172  //Make sure the operating system is running
173  if(running)
174  {
175  //Suspend all tasks
176  tsk_lock();
177  }
178 }
179 
180 
181 /**
182  * @brief Resume scheduler activity
183  **/
184 
186 {
187  //Make sure the operating system is running
188  if(running)
189  {
190  //Resume all tasks
191  tsk_unlock();
192  }
193 }
194 
195 
196 /**
197  * @brief Create an event object
198  * @param[in] event Pointer to the event object
199  * @return The function returns TRUE if the event object was successfully
200  * created. Otherwise, FALSE is returned
201  **/
202 
204 {
205  //Initialize the event object
206  os_sem_init(event, 0);
207 
208  //Event successfully created
209  return TRUE;
210 }
211 
212 
213 /**
214  * @brief Delete an event object
215  * @param[in] event Pointer to the event object
216  **/
217 
218 void osDeleteEvent(OsEvent *event)
219 {
220  //No resource to release
221 }
222 
223 
224 /**
225  * @brief Set the specified event object to the signaled state
226  * @param[in] event Pointer to the event object
227  **/
228 
229 void osSetEvent(OsEvent *event)
230 {
231  //Set the specified event to the signaled state
232  os_sem_send(event);
233 }
234 
235 
236 /**
237  * @brief Set the specified event object to the nonsignaled state
238  * @param[in] event Pointer to the event object
239  **/
240 
241 void osResetEvent(OsEvent *event)
242 {
243  OS_RESULT res;
244 
245  //Force the specified event to the nonsignaled state
246  do
247  {
248  //Decrement the semaphore's count by one
249  res = os_sem_wait(event, 0);
250 
251  //Check status
252  } while(res == OS_R_OK);
253 }
254 
255 
256 /**
257  * @brief Wait until the specified event is in the signaled state
258  * @param[in] event Pointer to the event object
259  * @param[in] timeout Timeout interval
260  * @return The function returns TRUE if the state of the specified object is
261  * signaled. FALSE is returned if the timeout interval elapsed
262  **/
263 
265 {
266  uint16_t n;
267  OS_RESULT res;
268 
269  //Wait until the specified event is in the signaled state or the timeout
270  //interval elapses
271  if(timeout == INFINITE_DELAY)
272  {
273  //Infinite timeout period
274  res = os_sem_wait(event, 0xFFFF);
275  }
276  else
277  {
278  //Convert milliseconds to system ticks
279  timeout = OS_MS_TO_SYSTICKS(timeout);
280 
281  //Loop until the assigned time period has elapsed
282  do
283  {
284  //The timeout value cannot be higher than 0xFFFE...
285  n = MIN(timeout, 0xFFFE);
286  //Wait for the specified time interval
287  res = os_sem_wait(event, n);
288  //Decrement timeout value
289  timeout -= n;
290 
291  //Check timeout value
292  } while(res == OS_R_TMO && timeout > 0);
293  }
294 
295  //Check whether the specified event is set
296  if(res == OS_R_OK || res == OS_R_SEM)
297  {
298  //Force the event back to the nonsignaled state
299  do
300  {
301  //Decrement the semaphore's count by one
302  res = os_sem_wait(event, 0);
303 
304  //Check status
305  } while(res == OS_R_OK);
306 
307  //The specified event is in the signaled state
308  return TRUE;
309  }
310  else
311  {
312  //The timeout interval elapsed
313  return FALSE;
314  }
315 }
316 
317 
318 /**
319  * @brief Set an event object to the signaled state from an interrupt service routine
320  * @param[in] event Pointer to the event object
321  * @return TRUE if setting the event to signaled state caused a task to unblock
322  * and the unblocked task has a priority higher than the currently running task
323  **/
324 
326 {
327  //Set the specified event to the signaled state
328  isr_sem_send(event);
329 
330  //The return value is not relevant
331  return FALSE;
332 }
333 
334 
335 /**
336  * @brief Create a semaphore object
337  * @param[in] semaphore Pointer to the semaphore object
338  * @param[in] count The maximum count for the semaphore object. This value
339  * must be greater than zero
340  * @return The function returns TRUE if the semaphore was successfully
341  * created. Otherwise, FALSE is returned
342  **/
343 
345 {
346  //Initialize the semaphore object
347  os_sem_init(semaphore, count);
348 
349  //Semaphore successfully created
350  return TRUE;
351 }
352 
353 
354 /**
355  * @brief Delete a semaphore object
356  * @param[in] semaphore Pointer to the semaphore object
357  **/
358 
360 {
361  //No resource to release
362 }
363 
364 
365 /**
366  * @brief Wait for the specified semaphore to be available
367  * @param[in] semaphore Pointer to the semaphore object
368  * @param[in] timeout Timeout interval
369  * @return The function returns TRUE if the semaphore is available. FALSE is
370  * returned if the timeout interval elapsed
371  **/
372 
374 {
375  uint16_t n;
376  OS_RESULT res;
377 
378  //Wait until the semaphore is available or the timeout interval elapses
379  if(timeout == INFINITE_DELAY)
380  {
381  //Infinite timeout period
382  res = os_sem_wait(semaphore, 0xFFFF);
383  }
384  else
385  {
386  //Convert milliseconds to system ticks
387  timeout = OS_MS_TO_SYSTICKS(timeout);
388 
389  //Loop until the assigned time period has elapsed
390  do
391  {
392  //The timeout value cannot be higher than 0xFFFE...
393  n = MIN(timeout, 0xFFFE);
394  //Wait for the specified time interval
395  res = os_sem_wait(semaphore, n);
396  //Decrement timeout value
397  timeout -= n;
398 
399  //Check timeout value
400  } while(res == OS_R_TMO && timeout > 0);
401  }
402 
403  //Check whether the specified semaphore is available
404  if(res == OS_R_OK || res == OS_R_SEM)
405  {
406  return TRUE;
407  }
408  else
409  {
410  return FALSE;
411  }
412 }
413 
414 
415 /**
416  * @brief Release the specified semaphore object
417  * @param[in] semaphore Pointer to the semaphore object
418  **/
419 
421 {
422  //Release the semaphore
423  os_sem_send(semaphore);
424 }
425 
426 
427 /**
428  * @brief Create a mutex object
429  * @param[in] mutex Pointer to the mutex object
430  * @return The function returns TRUE if the mutex was successfully
431  * created. Otherwise, FALSE is returned
432  **/
433 
435 {
436  //Initialize the mutex object
437  os_mut_init(mutex);
438 
439  //Mutex successfully created
440  return TRUE;
441 }
442 
443 
444 /**
445  * @brief Delete a mutex object
446  * @param[in] mutex Pointer to the mutex object
447  **/
448 
449 void osDeleteMutex(OsMutex *mutex)
450 {
451  //No resource to release
452 }
453 
454 
455 /**
456  * @brief Acquire ownership of the specified mutex object
457  * @param[in] mutex Pointer to the mutex object
458  **/
459 
461 {
462  //Obtain ownership of the mutex object
463  os_mut_wait(mutex, 0xFFFF);
464 }
465 
466 
467 /**
468  * @brief Release ownership of the specified mutex object
469  * @param[in] mutex Pointer to the mutex object
470  **/
471 
473 {
474  //Release ownership of the mutex object
475  os_mut_release(mutex);
476 }
477 
478 
479 /**
480  * @brief Retrieve system time
481  * @return Number of milliseconds elapsed since the system was last started
482  **/
483 
485 {
486  systime_t time;
487 
488  //Get current tick count
489  time = os_time_get();
490 
491  //Convert system ticks to milliseconds
492  return OS_SYSTICKS_TO_MS(time);
493 }
494 
495 
496 /**
497  * @brief Allocate a memory block
498  * @param[in] size Bytes to allocate
499  * @return A pointer to the allocated memory block or NULL if
500  * there is insufficient memory available
501  **/
502 
503 __weak_func void *osAllocMem(size_t size)
504 {
505  void *p;
506 
507  //Enter critical section
509  //Allocate a memory block
510  p = malloc(size);
511  //Leave critical section
513 
514  //Debug message
515  TRACE_DEBUG("Allocating %" PRIuSIZE " bytes at 0x%08" PRIXPTR "\r\n",
516  size, (uintptr_t) p);
517 
518  //Return a pointer to the newly allocated memory block
519  return p;
520 }
521 
522 
523 /**
524  * @brief Release a previously allocated memory block
525  * @param[in] p Previously allocated memory block to be freed
526  **/
527 
528 __weak_func void osFreeMem(void *p)
529 {
530  //Make sure the pointer is valid
531  if(p != NULL)
532  {
533  //Debug message
534  TRACE_DEBUG("Freeing memory at 0x%08" PRIXPTR "\r\n", (uintptr_t) p);
535 
536  //Enter critical section
538  //Free memory block
539  free(p);
540  //Leave critical section
542  }
543 }
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_MS_TO_SYSTICKS(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.
Definition: os_port_rtx.c:159
void osResumeAllTasks(void)
Resume scheduler activity.
Definition: os_port_rtx.c:185
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
Definition: os_port_rtx.c:434
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
Definition: os_port_rtx.c:264
void osDeleteEvent(OsEvent *event)
Delete an event object.
Definition: os_port_rtx.c:218
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
Definition: os_port_rtx.c:449
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
Definition: os_port_rtx.c:420
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
Definition: os_port_rtx.c:44
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
Definition: os_port_rtx.c:503
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
Definition: os_port_rtx.c:359
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
Definition: os_port_rtx.c:460
void osDelayTask(systime_t delay)
Delay routine.
Definition: os_port_rtx.c:135
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
Definition: os_port_rtx.c:528
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
Definition: os_port_rtx.c:373
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
Definition: os_port_rtx.c:86
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Definition: os_port_rtx.c:472
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
Definition: os_port_rtx.c:241
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
Definition: os_port_rtx.c:325
void osStartKernel(OsInitTaskCode task)
Start kernel.
Definition: os_port_rtx.c:68
void osDeleteTask(OsTaskId taskId)
Delete a task.
Definition: os_port_rtx.c:114
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
Definition: os_port_rtx.c:344
systime_t osGetSystemTime(void)
Retrieve system time.
Definition: os_port_rtx.c:484
void osSuspendAllTasks(void)
Suspend scheduler activity.
Definition: os_port_rtx.c:170
bool_t osCreateEvent(OsEvent *event)
Create an event object.
Definition: os_port_rtx.c:203
void osInitKernel(void)
Kernel initialization.
Definition: os_port_rtx.c:56
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
Definition: os_port_rtx.c:229
RTOS abstraction layer (Keil RTX)
void(* OsInitTaskCode)(void)
Initialization task.
Definition: os_port_rtx.h:142
const uint8_t res[]
char_t name[]
Event object.
Mutex object.
Semaphore object.
Task parameters.