1 /***********************************************************************************************//**
2 * \file cyabs_rtos_freertos.c
3 *
4 * \brief
5 * Implementation for FreeRTOS abstraction
6 *
7 ***************************************************************************************************
8 * \copyright
9 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 **************************************************************************************************/
26
27 #include <cy_utils.h>
28 #include <cy_result.h>
29 #include <cyabs_rtos.h>
30 #include <stdlib.h>
31 #include <FreeRTOS.h>
32 #include <task.h>
33 #include "cyabs_rtos_internal.h"
34
35 static const uint32_t TASK_IDENT = 0xABCDEF01U;
36
37
38 typedef struct
39 {
40 cy_timer_callback_t cb;
41 cy_timer_callback_arg_t arg;
42 } callback_data_t;
43
44
45 // Wrapper function to convert FreeRTOS callback signature to match expectation
46 // for our cyabs_rtos abstraction API.
timer_callback(TimerHandle_t arg)47 static void timer_callback(TimerHandle_t arg)
48 {
49 callback_data_t* cb_arg = (callback_data_t*)pvTimerGetTimerID(arg);
50 if (NULL != cb_arg->cb)
51 {
52 cb_arg->cb(cb_arg->arg);
53 }
54 }
55
56
57 //==================================================================================================
58 // Error Converter
59 //==================================================================================================
60
61 //--------------------------------------------------------------------------------------------------
62 // cy_rtos_last_error
63 //--------------------------------------------------------------------------------------------------
cy_rtos_last_error(void)64 cy_rtos_error_t cy_rtos_last_error(void)
65 {
66 return pdFALSE;
67 }
68
69
70 //==================================================================================================
71 // Threads
72 //==================================================================================================
73
74 typedef struct
75 {
76 StaticTask_t task;
77 SemaphoreHandle_t sema;
78 uint32_t magic;
79 void* memptr;
80 } cy_task_wrapper_t;
81
82
83 //--------------------------------------------------------------------------------------------------
84 // cy_rtos_thread_create
85 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_create(cy_thread_t * thread,cy_thread_entry_fn_t entry_function,const char * name,void * stack,uint32_t stack_size,cy_thread_priority_t priority,cy_thread_arg_t arg)86 cy_rslt_t cy_rtos_thread_create(cy_thread_t* thread, cy_thread_entry_fn_t entry_function,
87 const char* name, void* stack, uint32_t stack_size,
88 cy_thread_priority_t priority, cy_thread_arg_t arg)
89 {
90 cy_rslt_t status;
91 if ((thread == NULL) || (stack_size < CY_RTOS_MIN_STACK_SIZE))
92 {
93 status = CY_RTOS_BAD_PARAM;
94 }
95 else if ((stack != NULL) && (0 != (((uint32_t)stack) & CY_RTOS_ALIGNMENT_MASK)))
96 {
97 status = CY_RTOS_ALIGNMENT_ERROR;
98 }
99 else
100 {
101 // If the user provides a stack, we need to allocate memory for the StaticTask_t. If we
102 // allocate memory we also need to clean it up. This is true when the task exits itself or
103 // when it is killed. In the case it is killed is fairly straight forward. In the case
104 // where it exits, we can't clean up any allocated memory since we can't free it before
105 // calling vTaskDelete() and vTaskDelete() never returns. Thus we need to do it in join.
106 // However, if the task exited itself it has also released any memory it allocated. Thus
107 // in order to be able to reliably free memory as part of join, we need to know that the
108 // data we are accessing (the StaticTask_t) has not been freed. We therefore need to always
109 // allocate that object ourselves. This means we also need to allocate the stack if the
110 // user did not provide one.
111 uint32_t offset = (stack == NULL)
112 ? (stack_size & ~CY_RTOS_ALIGNMENT_MASK)
113 : 0;
114 uint32_t size = offset + sizeof(cy_task_wrapper_t);
115 uint8_t* ident = (uint8_t*)pvPortMalloc(size);
116
117 if (ident == NULL)
118 {
119 status = CY_RTOS_NO_MEMORY;
120 }
121 else
122 {
123 StackType_t stack_size_rtos =
124 ((stack_size & ~CY_RTOS_ALIGNMENT_MASK) / sizeof(StackType_t));
125 StackType_t* stack_rtos = (stack == NULL)
126 ? (StackType_t*)ident
127 : (StackType_t*)stack;
128
129 cy_task_wrapper_t* wrapper = (cy_task_wrapper_t*)(ident + offset);
130 wrapper->sema = xSemaphoreCreateBinary();
131 CY_ASSERT(wrapper->sema != NULL);
132 wrapper->magic = TASK_IDENT;
133 wrapper->memptr = ident;
134 CY_ASSERT(((uint32_t)wrapper & CY_RTOS_ALIGNMENT_MASK) == 0UL);
135 *thread = xTaskCreateStatic((TaskFunction_t)entry_function, name, stack_size_rtos, arg,
136 (UBaseType_t)priority, stack_rtos, &(wrapper->task));
137 CY_ASSERT(((void*)*thread == (void*)&(wrapper->task)) || (*thread == NULL));
138 status = CY_RSLT_SUCCESS;
139 }
140 }
141 return status;
142 }
143
144
145 //--------------------------------------------------------------------------------------------------
146 // cy_rtos_thread_exit
147 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_exit(void)148 cy_rslt_t cy_rtos_thread_exit(void)
149 {
150 TaskHandle_t handle = xTaskGetCurrentTaskHandle();
151 // Ideally this would just call vTaskDelete(NULL); however FreeRTOS
152 // does not provide any way to know when the task is actually cleaned
153 // up. It will tell you that it has been deleted, but when delete is
154 // called from the thread itself it doesn't actually get deleted at
155 // that time. It just gets added to the list of items that will be
156 // deleted when the idle task runs, but there is no way of knowing
157 // that the idle task ran unless you add an application hook which is
158 // not something that can be done here. This means that
159 // cy_rtos_join_thread() has no way of knowing that it is actually
160 // save to cleanup memory. So, instad of deleting here, we use a
161 // semaphore to indicate that we can delete and then join waits on
162 // the semaphore.
163
164 // This cast is ok because the handle internally represents the TCB that we created in the
165 // thread create function.
166 cy_task_wrapper_t* wrapper = ((cy_task_wrapper_t*)handle);
167 if (wrapper->magic == TASK_IDENT)
168 {
169 // This signals to the thread deleting the current thread that it it is safe to delete the
170 // current thread.
171 xSemaphoreGive(wrapper->sema);
172 }
173 else
174 {
175 CY_ASSERT(false);
176 }
177
178 // This function is not expected to return and calling cy_rtos_join_thread will call vTaskDelete
179 // on this thread and clean up.
180 while (1)
181 {
182 #if defined(INCLUDE_vTaskSuspend)
183 vTaskSuspend(handle);
184 #else
185 vTaskDelay(10000);
186 #endif
187 }
188 }
189
190
191 //--------------------------------------------------------------------------------------------------
192 // cy_rtos_thread_terminate
193 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_terminate(cy_thread_t * thread)194 cy_rslt_t cy_rtos_thread_terminate(cy_thread_t* thread)
195 {
196 cy_rslt_t status;
197 if (thread == NULL)
198 {
199 status = CY_RTOS_BAD_PARAM;
200 }
201 else
202 {
203 vTaskDelete(*thread);
204 // Check to see if we allocated the task and if so free it up.
205 cy_task_wrapper_t* wrapper = ((cy_task_wrapper_t*)*thread);
206 vTaskSuspendAll();
207 if (wrapper->magic == TASK_IDENT)
208 {
209 wrapper->magic = 0;
210 vSemaphoreDelete(wrapper->sema);
211 vPortFree(wrapper->memptr);
212 }
213 xTaskResumeAll();
214 status = CY_RSLT_SUCCESS;
215 }
216 return status;
217 }
218
219
220 //--------------------------------------------------------------------------------------------------
221 // cy_rtos_thread_is_running
222 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_is_running(cy_thread_t * thread,bool * running)223 cy_rslt_t cy_rtos_thread_is_running(cy_thread_t* thread, bool* running)
224 {
225 cy_rslt_t status;
226 if ((thread == NULL) || (running == NULL))
227 {
228 status = CY_RTOS_BAD_PARAM;
229 }
230 else
231 {
232 eTaskState st = eTaskGetState(*thread);
233 *running = (st == eRunning);
234 status = CY_RSLT_SUCCESS;
235 }
236 return status;
237 }
238
239
240 //--------------------------------------------------------------------------------------------------
241 // cy_rtos_thread_get_state
242 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_state(cy_thread_t * thread,cy_thread_state_t * state)243 cy_rslt_t cy_rtos_thread_get_state(cy_thread_t* thread, cy_thread_state_t* state)
244 {
245 cy_rslt_t status;
246 if ((thread == NULL) || (state == NULL))
247 {
248 status = CY_RTOS_BAD_PARAM;
249 }
250 else
251 {
252 eTaskState st = eTaskGetState(*thread);
253 switch (st)
254 {
255 case eSuspended:
256 *state = CY_THREAD_STATE_INACTIVE;
257 break;
258
259 case eReady:
260 *state = CY_THREAD_STATE_READY;
261 break;
262
263 case eRunning:
264 *state = CY_THREAD_STATE_RUNNING;
265 break;
266
267 case eBlocked:
268 *state = CY_THREAD_STATE_BLOCKED;
269 break;
270
271 case eDeleted:
272 *state = CY_THREAD_STATE_TERMINATED;
273 break;
274
275 case eInvalid:
276 default:
277 *state = CY_THREAD_STATE_UNKNOWN;
278 break;
279 }
280
281 status = CY_RSLT_SUCCESS;
282 }
283 return status;
284 }
285
286
287 //--------------------------------------------------------------------------------------------------
288 // cy_rtos_thread_join
289 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_join(cy_thread_t * thread)290 cy_rslt_t cy_rtos_thread_join(cy_thread_t* thread)
291 {
292 cy_rslt_t status = CY_RSLT_SUCCESS;
293 if (thread == NULL)
294 {
295 status = CY_RTOS_BAD_PARAM;
296 }
297 else
298 {
299 cy_task_wrapper_t* wrapper = ((cy_task_wrapper_t*)(*thread));
300 // This makes sure that the thread to be deleted has completed. See cy_rtos_exit_thread()
301 // for description of why this is done.
302 if (wrapper->magic == TASK_IDENT)
303 {
304 xSemaphoreTake(wrapper->sema, portMAX_DELAY);
305 status = cy_rtos_terminate_thread(thread);
306 }
307 *thread = NULL;
308 }
309 return status;
310 }
311
312
313 //--------------------------------------------------------------------------------------------------
314 // cy_rtos_thread_get_handle
315 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_handle(cy_thread_t * thread)316 cy_rslt_t cy_rtos_thread_get_handle(cy_thread_t* thread)
317 {
318 cy_rslt_t status = CY_RSLT_SUCCESS;
319
320 if (thread == NULL)
321 {
322 status = CY_RTOS_BAD_PARAM;
323 }
324 else
325 {
326 *thread = xTaskGetCurrentTaskHandle();
327 }
328
329 return status;
330 }
331
332
333 //--------------------------------------------------------------------------------------------------
334 // cy_rtos_thread_wait_notification
335 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_wait_notification(cy_time_t timeout_ms)336 cy_rslt_t cy_rtos_thread_wait_notification(cy_time_t timeout_ms)
337 {
338 uint32_t ret;
339
340 ret = ulTaskNotifyTake(pdTRUE, (timeout_ms == CY_RTOS_NEVER_TIMEOUT) ?
341 portMAX_DELAY : convert_ms_to_ticks(timeout_ms));
342 if (0 != ret)
343 {
344 /* Received notify from another thread or ISR */
345 return CY_RSLT_SUCCESS;
346 }
347 else
348 {
349 return CY_RTOS_TIMEOUT;
350 }
351 }
352
353
354 //--------------------------------------------------------------------------------------------------
355 // cy_rtos_thread_set_notification
356 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_set_notification(cy_thread_t * thread)357 cy_rslt_t cy_rtos_thread_set_notification(cy_thread_t* thread)
358 {
359 cy_rslt_t status;
360 if (thread == NULL)
361 {
362 status = CY_RTOS_BAD_PARAM;
363 }
364 else
365 {
366 if (is_in_isr())
367 {
368 BaseType_t taskWoken = pdFALSE;
369 /* No error checking as this function always returns pdPASS. */
370 vTaskNotifyGiveFromISR(*thread, &taskWoken);
371 portEND_SWITCHING_ISR(taskWoken);
372 }
373 else
374 {
375 /* No error checking as this function always returns pdPASS. */
376 xTaskNotifyGive(*thread);
377 }
378 status = CY_RSLT_SUCCESS;
379 }
380 return status;
381 }
382
383
384 //--------------------------------------------------------------------------------------------------
385 // cy_rtos_thread_get_name
386 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_name(cy_thread_t * thread,const char ** thread_name)387 cy_rslt_t cy_rtos_thread_get_name(cy_thread_t* thread, const char** thread_name)
388 {
389 *thread_name = pcTaskGetName(*thread);
390 return CY_RSLT_SUCCESS;
391 }
392
393
394 //==================================================================================================
395 // Scheduler
396 //==================================================================================================
397 static uint16_t _cy_rtos_suspend_count = 0;
398 static uint16_t _cy_rtos_suspend_count_from_ISR = 0;
399 UBaseType_t uxSavedInterruptStatus[CY_RTOS_MAX_SUSPEND_NESTING];
400 //--------------------------------------------------------------------------------------------------
401 // cy_rtos_scheduler_suspend
402 //--------------------------------------------------------------------------------------------------
cy_rtos_scheduler_suspend(void)403 cy_rslt_t cy_rtos_scheduler_suspend(void)
404 {
405 cy_rslt_t status = CY_RSLT_SUCCESS;
406 if (is_in_isr())
407 {
408 if (_cy_rtos_suspend_count_from_ISR < (CY_RTOS_MAX_SUSPEND_NESTING -1))
409 {
410 uxSavedInterruptStatus[_cy_rtos_suspend_count_from_ISR] = taskENTER_CRITICAL_FROM_ISR();
411 ++_cy_rtos_suspend_count_from_ISR;
412 }
413 else
414 {
415 status = CY_RTOS_BAD_PARAM;
416 }
417 }
418 else
419 {
420 taskENTER_CRITICAL();
421 }
422
423 if (status == CY_RSLT_SUCCESS)
424 {
425 ++_cy_rtos_suspend_count;
426 }
427
428 return status;
429 }
430
431
432 //--------------------------------------------------------------------------------------------------
433 // cy_rtos_scheduler_resume
434 //--------------------------------------------------------------------------------------------------
cy_rtos_scheduler_resume(void)435 cy_rslt_t cy_rtos_scheduler_resume(void)
436 {
437 cy_rslt_t status;
438 if (_cy_rtos_suspend_count > 0)
439 {
440 if (is_in_isr())
441 {
442 if (_cy_rtos_suspend_count_from_ISR > 0) //We have at least one suspend from ISR call
443 {
444 taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus[_cy_rtos_suspend_count_from_ISR -
445 1]);
446 --_cy_rtos_suspend_count_from_ISR;
447 status = CY_RSLT_SUCCESS;
448 }
449 else
450 {
451 status = CY_RTOS_BAD_PARAM;
452 }
453 }
454 else
455 {
456 taskEXIT_CRITICAL();
457 status = CY_RSLT_SUCCESS;
458 }
459 --_cy_rtos_suspend_count;
460 }
461 else
462 {
463 status = CY_RTOS_BAD_PARAM;
464 }
465 return status;
466 }
467
468
469 //==================================================================================================
470 // Mutexes
471 //==================================================================================================
472
473 //--------------------------------------------------------------------------------------------------
474 // cy_rtos_mutex_init
475 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_init(cy_mutex_t * mutex,bool recursive)476 cy_rslt_t cy_rtos_mutex_init(cy_mutex_t* mutex, bool recursive)
477 {
478 cy_rslt_t status;
479 if (mutex == NULL)
480 {
481 status = CY_RTOS_BAD_PARAM;
482 }
483 else
484 {
485 mutex->is_recursive = recursive;
486 mutex->mutex_handle = recursive
487 ? xSemaphoreCreateRecursiveMutex()
488 : xSemaphoreCreateMutex();
489 if (mutex->mutex_handle == NULL)
490 {
491 status = CY_RTOS_NO_MEMORY;
492 }
493 else
494 {
495 status = CY_RSLT_SUCCESS;
496 }
497 }
498 return status;
499 }
500
501
502 #if defined(FREERTOS_COMMON_SECTION_BEGIN)
503 FREERTOS_COMMON_SECTION_BEGIN
504 #endif
505 //--------------------------------------------------------------------------------------------------
506 // cy_rtos_mutex_get
507 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_get(cy_mutex_t * mutex,cy_time_t timeout_ms)508 cy_rslt_t cy_rtos_mutex_get(cy_mutex_t* mutex, cy_time_t timeout_ms)
509 {
510 cy_rslt_t status;
511 if (mutex == NULL)
512 {
513 status = CY_RTOS_BAD_PARAM;
514 }
515 else
516 {
517 TickType_t ticks = convert_ms_to_ticks(timeout_ms);
518 BaseType_t result = (mutex->is_recursive)
519 ? xSemaphoreTakeRecursive(mutex->mutex_handle, ticks)
520 : xSemaphoreTake(mutex->mutex_handle, ticks);
521
522 status = (result == pdFALSE)
523 ? CY_RTOS_TIMEOUT
524 : CY_RSLT_SUCCESS;
525 }
526 return status;
527 }
528
529
530 #if defined(FREERTOS_COMMON_SECTION_END)
531 FREERTOS_COMMON_SECTION_END
532 #endif
533
534
535 #if defined(FREERTOS_COMMON_SECTION_BEGIN)
536 FREERTOS_COMMON_SECTION_BEGIN
537 #endif
538 //--------------------------------------------------------------------------------------------------
539 // cy_rtos_mutex_set
540 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_set(cy_mutex_t * mutex)541 cy_rslt_t cy_rtos_mutex_set(cy_mutex_t* mutex)
542 {
543 cy_rslt_t status;
544 if (mutex == NULL)
545 {
546 status = CY_RTOS_BAD_PARAM;
547 }
548 else
549 {
550 BaseType_t result = (mutex->is_recursive)
551 ? xSemaphoreGiveRecursive(mutex->mutex_handle)
552 : xSemaphoreGive(mutex->mutex_handle);
553
554 status = (result == pdFALSE)
555 ? CY_RTOS_GENERAL_ERROR
556 : CY_RSLT_SUCCESS;
557 }
558 return status;
559 }
560
561
562 #if defined(FREERTOS_COMMON_SECTION_END)
563 FREERTOS_COMMON_SECTION_END
564 #endif
565
566 //--------------------------------------------------------------------------------------------------
567 // cy_rtos_mutex_deinit
568 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_deinit(cy_mutex_t * mutex)569 cy_rslt_t cy_rtos_mutex_deinit(cy_mutex_t* mutex)
570 {
571 cy_rslt_t status;
572 if (mutex == NULL)
573 {
574 status = CY_RTOS_BAD_PARAM;
575 }
576 else
577 {
578 vSemaphoreDelete(mutex->mutex_handle);
579 status = CY_RSLT_SUCCESS;
580 }
581 return status;
582 }
583
584
585 //==================================================================================================
586 // Semaphores
587 //==================================================================================================
588
589 //--------------------------------------------------------------------------------------------------
590 // cy_rtos_semaphore_init
591 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_init(cy_semaphore_t * semaphore,uint32_t maxcount,uint32_t initcount)592 cy_rslt_t cy_rtos_semaphore_init(cy_semaphore_t* semaphore, uint32_t maxcount, uint32_t initcount)
593 {
594 cy_rslt_t status;
595 if (semaphore == NULL)
596 {
597 status = CY_RTOS_BAD_PARAM;
598 }
599 else
600 {
601 *semaphore = xSemaphoreCreateCounting(maxcount, initcount);
602 if (*semaphore == NULL)
603 {
604 status = CY_RTOS_NO_MEMORY;
605 }
606 else
607 {
608 status = CY_RSLT_SUCCESS;
609 }
610 }
611 return status;
612 }
613
614
615 //--------------------------------------------------------------------------------------------------
616 // cy_rtos_semaphore_get
617 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_get(cy_semaphore_t * semaphore,cy_time_t timeout_ms)618 cy_rslt_t cy_rtos_semaphore_get(cy_semaphore_t* semaphore, cy_time_t timeout_ms)
619 {
620 cy_rslt_t status;
621 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
622 // xSemaphoreTakeFromISR does not take timeout as a parameter
623 // since it cannot block. Hence we return an error if the user
624 // tries to set a timeout.
625 if ((semaphore == NULL) || (is_in_isr() && (timeout_ms != 0)))
626 {
627 status = CY_RTOS_BAD_PARAM;
628 }
629 else
630 {
631 TickType_t ticks = convert_ms_to_ticks(timeout_ms);
632 status = CY_RSLT_SUCCESS;
633
634 if (is_in_isr())
635 {
636 if (pdFALSE == xSemaphoreTakeFromISR(*semaphore, &xHigherPriorityTaskWoken))
637 {
638 status = CY_RTOS_TIMEOUT;
639 }
640 else
641 {
642 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
643 }
644 }
645 else
646 {
647 if (pdFALSE == xSemaphoreTake(*semaphore, ticks))
648 {
649 status = CY_RTOS_TIMEOUT;
650 }
651 }
652 }
653
654 return status;
655 }
656
657
658 //--------------------------------------------------------------------------------------------------
659 // cy_rtos_semaphore_set
660 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_set(cy_semaphore_t * semaphore)661 cy_rslt_t cy_rtos_semaphore_set(cy_semaphore_t* semaphore)
662 {
663 cy_rslt_t status;
664 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
665 if (semaphore == NULL)
666 {
667 status = CY_RTOS_BAD_PARAM;
668 }
669 else
670 {
671 BaseType_t ret;
672
673 if (is_in_isr())
674 {
675 ret = xSemaphoreGiveFromISR(*semaphore, &xHigherPriorityTaskWoken);
676 if (ret == pdTRUE)
677 {
678 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
679 }
680 }
681 else
682 {
683 ret = xSemaphoreGive(*semaphore);
684 }
685
686 if (ret == pdFALSE)
687 {
688 status = CY_RTOS_GENERAL_ERROR;
689 }
690 else
691 {
692 status = CY_RSLT_SUCCESS;
693 }
694 }
695
696 return status;
697 }
698
699
700 //--------------------------------------------------------------------------------------------------
701 // cy_rtos_semaphore_get_count
702 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_get_count(cy_semaphore_t * semaphore,size_t * count)703 cy_rslt_t cy_rtos_semaphore_get_count(cy_semaphore_t* semaphore, size_t* count)
704 {
705 cy_rslt_t status;
706 if (semaphore == NULL)
707 {
708 status = CY_RTOS_BAD_PARAM;
709 }
710 else
711 {
712 *count = uxSemaphoreGetCount(*semaphore);
713 status = CY_RSLT_SUCCESS;
714 }
715 return status;
716 }
717
718
719 //--------------------------------------------------------------------------------------------------
720 // cy_rtos_semaphore_deinit
721 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_deinit(cy_semaphore_t * semaphore)722 cy_rslt_t cy_rtos_semaphore_deinit(cy_semaphore_t* semaphore)
723 {
724 cy_rslt_t status;
725 if (semaphore == NULL)
726 {
727 status = CY_RTOS_BAD_PARAM;
728 }
729 else
730 {
731 vSemaphoreDelete(*semaphore);
732 status = CY_RSLT_SUCCESS;
733 }
734 return status;
735 }
736
737
738 //==================================================================================================
739 // Events
740 //==================================================================================================
741
742 //--------------------------------------------------------------------------------------------------
743 // cy_rtos_init_event
744 //--------------------------------------------------------------------------------------------------
cy_rtos_event_init(cy_event_t * event)745 cy_rslt_t cy_rtos_event_init(cy_event_t* event)
746 {
747 cy_rslt_t status;
748 if (event == NULL)
749 {
750 status = CY_RTOS_BAD_PARAM;
751 }
752 else
753 {
754 *event = xEventGroupCreate();
755 if (*event == NULL)
756 {
757 status = CY_RTOS_NO_MEMORY;
758 }
759 else
760 {
761 status = CY_RSLT_SUCCESS;
762 }
763 }
764 return status;
765 }
766
767
768 //--------------------------------------------------------------------------------------------------
769 // cy_rtos_event_setbits
770 //--------------------------------------------------------------------------------------------------
cy_rtos_event_setbits(cy_event_t * event,uint32_t bits)771 cy_rslt_t cy_rtos_event_setbits(cy_event_t* event, uint32_t bits)
772 {
773 cy_rslt_t status;
774 if (event == NULL)
775 {
776 status = CY_RTOS_BAD_PARAM;
777 }
778 else
779 {
780 BaseType_t ret;
781 if (is_in_isr())
782 {
783 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
784 ret = xEventGroupSetBitsFromISR(*event, (EventBits_t)bits, &xHigherPriorityTaskWoken);
785
786 if (ret == pdTRUE)
787 {
788 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
789 }
790 }
791 else
792 {
793 // xEventGroupSetBits does not return pass/fail, but instead returns the value of the
794 // event bits at the time the function returns. There is potential to
795 // return 0 (value equal to pdFALSE), so instead treat it as successful after the call
796 // to xEventGroupSetBits to avoid false error.
797 xEventGroupSetBits(*event, (EventBits_t)bits);
798 ret = pdTRUE;
799 }
800
801 if (ret == pdFALSE)
802 {
803 status = CY_RTOS_GENERAL_ERROR;
804 }
805 else
806 {
807 status = CY_RSLT_SUCCESS;
808 }
809 }
810 return status;
811 }
812
813
814 //--------------------------------------------------------------------------------------------------
815 // cy_rtos_event_clearbits
816 //--------------------------------------------------------------------------------------------------
cy_rtos_event_clearbits(cy_event_t * event,uint32_t bits)817 cy_rslt_t cy_rtos_event_clearbits(cy_event_t* event, uint32_t bits)
818 {
819 cy_rslt_t status;
820 if (event == NULL)
821 {
822 status = CY_RTOS_BAD_PARAM;
823 }
824 else
825 {
826 BaseType_t ret;
827 if (is_in_isr())
828 {
829 ret = xEventGroupClearBitsFromISR(*event, (EventBits_t)bits);
830 }
831 else
832 {
833 // xEventGroupClearBits does not return pass/fail, but instead returns the value of the
834 // event bits before the requested bits were cleared. There is potential to
835 // return 0 (value equal to pdFALSE), so instead treat it as successful after the call
836 // to xEventGroupClearBits to avoid false error.
837 xEventGroupClearBits(*event, (EventBits_t)bits);
838 ret = pdTRUE;
839 }
840
841 if (ret == pdFALSE)
842 {
843 status = CY_RTOS_GENERAL_ERROR;
844 }
845 else
846 {
847 status = CY_RSLT_SUCCESS;
848 }
849 }
850 return status;
851 }
852
853
854 //--------------------------------------------------------------------------------------------------
855 // cy_rtos_event_getbits
856 //--------------------------------------------------------------------------------------------------
cy_rtos_event_getbits(cy_event_t * event,uint32_t * bits)857 cy_rslt_t cy_rtos_event_getbits(cy_event_t* event, uint32_t* bits)
858 {
859 cy_rslt_t status;
860 if ((event == NULL) || (bits == NULL))
861 {
862 status = CY_RTOS_BAD_PARAM;
863 }
864 else
865 {
866 *bits = xEventGroupGetBits(*event);
867 status = CY_RSLT_SUCCESS;
868 }
869 return status;
870 }
871
872
873 //--------------------------------------------------------------------------------------------------
874 // cy_rtos_event_waitbits
875 //--------------------------------------------------------------------------------------------------
cy_rtos_event_waitbits(cy_event_t * event,uint32_t * bits,bool clear,bool all,cy_time_t timeout_ms)876 cy_rslt_t cy_rtos_event_waitbits(cy_event_t* event, uint32_t* bits, bool clear, bool all,
877 cy_time_t timeout_ms)
878 {
879 cy_rslt_t status;
880 if ((event == NULL) || (bits == NULL))
881 {
882 status = CY_RTOS_BAD_PARAM;
883 }
884 else
885 {
886 TickType_t ticks = convert_ms_to_ticks(timeout_ms);
887 uint32_t bitsVal = *bits;
888
889 *bits = xEventGroupWaitBits(*event, (EventBits_t)bitsVal, (BaseType_t)clear,
890 (BaseType_t)all, ticks);
891 status = (((bitsVal & *bits) == bitsVal) || (((bitsVal & *bits) > 0) & !all))
892 ? CY_RSLT_SUCCESS
893 : CY_RTOS_TIMEOUT;
894 }
895 return status;
896 }
897
898
899 //--------------------------------------------------------------------------------------------------
900 // cy_rtos_event_deinit
901 //--------------------------------------------------------------------------------------------------
cy_rtos_event_deinit(cy_event_t * event)902 cy_rslt_t cy_rtos_event_deinit(cy_event_t* event)
903 {
904 cy_rslt_t status;
905 if (event == NULL)
906 {
907 status = CY_RTOS_BAD_PARAM;
908 }
909 else
910 {
911 vEventGroupDelete(*event);
912 status = CY_RSLT_SUCCESS;
913 }
914 return status;
915 }
916
917
918 //==================================================================================================
919 // Queues
920 //==================================================================================================
921
922 //--------------------------------------------------------------------------------------------------
923 // cy_rtos_queue_init
924 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_init(cy_queue_t * queue,size_t length,size_t itemsize)925 cy_rslt_t cy_rtos_queue_init(cy_queue_t* queue, size_t length, size_t itemsize)
926 {
927 cy_rslt_t status;
928 if (queue == NULL)
929 {
930 status = CY_RTOS_BAD_PARAM;
931 }
932 else
933 {
934 *queue = xQueueCreate(length, itemsize);
935 if (*queue == NULL)
936 {
937 status = CY_RTOS_NO_MEMORY;
938 }
939 else
940 {
941 status = CY_RSLT_SUCCESS;
942 }
943 }
944 return status;
945 }
946
947
948 #if defined(FREERTOS_COMMON_SECTION_BEGIN)
949 FREERTOS_COMMON_SECTION_BEGIN
950 #endif
951 //--------------------------------------------------------------------------------------------------
952 // cy_rtos_queue_put
953 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_put(cy_queue_t * queue,const void * item_ptr,cy_time_t timeout_ms)954 cy_rslt_t cy_rtos_queue_put(cy_queue_t* queue, const void* item_ptr, cy_time_t timeout_ms)
955 {
956 cy_rslt_t status;
957 if ((queue == NULL) || (item_ptr == NULL))
958 {
959 status = CY_RTOS_BAD_PARAM;
960 }
961 else
962 {
963 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
964 BaseType_t ret;
965 if (is_in_isr())
966 {
967 ret = xQueueSendToBackFromISR(*queue, item_ptr, &xHigherPriorityTaskWoken);
968 if (ret == pdTRUE)
969 {
970 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
971 }
972 }
973 else
974 {
975 TickType_t ticks = convert_ms_to_ticks(timeout_ms);
976 ret = xQueueSendToBack(*queue, item_ptr, ticks);
977 }
978
979 if (ret == pdFALSE)
980 {
981 status = CY_RTOS_GENERAL_ERROR;
982 }
983 else
984 {
985 status = CY_RSLT_SUCCESS;
986 }
987 }
988 return status;
989 }
990
991
992 #if defined(FREERTOS_COMMON_SECTION_END)
993 FREERTOS_COMMON_SECTION_END
994 #endif
995
996
997 #if defined(FREERTOS_COMMON_SECTION_BEGIN)
998 FREERTOS_COMMON_SECTION_BEGIN
999 #endif
1000 //--------------------------------------------------------------------------------------------------
1001 // cy_rtos_queue_get
1002 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_get(cy_queue_t * queue,void * item_ptr,cy_time_t timeout_ms)1003 cy_rslt_t cy_rtos_queue_get(cy_queue_t* queue, void* item_ptr, cy_time_t timeout_ms)
1004 {
1005 cy_rslt_t status;
1006 if ((queue == NULL) || (item_ptr == NULL))
1007 {
1008 status = CY_RTOS_BAD_PARAM;
1009 }
1010 else
1011 {
1012 BaseType_t ret;
1013 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
1014 if (is_in_isr())
1015 {
1016 ret = xQueueReceiveFromISR(*queue, item_ptr, &xHigherPriorityTaskWoken);
1017 if (ret == pdTRUE)
1018 {
1019 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
1020 }
1021 }
1022 else
1023 {
1024 TickType_t ticks = convert_ms_to_ticks(timeout_ms);
1025 ret = xQueueReceive(*queue, item_ptr, ticks);
1026 }
1027
1028 if (ret == pdFALSE)
1029 {
1030 status = CY_RTOS_GENERAL_ERROR;
1031 }
1032 else
1033 {
1034 status = CY_RSLT_SUCCESS;
1035 }
1036 }
1037 return status;
1038 }
1039
1040
1041 #if defined(FREERTOS_COMMON_SECTION_END)
1042 FREERTOS_COMMON_SECTION_END
1043 #endif
1044
1045
1046 //--------------------------------------------------------------------------------------------------
1047 // cy_rtos_queue_count
1048 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_count(cy_queue_t * queue,size_t * num_waiting)1049 cy_rslt_t cy_rtos_queue_count(cy_queue_t* queue, size_t* num_waiting)
1050 {
1051 cy_rslt_t status;
1052 if ((queue == NULL) || (num_waiting == NULL))
1053 {
1054 status = CY_RTOS_BAD_PARAM;
1055 }
1056 else
1057 {
1058 *num_waiting = is_in_isr()
1059 ? uxQueueMessagesWaitingFromISR(*queue)
1060 : uxQueueMessagesWaiting(*queue);
1061 status = CY_RSLT_SUCCESS;
1062 }
1063 return status;
1064 }
1065
1066
1067 //--------------------------------------------------------------------------------------------------
1068 // cy_rtos_queue_space
1069 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_space(cy_queue_t * queue,size_t * num_spaces)1070 cy_rslt_t cy_rtos_queue_space(cy_queue_t* queue, size_t* num_spaces)
1071 {
1072 cy_rslt_t status;
1073 if ((queue == NULL) || (num_spaces == NULL))
1074 {
1075 status = CY_RTOS_BAD_PARAM;
1076 }
1077 else
1078 {
1079 *num_spaces = uxQueueSpacesAvailable(*queue);
1080 status = CY_RSLT_SUCCESS;
1081 }
1082 return status;
1083 }
1084
1085
1086 //--------------------------------------------------------------------------------------------------
1087 // cy_rtos_queue_reset
1088 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_reset(cy_queue_t * queue)1089 cy_rslt_t cy_rtos_queue_reset(cy_queue_t* queue)
1090 {
1091 cy_rslt_t status;
1092 if (queue == NULL)
1093 {
1094 status = CY_RTOS_BAD_PARAM;
1095 }
1096 else
1097 {
1098 BaseType_t ret = xQueueReset(*queue);
1099
1100 if (ret == pdFALSE)
1101 {
1102 status = CY_RTOS_GENERAL_ERROR;
1103 }
1104 else
1105 {
1106 status = CY_RSLT_SUCCESS;
1107 }
1108 }
1109 return status;
1110 }
1111
1112
1113 //--------------------------------------------------------------------------------------------------
1114 // cy_rtos_queue_deinit
1115 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_deinit(cy_queue_t * queue)1116 cy_rslt_t cy_rtos_queue_deinit(cy_queue_t* queue)
1117 {
1118 cy_rslt_t status;
1119 if (queue == NULL)
1120 {
1121 status = CY_RTOS_BAD_PARAM;
1122 }
1123 else
1124 {
1125 vQueueDelete(*queue);
1126 status = CY_RSLT_SUCCESS;
1127 }
1128 return status;
1129 }
1130
1131
1132 //==================================================================================================
1133 // Timers
1134 //==================================================================================================
1135
1136 //--------------------------------------------------------------------------------------------------
1137 // cy_rtos_timer_init
1138 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_init(cy_timer_t * timer,cy_timer_trigger_type_t type,cy_timer_callback_t fun,cy_timer_callback_arg_t arg)1139 cy_rslt_t cy_rtos_timer_init(cy_timer_t* timer, cy_timer_trigger_type_t type,
1140 cy_timer_callback_t fun, cy_timer_callback_arg_t arg)
1141 {
1142 cy_rslt_t status;
1143 if ((timer == NULL) || (fun == NULL))
1144 {
1145 status = CY_RTOS_BAD_PARAM;
1146 }
1147 else
1148 {
1149 // Create a wrapper callback to make sure to call fun() with arg as opposed
1150 // to providing the timer reference as FreeRTOS does by default.
1151 callback_data_t* cb_arg = (callback_data_t*)malloc(sizeof(callback_data_t));
1152 if (NULL == cb_arg)
1153 {
1154 status = CY_RTOS_NO_MEMORY;
1155 }
1156 else
1157 {
1158 cb_arg->cb = fun;
1159 cb_arg->arg = arg;
1160
1161 BaseType_t reload = (type == CY_TIMER_TYPE_PERIODIC) ? pdTRUE : pdFALSE;
1162 *timer = xTimerCreate("", 1, (UBaseType_t)reload, cb_arg, &timer_callback);
1163
1164 if (*timer == NULL)
1165 {
1166 free(cb_arg);
1167 status = CY_RTOS_NO_MEMORY;
1168 }
1169 else
1170 {
1171 status = CY_RSLT_SUCCESS;
1172 }
1173 }
1174 }
1175 return status;
1176 }
1177
1178
1179 //--------------------------------------------------------------------------------------------------
1180 // cy_rtos_timer_start
1181 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_start(cy_timer_t * timer,cy_time_t num_ms)1182 cy_rslt_t cy_rtos_timer_start(cy_timer_t* timer, cy_time_t num_ms)
1183 {
1184 cy_rslt_t status;
1185 if (timer == NULL)
1186 {
1187 status = CY_RTOS_BAD_PARAM;
1188 }
1189 else
1190 {
1191 TickType_t ticks = convert_ms_to_ticks(num_ms);
1192 BaseType_t ret = xTimerChangePeriod(*timer, ticks, 0);
1193
1194 if (ret == pdPASS)
1195 {
1196 ret = xTimerStart(*timer, 0);
1197 }
1198
1199 if (ret == pdFALSE)
1200 {
1201 status = CY_RTOS_GENERAL_ERROR;
1202 }
1203 else
1204 {
1205 status = CY_RSLT_SUCCESS;
1206 }
1207 }
1208 return status;
1209 }
1210
1211
1212 //--------------------------------------------------------------------------------------------------
1213 // cy_rtos_timer_stop
1214 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_stop(cy_timer_t * timer)1215 cy_rslt_t cy_rtos_timer_stop(cy_timer_t* timer)
1216 {
1217 cy_rslt_t status;
1218 if (timer == NULL)
1219 {
1220 status = CY_RTOS_BAD_PARAM;
1221 }
1222 else
1223 {
1224 BaseType_t ret = xTimerStop(*timer, 0);
1225
1226 if (ret == pdFALSE)
1227 {
1228 status = CY_RTOS_GENERAL_ERROR;
1229 }
1230 else
1231 {
1232 status = CY_RSLT_SUCCESS;
1233 }
1234 }
1235 return status;
1236 }
1237
1238
1239 //--------------------------------------------------------------------------------------------------
1240 // cy_rtos_timer_is_running
1241 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_is_running(cy_timer_t * timer,bool * state)1242 cy_rslt_t cy_rtos_timer_is_running(cy_timer_t* timer, bool* state)
1243 {
1244 cy_rslt_t status;
1245 if ((timer == NULL) || (state == NULL))
1246 {
1247 status = CY_RTOS_BAD_PARAM;
1248 }
1249 else
1250 {
1251 BaseType_t active = xTimerIsTimerActive(*timer);
1252 *state = (active != pdFALSE);
1253
1254 status = CY_RSLT_SUCCESS;
1255 }
1256 return status;
1257 }
1258
1259
1260 //--------------------------------------------------------------------------------------------------
1261 // cy_rtos_timer_deinit
1262 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_deinit(cy_timer_t * timer)1263 cy_rslt_t cy_rtos_timer_deinit(cy_timer_t* timer)
1264 {
1265 cy_rslt_t status;
1266 if (timer == NULL)
1267 {
1268 status = CY_RTOS_BAD_PARAM;
1269 }
1270 else
1271 {
1272 void* cb = pvTimerGetTimerID(*timer);
1273 BaseType_t ret = xTimerDelete(*timer, 0);
1274
1275 if (ret == pdFALSE)
1276 {
1277 status = CY_RTOS_GENERAL_ERROR;
1278 }
1279 else
1280 {
1281 free(cb);
1282 status = CY_RSLT_SUCCESS;
1283 }
1284 }
1285 return status;
1286 }
1287
1288
1289 //==================================================================================================
1290 // Time
1291 //==================================================================================================
1292
1293 //--------------------------------------------------------------------------------------------------
1294 // cy_rtos_time_get
1295 //--------------------------------------------------------------------------------------------------
cy_rtos_time_get(cy_time_t * tval)1296 cy_rslt_t cy_rtos_time_get(cy_time_t* tval)
1297 {
1298 cy_rslt_t status;
1299 if (tval == NULL)
1300 {
1301 status = CY_RTOS_BAD_PARAM;
1302 }
1303 else
1304 {
1305 *tval = (cy_time_t)((xTaskGetTickCount() * 1000LL) / configTICK_RATE_HZ);
1306 status = CY_RSLT_SUCCESS;
1307 }
1308 return status;
1309 }
1310
1311
1312 //--------------------------------------------------------------------------------------------------
1313 // cy_rtos_delay_milliseconds
1314 //--------------------------------------------------------------------------------------------------
cy_rtos_delay_milliseconds(cy_time_t num_ms)1315 cy_rslt_t cy_rtos_delay_milliseconds(cy_time_t num_ms)
1316 {
1317 vTaskDelay(convert_ms_to_ticks(num_ms));
1318 return CY_RSLT_SUCCESS;
1319 }
1320