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