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