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