1 /***********************************************************************************************//**
2  * \file cyabs_rtos_threadx.c
3  *
4  * \brief
5  * Implementation for ThreadX 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_result.h>
28 #include <cy_utils.h>
29 #include <cyabs_rtos.h>
30 #include <tx_api.h>
31 #include <stdlib.h>
32 #include "cyabs_rtos_internal.h"
33 #if defined (COMPONENT_CAT5)
34 #include "cyabs_rtos_impl_cat5.h"
35 #endif
36 
37 #define WRAPPER_IDENT           (0xABCDEF01U)
38 #define MAX_QUEUE_MESSAGE_SIZE  (16)
39 #define ALL_EVENT_FLAGS         (0xFFFFFFFFU)
40 #define MILLISECONDS_PER_SECOND (1000)
41 
42 static cy_rtos_error_t last_error;
43 
44 
45 //--------------------------------------------------------------------------------------------------
46 // convert_ms_to_ticks
47 //--------------------------------------------------------------------------------------------------
convert_ms_to_ticks(cy_time_t timeout_ms)48 static cy_time_t convert_ms_to_ticks(cy_time_t timeout_ms)
49 {
50     if (timeout_ms == CY_RTOS_NEVER_TIMEOUT)
51     {
52         return TX_WAIT_FOREVER;
53     }
54     else if (timeout_ms == 0)
55     {
56         return 0;
57     }
58     else
59     {
60         uint64_t ticks = (uint64_t)timeout_ms * (uint64_t)TX_TIMER_TICKS_PER_SECOND /
61                          (uint64_t)MILLISECONDS_PER_SECOND;
62         if (ticks == 0)
63         {
64             ticks = 1;
65         }
66         else if (ticks >= UINT32_MAX)
67         {
68             // if ticks if more than 32 bits, change ticks to max possible value that isn't
69             // TX_WAIT_FOREVER.
70             ticks = UINT32_MAX - 1;
71         }
72         return (cy_time_t)ticks;
73     }
74 }
75 
76 
77 //--------------------------------------------------------------------------------------------------
78 // convert_ticks_to_ms
79 //--------------------------------------------------------------------------------------------------
convert_ticks_to_ms(cy_time_t timeout_ticks)80 static inline cy_time_t convert_ticks_to_ms(cy_time_t timeout_ticks)
81 {
82     return (cy_time_t)((uint64_t)timeout_ticks * (uint64_t)MILLISECONDS_PER_SECOND /
83                        (uint64_t)TX_TIMER_TICKS_PER_SECOND);
84 }
85 
86 
87 //--------------------------------------------------------------------------------------------------
88 // convert_error
89 //--------------------------------------------------------------------------------------------------
convert_error(cy_rtos_error_t error)90 static inline cy_rslt_t convert_error(cy_rtos_error_t error)
91 {
92     if (error != TX_SUCCESS)
93     {
94         last_error = error;
95         return CY_RTOS_GENERAL_ERROR;
96     }
97     return CY_RSLT_SUCCESS;
98 }
99 
100 
101 /******************************************************
102 *                 Last Error
103 ******************************************************/
104 
105 //--------------------------------------------------------------------------------------------------
106 // cy_rtos_last_error
107 //--------------------------------------------------------------------------------------------------
cy_rtos_last_error(void)108 cy_rtos_error_t cy_rtos_last_error(void)
109 {
110     return last_error;
111 }
112 
113 
114 /******************************************************
115 *                 Threads
116 ******************************************************/
117 
118 typedef struct
119 {
120     TX_THREAD thread;
121     uint32_t  magic;
122     void*     memptr;
123 } cy_thread_wrapper_t;
124 
125 
126 //--------------------------------------------------------------------------------------------------
127 // cy_rtos_create_thread
128 //--------------------------------------------------------------------------------------------------
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)129 cy_rslt_t cy_rtos_thread_create(cy_thread_t* thread, cy_thread_entry_fn_t entry_function,
130                                 const char* name, void* stack, uint32_t stack_size,
131                                 cy_thread_priority_t priority, cy_thread_arg_t arg)
132 {
133     stack_size &= ~CY_RTOS_ALIGNMENT_MASK; // make stack pointer 8-byte aligned
134     if ((thread == NULL) || (stack_size < CY_RTOS_MIN_STACK_SIZE))
135     {
136         return CY_RTOS_BAD_PARAM;
137     }
138 
139     if ((stack != NULL) && (0 != (((uint32_t)stack) & CY_RTOS_ALIGNMENT_MASK)))
140     {
141         return CY_RTOS_ALIGNMENT_ERROR;
142     }
143 
144     size_t malloc_size = sizeof(cy_thread_wrapper_t);
145     if (stack == NULL)
146     {
147         malloc_size += stack_size;
148     }
149     void* buffer = malloc(malloc_size);
150     if (buffer == NULL)
151     {
152         return CY_RTOS_NO_MEMORY;
153     }
154 
155     cy_thread_wrapper_t* wrapper_ptr;
156     if (stack == NULL)
157     {
158         stack = buffer;
159         // Have stack be in front of wrapper since stack size is 8-byte aligned.
160         wrapper_ptr         = (cy_thread_wrapper_t*)((uint32_t)buffer + stack_size);
161         wrapper_ptr->memptr = stack;
162     }
163     else
164     {
165         wrapper_ptr         = buffer;
166         wrapper_ptr->memptr = NULL;
167     }
168     wrapper_ptr->magic = WRAPPER_IDENT;
169 
170     *thread = (cy_thread_t)wrapper_ptr;
171 
172     // Disable preemption-thresholding and time slicing
173     cy_rtos_error_t tx_rslt = tx_thread_create(*thread, (CHAR*)name, entry_function, arg, stack,
174                                                stack_size, priority, priority, TX_NO_TIME_SLICE,
175                                                TX_AUTO_START);
176 
177     if (TX_SUCCESS != tx_rslt)
178     {
179         last_error = tx_rslt;
180         free(buffer);
181         return CY_RTOS_GENERAL_ERROR;
182     }
183 
184     return CY_RSLT_SUCCESS;
185 }
186 
187 
188 //--------------------------------------------------------------------------------------------------
189 // cy_rtos_thread_exit
190 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_exit(void)191 cy_rslt_t cy_rtos_thread_exit(void)
192 {
193     // No need to do anything before thread exit
194     return CY_RSLT_SUCCESS;
195 }
196 
197 
198 //--------------------------------------------------------------------------------------------------
199 // cy_rtos_thread_terminate
200 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_terminate(cy_thread_t * thread)201 cy_rslt_t cy_rtos_thread_terminate(cy_thread_t* thread)
202 {
203     if (thread == NULL)
204     {
205         return CY_RTOS_BAD_PARAM;
206     }
207 
208     return convert_error(tx_thread_terminate(*thread));
209 }
210 
211 
212 //--------------------------------------------------------------------------------------------------
213 // cy_rtos_thread_is_running
214 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_is_running(cy_thread_t * thread,bool * running)215 cy_rslt_t cy_rtos_thread_is_running(cy_thread_t* thread, bool* running)
216 {
217     if ((thread == NULL) || (running == NULL))
218     {
219         return CY_RTOS_BAD_PARAM;
220     }
221 
222     // Only true when the given thread is the current one
223     *running = (*thread == tx_thread_identify());
224     return CY_RSLT_SUCCESS;
225 }
226 
227 
228 //--------------------------------------------------------------------------------------------------
229 // cy_rtos_thread_get_state
230 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_state(cy_thread_t * thread,cy_thread_state_t * state)231 cy_rslt_t cy_rtos_thread_get_state(cy_thread_t* thread, cy_thread_state_t* state)
232 {
233     if ((thread == NULL) || (state == NULL))
234     {
235         return CY_RTOS_BAD_PARAM;
236     }
237 
238     bool      running;
239     cy_rslt_t rslt = cy_rtos_is_thread_running(thread, &running);
240     if (CY_RSLT_SUCCESS != rslt)
241     {
242         return rslt;
243     }
244     else if (running)
245     {
246         *state = CY_THREAD_STATE_RUNNING;
247         return CY_RSLT_SUCCESS;
248     }
249 
250     UINT            thread_state;
251     cy_rtos_error_t tx_rslt = tx_thread_info_get(*thread, TX_NULL, &thread_state, TX_NULL, TX_NULL,
252                                                  TX_NULL, TX_NULL, TX_NULL, TX_NULL);
253     if (TX_SUCCESS != tx_rslt)
254     {
255         last_error = tx_rslt;
256         return CY_RTOS_GENERAL_ERROR;
257     }
258 
259     // Descriptions of these states are not given in the ThreadX user guide - these are best guesses
260     // as to their meanings
261     switch (thread_state)
262     {
263         case TX_READY:
264             *state = CY_THREAD_STATE_READY;
265             break;
266 
267         case TX_COMPLETED:
268         case TX_TERMINATED:
269             *state = CY_THREAD_STATE_TERMINATED;
270             break;
271 
272         case TX_SUSPENDED:
273         case TX_SLEEP:
274         case TX_QUEUE_SUSP:
275         case TX_SEMAPHORE_SUSP:
276         case TX_MUTEX_SUSP:
277         case TX_EVENT_FLAG: // Likely waiting for event flags to be set (tx_event_flags_get)
278         case TX_BLOCK_MEMORY: // Likely waiting to allocate a memory block (tx_block_allocate)
279         case TX_BYTE_MEMORY: // Likely waiting to allocate a byte pool (tx_byte_allocate)
280             *state = CY_THREAD_STATE_BLOCKED;
281             break;
282 
283         default:
284             *state = CY_THREAD_STATE_UNKNOWN;
285             break;
286     }
287 
288     return CY_RSLT_SUCCESS;
289 }
290 
291 
292 //--------------------------------------------------------------------------------------------------
293 // cy_rtos_thread_join
294 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_join(cy_thread_t * thread)295 cy_rslt_t cy_rtos_thread_join(cy_thread_t* thread)
296 {
297     if (thread == NULL)
298     {
299         return CY_RTOS_BAD_PARAM;
300     }
301 
302     // ThreadX doesn't have a join method itself, so just repeatedly check the thread's state until
303     // it completes or is terminated.
304     // Check if the thread we are joining has a higher priority, if it does, we need to lower our
305     // priority to that of the other thread.
306     UINT thread_state;
307 
308     cy_rtos_error_t tx_rslt = tx_thread_info_get(*thread, TX_NULL, &thread_state, TX_NULL, TX_NULL,
309                                                  TX_NULL, TX_NULL, TX_NULL, TX_NULL);
310     if (TX_SUCCESS != tx_rslt)
311     {
312         last_error = tx_rslt;
313         return CY_RTOS_GENERAL_ERROR;
314     }
315 
316     while (TX_TERMINATED != thread_state && TX_COMPLETED != thread_state)
317     {
318         tx_rslt = tx_thread_sleep(1);
319         if (TX_SUCCESS != tx_rslt)
320         {
321             last_error = tx_rslt;
322             return CY_RTOS_GENERAL_ERROR;
323         }
324 
325         tx_rslt = tx_thread_info_get(*thread, TX_NULL, &thread_state, TX_NULL, TX_NULL, TX_NULL,
326                                      TX_NULL, TX_NULL, TX_NULL);
327         if (TX_SUCCESS != tx_rslt)
328         {
329             last_error = tx_rslt;
330             return CY_RTOS_GENERAL_ERROR;
331         }
332     }
333 
334     tx_rslt = tx_thread_delete(*thread);
335     if (TX_SUCCESS != tx_rslt)
336     {
337         last_error = tx_rslt;
338         return CY_RTOS_GENERAL_ERROR;
339     }
340 
341     cy_thread_wrapper_t* wrapper_ptr = (cy_thread_wrapper_t*)(*thread);
342     if (wrapper_ptr->magic == WRAPPER_IDENT)
343     {
344         if (wrapper_ptr->memptr != NULL)
345         {
346             free(wrapper_ptr->memptr);
347         }
348         else
349         {
350             free(wrapper_ptr);
351         }
352     }
353     return CY_RSLT_SUCCESS;
354 }
355 
356 
357 //--------------------------------------------------------------------------------------------------
358 // cy_rtos_thread_get_handle
359 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_handle(cy_thread_t * thread)360 cy_rslt_t cy_rtos_thread_get_handle(cy_thread_t* thread)
361 {
362     if (thread == NULL)
363     {
364         return CY_RTOS_BAD_PARAM;
365     }
366 
367     *thread = tx_thread_identify();
368     return CY_RSLT_SUCCESS;
369 }
370 
371 
372 //--------------------------------------------------------------------------------------------------
373 // cy_rtos_thread_wait_notification
374 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_wait_notification(cy_time_t timeout_ms)375 cy_rslt_t cy_rtos_thread_wait_notification(cy_time_t timeout_ms)
376 {
377     UINT ret;
378     cy_rslt_t status = CY_RSLT_SUCCESS;
379 
380     ret = tx_thread_sleep(convert_ms_to_ticks(timeout_ms));
381     /* Update the last known error status */
382     last_error = (cy_rtos_error_t)ret;
383 
384     if (ret == TX_SUCCESS)
385     {
386         status = CY_RTOS_TIMEOUT;
387     }
388     else if (ret != TX_WAIT_ABORTED)
389     {
390         status = CY_RTOS_GENERAL_ERROR;
391     }
392     return status;
393 }
394 
395 
396 //--------------------------------------------------------------------------------------------------
397 // cy_rtos_thread_set_notification
398 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_set_notification(cy_thread_t * thread)399 cy_rslt_t cy_rtos_thread_set_notification(cy_thread_t* thread)
400 {
401     if (thread == NULL)
402     {
403         return CY_RTOS_BAD_PARAM;
404     }
405     /* According to ThreadX user guide, this function allowed to
406      * be called from ISR
407      */
408     return convert_error(tx_thread_wait_abort(*thread));
409 }
410 
411 
412 //--------------------------------------------------------------------------------------------------
413 // cy_rtos_thread_get_name
414 //--------------------------------------------------------------------------------------------------
cy_rtos_thread_get_name(cy_thread_t * thread,const char ** thread_name)415 cy_rslt_t cy_rtos_thread_get_name(cy_thread_t* thread, const char** thread_name)
416 {
417     char* temp_name;
418     cy_rtos_error_t tx_rslt = tx_thread_info_get(*thread, &temp_name, TX_NULL, TX_NULL, TX_NULL,
419                                                  TX_NULL,
420                                                  TX_NULL, TX_NULL, TX_NULL);
421     cy_rslt_t result = convert_error(tx_rslt);
422     if (result == CY_RSLT_SUCCESS)
423     {
424         *thread_name = temp_name;
425     }
426     return result;
427 }
428 
429 
430 /******************************************************
431 *                 Scheduler
432 ******************************************************/
433 static uint16_t _cy_rtos_suspend_count = 0;
434 
435 //--------------------------------------------------------------------------------------------------
436 // cy_rtos_scheduler_suspend
437 //--------------------------------------------------------------------------------------------------
cy_rtos_scheduler_suspend(void)438 cy_rslt_t cy_rtos_scheduler_suspend(void)
439 {
440     ++_cy_rtos_suspend_count;
441     #if defined (COMPONENT_CAT5)
442     if (_cy_rtos_suspend_count == 1)
443     {
444         tx_interrupt_control(TX_INT_DISABLE);
445     }
446     #else
447     tx_interrupt_control(TX_INT_DISABLE);
448     #endif
449     return CY_RSLT_SUCCESS;
450 }
451 
452 
453 //--------------------------------------------------------------------------------------------------
454 // cy_rtos_scheduler_resume
455 //--------------------------------------------------------------------------------------------------
cy_rtos_scheduler_resume(void)456 cy_rslt_t cy_rtos_scheduler_resume(void)
457 {
458     cy_rslt_t status;
459     if (_cy_rtos_suspend_count > 0)
460     {
461         if (_cy_rtos_suspend_count == 1)
462         {
463             tx_interrupt_control(TX_INT_ENABLE);
464         }
465         --_cy_rtos_suspend_count;
466         status = CY_RSLT_SUCCESS;
467     }
468     else
469     {
470         status = CY_RTOS_BAD_PARAM;
471     }
472 
473     return status;
474 }
475 
476 
477 /******************************************************
478 *                 Mutexes
479 ******************************************************/
480 
481 //--------------------------------------------------------------------------------------------------
482 // cy_rtos_mutex_init
483 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_init(cy_mutex_t * mutex,bool recursive)484 cy_rslt_t cy_rtos_mutex_init(cy_mutex_t* mutex, bool recursive)
485 {
486     if (mutex == NULL)
487     {
488         return CY_RTOS_BAD_PARAM;
489     }
490 
491     // Non recursive mutex is not supported by ThreadX. A recursive mutex is returned
492     // even if a non-recursive mutex was requested. This is ok because in all the cases
493     // where the behavior of the two types differs would have ended in a deadlock. So
494     // the difference in behavior should not have a functional impact on application.
495     CY_UNUSED_PARAMETER(recursive);
496     return convert_error(tx_mutex_create(mutex, TX_NULL, TX_INHERIT));
497 }
498 
499 
500 //--------------------------------------------------------------------------------------------------
501 // cy_rtos_mutex_get
502 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_get(cy_mutex_t * mutex,cy_time_t timeout_ms)503 cy_rslt_t cy_rtos_mutex_get(cy_mutex_t* mutex, cy_time_t timeout_ms)
504 {
505     if (mutex == NULL)
506     {
507         return CY_RTOS_BAD_PARAM;
508     }
509 
510     cy_rtos_error_t tx_rslt = tx_mutex_get(mutex, convert_ms_to_ticks(timeout_ms));
511     if (TX_NOT_AVAILABLE == tx_rslt)
512     {
513         return CY_RTOS_TIMEOUT;
514     }
515     else
516     {
517         return convert_error(tx_rslt);
518     }
519 }
520 
521 
522 //--------------------------------------------------------------------------------------------------
523 // cy_rtos_mutex_set
524 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_set(cy_mutex_t * mutex)525 cy_rslt_t cy_rtos_mutex_set(cy_mutex_t* mutex)
526 {
527     if (mutex == NULL)
528     {
529         return CY_RTOS_BAD_PARAM;
530     }
531 
532     return convert_error(tx_mutex_put(mutex));
533 }
534 
535 
536 //--------------------------------------------------------------------------------------------------
537 // cy_rtos_deinit_mutex
538 //--------------------------------------------------------------------------------------------------
cy_rtos_mutex_deinit(cy_mutex_t * mutex)539 cy_rslt_t cy_rtos_mutex_deinit(cy_mutex_t* mutex)
540 {
541     if (mutex == NULL)
542     {
543         return CY_RTOS_BAD_PARAM;
544     }
545 
546     return convert_error(tx_mutex_delete(mutex));
547 }
548 
549 
550 /******************************************************
551 *                 Semaphores
552 ******************************************************/
553 
554 //--------------------------------------------------------------------------------------------------
555 // cy_rtos_semaphore_init
556 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_init(cy_semaphore_t * semaphore,uint32_t maxcount,uint32_t initcount)557 cy_rslt_t cy_rtos_semaphore_init(cy_semaphore_t* semaphore, uint32_t maxcount, uint32_t initcount)
558 {
559     if (semaphore == NULL)
560     {
561         return CY_RTOS_BAD_PARAM;
562     }
563     semaphore->maxcount = maxcount;
564     return convert_error(tx_semaphore_create(&(semaphore->tx_semaphore), TX_NULL, initcount));
565 }
566 
567 
568 //--------------------------------------------------------------------------------------------------
569 // cy_rtos_semaphore_get
570 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_get(cy_semaphore_t * semaphore,cy_time_t timeout_ms)571 cy_rslt_t cy_rtos_semaphore_get(cy_semaphore_t* semaphore, cy_time_t timeout_ms)
572 {
573     // Based on documentation
574     // http://www.ece.ualberta.ca/~cmpe490/documents/ghs/405/threadxug_g40c.pdf
575     // pg 168 it specifies that the timeout must be zero when called from ISR.
576     if ((semaphore == NULL) || (is_in_isr() && (timeout_ms != 0)))
577     {
578         return CY_RTOS_BAD_PARAM;
579     }
580     cy_rtos_error_t tx_rslt =
581         tx_semaphore_get(&(semaphore->tx_semaphore), convert_ms_to_ticks(timeout_ms));
582     if (TX_NO_INSTANCE == tx_rslt)
583     {
584         return CY_RTOS_TIMEOUT;
585     }
586     else
587     {
588         return convert_error(tx_rslt);
589     }
590 }
591 
592 
593 //--------------------------------------------------------------------------------------------------
594 // cy_rtos_semaphore_set
595 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_set(cy_semaphore_t * semaphore)596 cy_rslt_t cy_rtos_semaphore_set(cy_semaphore_t* semaphore)
597 {
598     if (semaphore == NULL)
599     {
600         return CY_RTOS_BAD_PARAM;
601     }
602     return convert_error(tx_semaphore_ceiling_put(&(semaphore->tx_semaphore), semaphore->maxcount));
603 }
604 
605 
606 //--------------------------------------------------------------------------------------------------
607 // cy_rtos_semaphore_get_count
608 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_get_count(cy_semaphore_t * semaphore,size_t * count)609 cy_rslt_t cy_rtos_semaphore_get_count(cy_semaphore_t* semaphore, size_t* count)
610 {
611     if ((semaphore == NULL) || (count == NULL))
612     {
613         return CY_RTOS_BAD_PARAM;
614     }
615     return convert_error(tx_semaphore_info_get(&(semaphore->tx_semaphore), TX_NULL, (ULONG*)count,
616                                                TX_NULL, TX_NULL, TX_NULL));
617 }
618 
619 
620 //--------------------------------------------------------------------------------------------------
621 // cy_rtos_semaphore_deinit
622 //--------------------------------------------------------------------------------------------------
cy_rtos_semaphore_deinit(cy_semaphore_t * semaphore)623 cy_rslt_t cy_rtos_semaphore_deinit(cy_semaphore_t* semaphore)
624 {
625     if (semaphore == NULL)
626     {
627         return CY_RTOS_BAD_PARAM;
628     }
629     return convert_error(tx_semaphore_delete(&(semaphore->tx_semaphore)));
630 }
631 
632 
633 /******************************************************
634 *                 Events
635 ******************************************************/
636 
637 //--------------------------------------------------------------------------------------------------
638 // cy_rtos_event_init
639 //--------------------------------------------------------------------------------------------------
cy_rtos_event_init(cy_event_t * event)640 cy_rslt_t cy_rtos_event_init(cy_event_t* event)
641 {
642     if (event == NULL)
643     {
644         return CY_RTOS_BAD_PARAM;
645     }
646 
647     return convert_error(tx_event_flags_create(event, TX_NULL));
648 }
649 
650 
651 //--------------------------------------------------------------------------------------------------
652 // cy_rtos_event_setbits
653 //--------------------------------------------------------------------------------------------------
cy_rtos_event_setbits(cy_event_t * event,uint32_t bits)654 cy_rslt_t cy_rtos_event_setbits(cy_event_t* event, uint32_t bits)
655 {
656     if (event == NULL)
657     {
658         return CY_RTOS_BAD_PARAM;
659     }
660     return convert_error(tx_event_flags_set(event, bits, TX_OR));
661 }
662 
663 
664 //--------------------------------------------------------------------------------------------------
665 // cy_rtos_event_clearbits
666 //--------------------------------------------------------------------------------------------------
cy_rtos_event_clearbits(cy_event_t * event,uint32_t bits)667 cy_rslt_t cy_rtos_event_clearbits(cy_event_t* event, uint32_t bits)
668 {
669     if (event == NULL)
670     {
671         return CY_RTOS_BAD_PARAM;
672     }
673 
674     return convert_error(tx_event_flags_set(event, ~bits, TX_AND));
675 }
676 
677 
678 //--------------------------------------------------------------------------------------------------
679 // cy_rtos_event_getbits
680 //--------------------------------------------------------------------------------------------------
cy_rtos_event_getbits(cy_event_t * event,uint32_t * bits)681 cy_rslt_t cy_rtos_event_getbits(cy_event_t* event, uint32_t* bits)
682 {
683     if ((event == NULL) || (bits == NULL))
684     {
685         return CY_RTOS_BAD_PARAM;
686     }
687 
688     cy_rtos_error_t tx_rslt = tx_event_flags_get(event, ALL_EVENT_FLAGS, TX_OR, (ULONG*)bits,
689                                                  TX_NO_WAIT);
690     if (TX_NO_EVENTS == tx_rslt) // If timeout error occur with ALL_EVENT_FLAGS and TX_OR, then no
691                                  // flag is set
692     {
693         *bits = 0;
694         return CY_RSLT_SUCCESS;
695     }
696     else
697     {
698         return convert_error(tx_rslt);
699     }
700 }
701 
702 
703 //--------------------------------------------------------------------------------------------------
704 // cy_rtos_event_waitbits
705 //--------------------------------------------------------------------------------------------------
cy_rtos_event_waitbits(cy_event_t * event,uint32_t * bits,bool clear,bool all,cy_time_t timeout_ms)706 cy_rslt_t cy_rtos_event_waitbits(cy_event_t* event, uint32_t* bits, bool clear, bool all,
707                                  cy_time_t timeout_ms)
708 {
709     UINT get_option;
710 
711     if ((event == NULL) || (bits == NULL))
712     {
713         return CY_RTOS_BAD_PARAM;
714     }
715 
716     if (all)
717     {
718         get_option = clear ? TX_AND_CLEAR : TX_AND;
719     }
720     else
721     {
722         get_option = clear ? TX_OR_CLEAR : TX_OR;
723     }
724 
725     cy_rtos_error_t tx_rslt =
726         tx_event_flags_get(event, *bits, get_option, (ULONG*)bits, convert_ms_to_ticks(timeout_ms));
727     if (TX_NO_EVENTS == tx_rslt)
728     {
729         return CY_RTOS_TIMEOUT;
730     }
731     else
732     {
733         return convert_error(tx_rslt);
734     }
735 }
736 
737 
738 //--------------------------------------------------------------------------------------------------
739 // cy_rtos_event_deinit
740 //--------------------------------------------------------------------------------------------------
cy_rtos_event_deinit(cy_event_t * event)741 cy_rslt_t cy_rtos_event_deinit(cy_event_t* event)
742 {
743     if (event == NULL)
744     {
745         return CY_RTOS_BAD_PARAM;
746     }
747 
748     return convert_error(tx_event_flags_delete(event));
749 }
750 
751 
752 /******************************************************
753 *                 Queues
754 ******************************************************/
755 
756 //--------------------------------------------------------------------------------------------------
757 // cy_rtos_queue_init
758 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_init(cy_queue_t * queue,size_t length,size_t itemsize)759 cy_rslt_t cy_rtos_queue_init(cy_queue_t* queue, size_t length, size_t itemsize)
760 {
761     // Valid message lengths are {1-ULONG, 2-ULONG, 4-ULONG, 8-ULONG, 16-ULONG}
762     static const uint32_t BYTES_PER_QUEUE_WORD = sizeof(ULONG);
763 
764     if ((queue == NULL) || (itemsize == 0) ||
765         (itemsize > BYTES_PER_QUEUE_WORD * MAX_QUEUE_MESSAGE_SIZE))
766     {
767         return CY_RTOS_BAD_PARAM;
768     }
769 
770     // round message words to next power of 2 times word size.
771     UINT message_words = 1;
772     while (message_words * BYTES_PER_QUEUE_WORD < itemsize)
773     {
774         message_words <<= 1;
775     }
776 
777     queue->itemsize = itemsize;
778     ULONG queue_size = length * message_words * BYTES_PER_QUEUE_WORD;
779     queue->mem = malloc(queue_size);
780     if (queue->mem == NULL)
781     {
782         return CY_RTOS_NO_MEMORY;
783     }
784 
785     cy_rtos_error_t tx_rslt = tx_queue_create(&(queue->tx_queue), TX_NULL, message_words,
786                                               queue->mem, queue_size);
787     if (TX_SUCCESS != tx_rslt)
788     {
789         last_error = tx_rslt;
790         free(queue->mem);
791         return CY_RTOS_GENERAL_ERROR;
792     }
793 
794     return CY_RSLT_SUCCESS;
795 }
796 
797 
798 //--------------------------------------------------------------------------------------------------
799 // cy_rtos_queue_put
800 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_put(cy_queue_t * queue,const void * item_ptr,cy_time_t timeout_ms)801 cy_rslt_t cy_rtos_queue_put(cy_queue_t* queue, const void* item_ptr, cy_time_t timeout_ms)
802 {
803     if ((queue == NULL) || (item_ptr == NULL) || (is_in_isr() && (timeout_ms != 0)))
804     {
805         return CY_RTOS_BAD_PARAM;
806     }
807 
808     cy_rtos_error_t tx_rslt = tx_queue_send(&(queue->tx_queue), (void*)item_ptr, convert_ms_to_ticks(
809                                                 timeout_ms));
810     if (TX_QUEUE_FULL == tx_rslt)
811     {
812         return CY_RTOS_NO_MEMORY;
813     }
814     else
815     {
816         return convert_error(tx_rslt);
817     }
818 }
819 
820 
821 //--------------------------------------------------------------------------------------------------
822 // cy_rtos_queue_get
823 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_get(cy_queue_t * queue,void * item_ptr,cy_time_t timeout_ms)824 cy_rslt_t cy_rtos_queue_get(cy_queue_t* queue, void* item_ptr, cy_time_t timeout_ms)
825 {
826     ULONG buffer[MAX_QUEUE_MESSAGE_SIZE];
827     if ((queue == NULL) || (item_ptr == NULL) || (is_in_isr() && (timeout_ms != 0)))
828     {
829         return CY_RTOS_BAD_PARAM;
830     }
831 
832     cy_rtos_error_t tx_rslt =
833         tx_queue_receive(&(queue->tx_queue), buffer, convert_ms_to_ticks(timeout_ms));
834     if (TX_QUEUE_EMPTY == tx_rslt)
835     {
836         return CY_RTOS_TIMEOUT;
837     }
838     else if (tx_rslt == TX_SUCCESS)
839     {
840         memcpy(item_ptr, (void*)buffer, queue->itemsize);
841         return CY_RSLT_SUCCESS;
842     }
843     else
844     {
845         last_error = tx_rslt;
846         return CY_RTOS_GENERAL_ERROR;
847     }
848 }
849 
850 
851 //--------------------------------------------------------------------------------------------------
852 // cy_rtos_queue_count
853 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_count(cy_queue_t * queue,size_t * num_waiting)854 cy_rslt_t cy_rtos_queue_count(cy_queue_t* queue, size_t* num_waiting)
855 {
856     if ((queue == NULL) || (num_waiting == NULL))
857     {
858         return CY_RTOS_BAD_PARAM;
859     }
860     return convert_error(tx_queue_info_get(&(queue->tx_queue), TX_NULL, (ULONG*)num_waiting,
861                                            TX_NULL, TX_NULL, TX_NULL, TX_NULL));
862 }
863 
864 
865 //--------------------------------------------------------------------------------------------------
866 // cy_rtos_queue_space
867 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_space(cy_queue_t * queue,size_t * num_spaces)868 cy_rslt_t cy_rtos_queue_space(cy_queue_t* queue, size_t* num_spaces)
869 {
870     if ((queue == NULL) || (num_spaces == NULL))
871     {
872         return CY_RTOS_BAD_PARAM;
873     }
874     return convert_error(tx_queue_info_get(&(queue->tx_queue), TX_NULL, TX_NULL, (ULONG*)num_spaces,
875                                            TX_NULL, TX_NULL, TX_NULL));
876 }
877 
878 
879 //--------------------------------------------------------------------------------------------------
880 // cy_rtos_queue_reset
881 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_reset(cy_queue_t * queue)882 cy_rslt_t cy_rtos_queue_reset(cy_queue_t* queue)
883 {
884     if (queue == NULL)
885     {
886         return CY_RTOS_BAD_PARAM;
887     }
888     return convert_error(tx_queue_flush(&(queue->tx_queue)));
889 }
890 
891 
892 //--------------------------------------------------------------------------------------------------
893 // cy_rtos_queue_deinit
894 //--------------------------------------------------------------------------------------------------
cy_rtos_queue_deinit(cy_queue_t * queue)895 cy_rslt_t cy_rtos_queue_deinit(cy_queue_t* queue)
896 {
897     if (queue == NULL)
898     {
899         return CY_RTOS_BAD_PARAM;
900     }
901     cy_rslt_t result = convert_error(tx_queue_delete(&(queue->tx_queue)));
902     if (result == CY_RSLT_SUCCESS)
903     {
904         free(queue->mem);
905     }
906     return result;
907 }
908 
909 
910 /******************************************************
911 *                 Timers
912 ******************************************************/
913 
914 //--------------------------------------------------------------------------------------------------
915 // cy_rtos_timer_init
916 //--------------------------------------------------------------------------------------------------
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)917 cy_rslt_t cy_rtos_timer_init(cy_timer_t* timer, cy_timer_trigger_type_t type,
918                              cy_timer_callback_t fun, cy_timer_callback_arg_t arg)
919 {
920     if ((timer == NULL) || (fun == NULL))
921     {
922         return CY_RTOS_BAD_PARAM;
923     }
924     timer->oneshot = (type == CY_TIMER_TYPE_ONCE);
925     // Use 1s here as default timeouts since these are going to get changed anyway
926     return convert_error(tx_timer_create(&(timer->tx_timer), TX_NULL, fun, arg, 1, 1,
927                                          TX_NO_ACTIVATE));
928 }
929 
930 
931 //--------------------------------------------------------------------------------------------------
932 // cy_rtos_timer_start
933 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_start(cy_timer_t * timer,cy_time_t num_ms)934 cy_rslt_t cy_rtos_timer_start(cy_timer_t* timer, cy_time_t num_ms)
935 {
936     if (timer == NULL)
937     {
938         return CY_RTOS_BAD_PARAM;
939     }
940     ULONG     timer_ticks = convert_ms_to_ticks(num_ms);
941     cy_rslt_t rslt        =
942         convert_error(tx_timer_change(&(timer->tx_timer), timer_ticks,
943                                       timer->oneshot ? 0 : timer_ticks));
944     if (CY_RSLT_SUCCESS != rslt)
945     {
946         return rslt;
947     }
948     return convert_error(tx_timer_activate(&(timer->tx_timer)));
949 }
950 
951 
952 //--------------------------------------------------------------------------------------------------
953 // cy_rtos_timer_stop
954 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_stop(cy_timer_t * timer)955 cy_rslt_t cy_rtos_timer_stop(cy_timer_t* timer)
956 {
957     if (timer == NULL)
958     {
959         return CY_RTOS_BAD_PARAM;
960     }
961     return convert_error(tx_timer_deactivate(&(timer->tx_timer)));
962 }
963 
964 
965 //--------------------------------------------------------------------------------------------------
966 // cy_rtos_timer_is_running
967 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_is_running(cy_timer_t * timer,bool * state)968 cy_rslt_t cy_rtos_timer_is_running(cy_timer_t* timer, bool* state)
969 {
970     if ((timer == NULL) || (state == NULL))
971     {
972         return CY_RTOS_BAD_PARAM;
973     }
974 
975     UINT      active;
976     cy_rslt_t rslt =
977         convert_error(tx_timer_info_get(&(timer->tx_timer), TX_NULL, &active, TX_NULL, TX_NULL,
978                                         TX_NULL));
979     if (CY_RSLT_SUCCESS == rslt)
980     {
981         *state = (active == TX_TRUE);
982     }
983     return rslt;
984 }
985 
986 
987 //--------------------------------------------------------------------------------------------------
988 // cy_rtos_timer_deinit
989 //--------------------------------------------------------------------------------------------------
cy_rtos_timer_deinit(cy_timer_t * timer)990 cy_rslt_t cy_rtos_timer_deinit(cy_timer_t* timer)
991 {
992     if (timer == NULL)
993     {
994         return CY_RTOS_BAD_PARAM;
995     }
996     return convert_error(tx_timer_delete(&(timer->tx_timer)));
997 }
998 
999 
1000 /******************************************************
1001 *                 Time
1002 ******************************************************/
1003 
1004 //--------------------------------------------------------------------------------------------------
1005 // cy_rtos_time_get
1006 //--------------------------------------------------------------------------------------------------
cy_rtos_time_get(cy_time_t * tval)1007 cy_rslt_t cy_rtos_time_get(cy_time_t* tval)
1008 {
1009     if (tval == NULL)
1010     {
1011         return CY_RTOS_BAD_PARAM;
1012     }
1013 
1014     *tval = convert_ticks_to_ms(tx_time_get());
1015 
1016     return CY_RSLT_SUCCESS;
1017 }
1018 
1019 
1020 //--------------------------------------------------------------------------------------------------
1021 // cy_rtos_delay_milliseconds
1022 //--------------------------------------------------------------------------------------------------
cy_rtos_delay_milliseconds(cy_time_t num_ms)1023 cy_rslt_t cy_rtos_delay_milliseconds(cy_time_t num_ms)
1024 {
1025     cy_time_t ticks = convert_ms_to_ticks(num_ms);
1026 
1027     return convert_error(tx_thread_sleep(ticks));
1028 }
1029