-
Notifications
You must be signed in to change notification settings - Fork 56
/
cmsis_os2.c
4340 lines (4014 loc) · 145 KB
/
cmsis_os2.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
******************************************************************************
* @file cmsis_os2.c
* @author MCD Application Team
* @brief CMSIS RTOS2 wrapper for AzureRTOS ThreadX
******************************************************************************
* @attention
*
* Copyright (c) 2020 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Important note
* --------------
* This file is the implementation of functions to wrap CMSIS RTOS2 onto
* AzureRTOS ThreadX based on API published by Arm Limited in cmsis_os2.h.
* The implementation of these functions is inspired from an original work from
* Arm Limited to wrap CMSIS RTOS2 onto FreeRTOS (see copyright and license
* information below).
* The whole contents of this file is a creation by STMicroelectronics licensed
* to you under the License as specified above. However, some functions
* originally created by Arm Limited have not been strongly reworked by
* STMicroelectronics and are still available under their Apache License,
* Version 2.0 original terms; these original functions are:
* - osKernelGetInfo
* - osKernelStart
* - osKernelGetTickCount
* - osKernelGetTickFreq
* - osKernelGetSysTimerFreq
* - osDelay
* - osDelayUntil
* - osThreadGetId
* - osTimerIsRunning
*/
/* --------------------------------------------------------------------------
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Name: cmsis_os2.c
* Purpose: CMSIS RTOS2 wrapper for AzureRTOS ThreadX
*
*---------------------------------------------------------------------------*/
#include <string.h>
/* ::CMSIS:RTOS2 */
#include "cmsis_os2.h"
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
#include "tx_timer.h"
#include "tx_byte_pool.h"
#include "tx_event_flags.h"
#include "tx_mutex.h"
#include "tx_semaphore.h"
#include "tx_queue.h"
#include "tx_block_pool.h"
/* CMSIS compiler specific defines */
#include "cmsis_compiler.h"
/*---------------------------------------------------------------------------*/
/* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */
#define KERNEL_VERSION (((uint32_t)THREADX_MAJOR_VERSION * 10000000UL) + \
((uint32_t)THREADX_MINOR_VERSION * 10000UL) + \
((uint32_t)THREADX_PATCH_VERSION * 1UL))
#define KERNEL_ID ("Azure RTOS ThreadX")
#define IS_IRQ_MODE() (__get_IPSR() != 0U)
/* Default thread stack size */
#define RTOS2_DEFAULT_THREAD_STACK_SIZE 1024
/* Default thread stack size */
#define RTOS2_INTERNAL_BYTE_POOL_SIZE 256
#ifndef USE_DYNAMIC_MEMORY_ALLOCATION
#ifndef USE_MEMORY_POOL_ALLOCATION
#error "CMSIS RTOS ThreadX Wrapper cmsis_os2.c: USE_DYNAMIC_MEMORY_ALLOCATION or USE_MEMORY_POOL_ALLOCATION must be defined"
#endif
#endif
/* Default stack byte pool memory size */
#ifndef RTOS2_BYTE_POOL_STACK_SIZE
#define RTOS2_BYTE_POOL_STACK_SIZE 3 * 1024
#endif
/* Default stack byte pool memory size */
#ifndef RTOS2_BYTE_POOL_HEAP_SIZE
#define RTOS2_BYTE_POOL_HEAP_SIZE 4 * 1024
#endif
/* Default time slice for the created threads */
#ifndef RTOS2_DEFAULT_TIME_SLICE
#define RTOS2_DEFAULT_TIME_SLICE 4
#endif
/* Default stack byte pool memory type */
#define RTOS2_BYTE_POOL_STACK_TYPE 1
/* Default stack byte pool memory type */
#define RTOS2_BYTE_POOL_HEAP_TYPE 2
#ifndef TX_THREAD_USER_EXTENSION
#error "CMSIS RTOS ThreadX Wrapper: TX_THREAD_USER_EXTENSION must be defined as tx_thread_detached_joinable (ULONG) in tx_user.h file"
#endif
#ifdef TX_DISABLE_ERROR_CHECKING
#error "CMSIS RTOS ThreadX Wrapper : TX_DISABLE_ERROR_CHECKING must be undefined"
#endif
/* Ensure the maximum number of priorities is modified by the user to 64. */
#if(TX_MAX_PRIORITIES != 64)
#error "CMSIS RTOS ThreadX Wrapper: TX_MAX_PRIORITIES must be fixed to 64 in tx_user.h file"
#endif
/*---------------------------------------------------------------------------*/
static osKernelState_t KernelState = osKernelInactive;
extern uint32_t SystemCoreClock;
TX_BYTE_POOL HeapBytePool;
TX_BYTE_POOL StackBytePool;
TX_BLOCK_POOL BlockPool;
/*---------------------------------------------------------------------------*/
/*-------------------CMSIS RTOS2 Internal Functions--------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @brief The function MemAlloc allocates thread, timer, mutex, semaphore,
* event flags and message queue block object memory.
* Or it allocates the thread or message queue stack memory.
* @param [in] memory size to be allocated from BytePool
* [in] to be allocated memory type (Heap or Stack)
* @retval pointer to the allocated memory or NULL in case of error.
*/
static uint8_t *MemAlloc(uint32_t mem_size, uint8_t pool_type)
{
/* The output pointer to the allocated memory or NULL in case of error */
uint8_t *mem_ptr;
/* Allocated memory size */
uint32_t allocated_mem_size = mem_size;
/* Pointer to the BytePool to be used for memory allocation */
TX_BYTE_POOL *byte_pool;
/* Check if the memory size is invalid or the BytePool type is wrong */
if ((mem_size == 0) || (pool_type > RTOS2_BYTE_POOL_HEAP_TYPE))
{
/* Return NULL in case of error */
mem_ptr = NULL;
}
else
{
/* If the memory size the be allocated is less then the TX_BYTE_POOL_MIN */
if (allocated_mem_size < TX_BYTE_POOL_MIN)
{
/* We should at least allocate TX_BYTE_POOL_MIN */
allocated_mem_size = TX_BYTE_POOL_MIN;
}
/* Assign the BytePool to be used (StackBytePool or HeapBytePool) */
if (pool_type == RTOS2_BYTE_POOL_STACK_TYPE)
{
/* Point to the Stack BytePool */
byte_pool = &StackBytePool;
}
else
{
/* Point to the Heap BytePool */
byte_pool = &HeapBytePool;
}
/* Allocate the mem_ptr */
if (tx_byte_allocate(byte_pool, (void **) &mem_ptr, allocated_mem_size, TX_NO_WAIT) != TX_SUCCESS)
{
/* Return NULL in case of error */
mem_ptr = NULL;
}
}
return (mem_ptr);
}
/**
* @brief The function MemFree allocates thread, timer, mutex, semaphore,
* event flags and message queue block object memory.
* Or it allocates the thread or message queue stack memory.
* @param [in] memory size to be allocated from BytePool
* [in] to be allocated memory type (Heap or Stack)
* @retval pointer to the allocated memory or NULL in case of error.
*/
static osStatus_t MemFree(VOID *memory_ptr)
{
/* The output status code that indicates the execution status */
osStatus_t status = osOK;
/* Check if the memory_ptr is invalid */
if (memory_ptr == NULL)
{
/* Return osError in case of error */
status = osError;
}
else
{
/* Free the allocated memory_ptr */
if (tx_byte_release(memory_ptr) != TX_SUCCESS)
{
/* Return osError in case of error */
status = osError;
}
}
return (status);
}
/**
* @brief The function MemInit creates memory pools for stack and heap.
* The stack pool is used for threads and queues stacks allocations.
* The heap pool is used for threads, timers, mutex, semaphores,
* message queues and events flags control block object memory allocations.
* The size of stack and heap pools are user configured using the
* RTOS2_BYTE_POOL_STACK_SIZE and RTOS2_BYTE_POOL_HEAP_SIZE flags.
* @param none.
* @retval status code that indicates the execution status of the function.
*/
static osStatus_t MemInit(void)
{
/* Allocated memory size */
uint32_t bytepool_size = RTOS2_BYTE_POOL_STACK_SIZE;
#ifdef USE_DYNAMIC_MEMORY_ALLOCATION
/* Unused memory address */
CHAR *unused_memory = NULL;
#else
#ifdef USE_MEMORY_POOL_ALLOCATION
CHAR *unused_memory_Stack = NULL;
CHAR *unused_memory_Heap = NULL;
#endif
#endif
/* If the memory size the be allocated is less then the TX_BYTE_POOL_MIN */
if (bytepool_size < TX_BYTE_POOL_MIN)
{
/* We should at least allocate TX_BYTE_POOL_MIN */
bytepool_size = TX_BYTE_POOL_MIN;
}
/* Initialize the Heap BytePool address */
#ifdef USE_DYNAMIC_MEMORY_ALLOCATION
unused_memory = (CHAR *)_tx_initialize_unused_memory;
#else
#ifdef USE_MEMORY_POOL_ALLOCATION
static CHAR freememStack[RTOS2_BYTE_POOL_STACK_SIZE + RTOS2_INTERNAL_BYTE_POOL_SIZE];
static CHAR freememHeap[RTOS2_BYTE_POOL_HEAP_SIZE + RTOS2_INTERNAL_BYTE_POOL_SIZE];
unused_memory_Stack = (CHAR *)freememStack;
unused_memory_Heap = (CHAR *)freememHeap;
#endif
#endif
#ifdef USE_DYNAMIC_MEMORY_ALLOCATION
/* Create a byte memory pool from which to allocate the timer control
block */
if (tx_byte_pool_create(&StackBytePool, "Byte Pool Stack", unused_memory,
RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size) != TX_SUCCESS)
{
/* Return osError in case of error */
return (osError);
}
else
{
/* Set the tx_initialize_unused_memory address */
unused_memory += RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size;
}
/* Set bytepool_size to the user configured Heap size */
bytepool_size = RTOS2_BYTE_POOL_HEAP_SIZE;
/* If the memory size the be allocated is less then the TX_BYTE_POOL_MIN */
if (bytepool_size < TX_BYTE_POOL_MIN)
{
/* We should at least allocate TX_BYTE_POOL_MIN */
bytepool_size = TX_BYTE_POOL_MIN;
}
/* Create a byte memory pool from which to allocate the timer control
block */
if (tx_byte_pool_create(&HeapBytePool, "Byte Pool Heap", unused_memory,
RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size) != TX_SUCCESS)
{
/* Return osError in case of error */
return (osError);
}
else
{
/* Set the tx_initialize_unused_memory address */
unused_memory += RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size;
}
/* Update the _tx_initialize_unused_memory */
_tx_initialize_unused_memory = unused_memory;
#else
#ifdef USE_MEMORY_POOL_ALLOCATION
/* Create a byte memory pool from which to allocate the timer control
block */
if (tx_byte_pool_create(&StackBytePool, "Byte Pool Stack", unused_memory_Stack,
RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size) != TX_SUCCESS)
{
/* Return osError in case of error */
return (osError);
}
/* Set bytepool_size to the user configured Heap size */
bytepool_size = RTOS2_BYTE_POOL_HEAP_SIZE;
/* If the memory size the be allocated is less then the TX_BYTE_POOL_MIN */
if (bytepool_size < TX_BYTE_POOL_MIN)
{
/* We should at least allocate TX_BYTE_POOL_MIN */
bytepool_size = TX_BYTE_POOL_MIN;
}
/* Create a byte memory pool from which to allocate the timer control
block */
if (tx_byte_pool_create(&HeapBytePool, "Byte Pool Heap", unused_memory_Heap,
RTOS2_INTERNAL_BYTE_POOL_SIZE + bytepool_size) != TX_SUCCESS)
{
/* Return osError in case of error */
return (osError);
}
#endif
#endif
return (osOK);
}
/*---------------------------------------------------------------------------*/
/*---------------------------Kenel Management APIs---------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @brief The function osKernelInitialize initializes the RTOS Kernel. Before
* it is successfully executed, only the functions osKernelGetInfo and
* osKernelGetState may be called.
* Note : This function cannot be called from Interrupt Service
* Routines.
* @param none
* @retval status code that indicates the execution status of the function.
*/
osStatus_t osKernelInitialize(void)
{
/* The output status code that indicates the execution status */
osStatus_t status;
/* Check if this API is called from Interrupt Service Routines */
if (IS_IRQ_MODE())
{
/* Return osErrorISR in case of error */
status = osErrorISR;
}
else
{
/* Check if the kernel state is osKernelInactive */
if (KernelState == osKernelInactive)
{
/* Initialize the kernel */
_tx_initialize_kernel_setup();
/* Initialize the Heap and stack memory BytePools */
if (MemInit() == osOK)
{
/* Set the kernel state to osKernelReady */
KernelState = osKernelReady;
/* Return osOK in case of success */
status = osOK;
}
else
{
/* Return osError in case of error */
status = osError;
}
}
else
{
/* Return osError in case of error */
status = osError;
}
}
return (status);
}
/**
* @brief The function osKernelGetInfo retrieves the API and kernel version
* of the underlying RTOS kernel and a human readable identifier string
* for the kernel. It can be safely called before the RTOS is
* initialized or started (call to osKernelInitialize or osKernelStart)
* Note : This function may be called from Interrupt Service
* Routines.
* @param [out] version pointer to buffer for retrieving version information.
* [out] id_buf pointer to buffer for retrieving kernel identification
* string.
* [in] id_size size of buffer for kernel identification string.
* @retval status code that indicates the execution status of the function.
*/
osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size)
{
/* The output status code that indicates the execution status */
osStatus_t status = osOK;
/* Check if input version pointer is not NULL */
if (version != NULL)
{
/* Version encoding is major.minor.rev: mmnnnrrrr dec */
version->api = KERNEL_VERSION;
version->kernel = KERNEL_VERSION;
}
else
{
/* Return osError in case of error */
status = osError;
}
/* Check if input id_buf pointer is not NULL and id_size != 0 */
if ((id_buf != NULL) && (id_size != 0U))
{
if (id_size > sizeof(KERNEL_ID))
{
id_size = sizeof(KERNEL_ID);
}
memcpy(id_buf, KERNEL_ID, id_size);
}
else
{
/* Return osError in case of error */
status = osError;
}
return (status);
}
/**
* @brief The function osKernelGetState returns the current state of the
* kernel and can be safely called before the RTOS is initialized or
* started (call to osKernelInitialize or osKernelStart). In case it
* fails it will return osKernelError, otherwise it returns the kernel
* state (refer to osKernelState_t for the list of kernel states).
* Note : This function may be called from Interrupt Service
* Routines.
* @param none
* @retval current RTOS Kernel state.
*/
osKernelState_t osKernelGetState(void)
{
return (KernelState);
}
/**
* @brief The function osKernelStart starts the RTOS kernel and begins thread
* switching. It will not return to its calling function in case of
* success. Before it is successfully executed, only the functions
* osKernelGetInfo, osKernelGetState, and object creation functions
* (osXxxNew) may be called.
* Note : This function cannot be called from Interrupt Service
* Routines.
* @param none
* @retval status code that indicates the execution status of the function.
*/
osStatus_t osKernelStart(void)
{
/* The output status code that indicates the execution status */
osStatus_t status;
/* Check if this API is called from Interrupt Service Routines */
if (IS_IRQ_MODE())
{
/* Return osErrorISR in case of error */
status = osErrorISR;
}
else
{
/* Check if the kernel state is osKernelReady */
if (KernelState == osKernelReady)
{
/* Set the kernel state to osKernelRunning */
KernelState = osKernelRunning;
/* Return osOK in case of success */
status = osOK;
/* Start the Kernel */
tx_kernel_enter();
}
else
{
/* Return osError in case of error */
status = osError;
}
}
return (status);
}
/**
* @brief The function osKernelGetTickCount returns the current RTOS kernel
* tick count.
* Note : This function may be called from Interrupt Service
* Routines.
* @param none
* @retval RTOS kernel current tick count.
*/
uint32_t osKernelGetTickCount(void)
{
/* The output RTOS kernel current tick count */
uint32_t ticks;
/* Get the RTOS kernel current tick count */
ticks = (uint32_t)tx_time_get();
return (ticks);
}
/**
* @brief The function osKernelGetTickFreq returns the frequency of the
* current RTOS kernel tick.
* Note : This function may be called from Interrupt Service
* Routines.
* @param none
* @retval frequency of the kernel tick in hertz, i.e. kernel ticks per second.
*/
uint32_t osKernelGetTickFreq(void)
{
return (TX_TIMER_TICKS_PER_SECOND);
}
/**
* @brief The function osKernelGetSysTimerCount returns the current RTOS
* kernel system timer as a 32-bit value. The value is a rolling 32-bit
* counter that is composed of the kernel system interrupt timer value
* and the counter that counts these interrupts (RTOS kernel ticks).
* This function allows the implementation of very short timeout checks
* below the RTOS tick granularity. Such checks might be required when
* checking for a busy status in a device or peripheral initialization
* routine, see code example below.
* Note : This function may be called from Interrupt Service
* Routines.
* @param none
* @retval RTOS kernel current system timer count as 32-bit value.
*/
uint32_t osKernelGetSysTimerCount(void)
{
/* The RTOS kernel current tick count */
uint32_t ticks;
/* The output RTOS kernel current system timer count as 32-bit value */
uint32_t val;
/* Get the RTOS kernel current tick count */
ticks = (uint32_t)tx_time_get();
/* Compute the RTOS kernel current system timer count */
val = (uint32_t)(ticks * (SystemCoreClock / TX_TIMER_TICKS_PER_SECOND));
return (val);
}
/**
* @brief The function osKernelGetSysTimerFreq returns the frequency of the
* current RTOS kernel system timer.
* Note : This function may be called from Interrupt Service
* Routines.
* @param none
* @retval frequency of the system timer in hertz, i.e. timer ticks per second.
*/
uint32_t osKernelGetSysTimerFreq(void)
{
return (SystemCoreClock);
}
/*---------------------------------------------------------------------------*/
/*-----------------------------Generic Wait APIs-----------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @brief The function osDelay waits for a time period specified in kernel
* ticks. For a value of 1 the system waits until the next timer tick
* occurs. The actual time delay may be up to one timer tick less than
* specified, i.e. calling osDelay(1) right before the next system tick
* occurs the thread is rescheduled immediately.
* The delayed thread is put into the BLOCKED state and a context
* switch occurs immediately. The thread is automatically put back to
* the READY state after the given amount of ticks has elapsed. If the
* thread will have the highest priority in READY state it will being
* scheduled immediately.
* Note : This function cannot be called from Interrupt Service
* Routines.
* @param [in] ticks time ticks value
* @retval status code that indicates the execution status of the function.
*/
osStatus_t osDelay(uint32_t ticks)
{
/* The output status code that indicates the execution status */
osStatus_t status;
/* Check if this API is called from Interrupt Service Routines */
if (IS_IRQ_MODE())
{
/* Return osErrorISR in case of error */
status = osErrorISR;
}
else
{
/* Return osOK in case of success */
status = osOK;
/* Check that the input ticks != 0 */
if (ticks != 0U)
{
/* Sleep the thread */
tx_thread_sleep(ticks);
}
}
return (status);
}
/**
* @brief The function osDelayUntil waits until an absolute time (specified
* in kernel ticks) is reached.
* The corner case when the kernel tick counter overflows is handled by
* osDelayUntil. Thus it is absolutely legal to provide a value which
* is lower than the current tick value, i.e. returned by
* osKernelGetTickCount. Typically as a user you do not have to take
* care about the overflow. The only limitation you have to have in
* mind is that the maximum delay is limited to (231)-1 ticks.
* The delayed thread is put into the BLOCKED state and a context
* switch occurs immediately. The thread is automatically put back to
* the READY state when the given time is reached. If the thread will
* have the highest priority in READY state it will being scheduled
* immediately.
* @param [in] ticks absolute time in ticks
* @retval status code that indicates the execution status of the function.
*/
osStatus_t osDelayUntil(uint32_t ticks)
{
uint32_t tcnt, delay;
/* The output status code that indicates the execution status */
osStatus_t status;
/* Check if this API is called from Interrupt Service Routines */
if (IS_IRQ_MODE())
{
/* Return osErrorISR in case of error */
status = osErrorISR;
}
else
{
/* Return osOK in case of success */
status = osOK;
/* Return osOK in case of success */
tcnt = (uint32_t)tx_time_get();
/* Determine remaining number of ticks to delay */
delay = ticks - tcnt;
/* Check if target tick has not expired */
if ((delay != 0U) && (0 == (delay >> (8 * sizeof(uint32_t) - 1))))
{
/* Sleep the thread */
tx_thread_sleep(delay);
}
else
{
/* No delay or already expired */
status = osErrorParameter;
}
}
return (status);
}
/*---------------------------------------------------------------------------*/
/*--------------------------Thread Management APIs---------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @brief The function osThreadNew starts a thread function by adding it to
* the list of active threads and sets it to state READY. Arguments for
* the thread function are passed using the parameter pointer
* *argument. When the priority of the created thread function is
* higher than the current RUNNING thread, the created thread function
* starts instantly and becomes the new RUNNING thread. Thread
* attributes are defined with the parameter pointer attr. Attributes
* include settings for thread priority, stack size, or memory
* allocation.
* The function can be safely called before the RTOS is started
* (call to osKernelStart), but not before it is initialized (call to
* osKernelInitialize).
* The function osThreadNew returns the pointer to the thread object
* identifier or NULL in case of an error.
* Note : This function Cannot be called from Interrupt Service
* Routines.
* @param [in] func thread function.
* [in] argument pointer that is passed to the thread function as
* start argument.
* [in] attr thread attributes; NULL: default values.
* @retval thread ID for reference by other functions or NULL in case of error.
*/
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
{
/* For ThreadX the control block pointer is the thread identifier */
TX_THREAD *thread_ptr = NULL;
/* Pointer to the thread name */
CHAR *name_ptr = NULL;
/* Pointer to start address of the thread stack */
VOID *stack_start;
/* The thread stack size */
ULONG stack_size;
/* The thread control block size */
ULONG cb_size;
/* The thread priority */
UINT priority;
/* The thread entry input */
ULONG entry_input = 0;
/* Check if this API is called from Interrupt Service Routines
or the thread_id is NULL */
if (!IS_IRQ_MODE() && (func != NULL))
{
/* Initialize the name_ptr to NULL */
name_ptr = NULL;
/* Check if the attr is not NULL */
if (attr != NULL)
{
/* Check if the name_ptr is not NULL */
if (attr->name != NULL)
{
/* Set the thread name_ptr */
name_ptr = (CHAR *)attr->name;
}
/* Check the input priority value and attribute bits for osThreadJoinable
parameter */
if ((attr->priority < osPriorityIdle) || (attr->priority > osPriorityISR))
{
/* Return NULL pointer in case of error */
return (NULL);
}
else
{
/* Set the thread priority */
priority = osPriorityISR - attr->priority;
}
/* Check if the argument is not NULL */
if (argument != NULL)
{
/* Set the entry_input */
entry_input = (ULONG) argument;
}
/* Check if the stack size is equal to 0 */
if (attr->stack_size == 0U)
{
/* Set stack size to DEFAULT_THREAD_STACK_SIZE */
stack_size = RTOS2_DEFAULT_THREAD_STACK_SIZE;
}
else if (attr->stack_size < TX_BYTE_POOL_MIN)
{
/* Set stack size to TX_BYTE_POOL_MIN */
stack_size = TX_BYTE_POOL_MIN;
}
else
{
/* Set stack size to attr->stack_size */
stack_size = (ULONG)attr->stack_size;
}
/* Check if the input stack pointer is NULL */
if (attr->stack_mem == NULL)
{
/* Allocate the stack for the thread to be created */
stack_start = MemAlloc(stack_size, RTOS2_BYTE_POOL_STACK_TYPE);
if (stack_start == NULL)
{
/* Return NULL pointer in case of error */
return (NULL);
}
}
else
{
if (attr->stack_size == 0U)
{
/* Return NULL pointer in case of error */
return (NULL);
}
else
{
/* Set stack size to the input attr->stack_size */
stack_size = (ULONG)attr->stack_size;
}
/* The stack shall point to the input stack memory address */
stack_start = attr->stack_mem;
}
/* Check if the control block size is equal to 0 */
if (attr->cb_size == 0U)
{
/* Set control block size to sizeof(TX_THREAD) */
cb_size = sizeof(TX_THREAD);
}
else if (attr->cb_size < sizeof(TX_THREAD))
{
/* Return NULL pointer in case of error */
return (NULL);
}
else
{
/* Set stack size to attr->cb_size */
cb_size = (ULONG)attr->cb_size;
}
/* Check if the input control block pointer is NULL */
if (attr->cb_mem == NULL)
{
/* Allocate the thread_ptr structure for the thread to be created */
thread_ptr = (TX_THREAD *)MemAlloc(cb_size, RTOS2_BYTE_POOL_HEAP_TYPE);
if (thread_ptr == NULL)
{
/* Check if the memory for thread stack has been internally
allocated */
if (attr->stack_mem == NULL)
{
/* Free the already allocated memory for thread stack */
MemFree(stack_start);
}
/* Return NULL pointer in case of error */
return (NULL);
}
}
else
{
/* The control block shall point to the input cb_mem memory address */
thread_ptr = attr->cb_mem;
}
}
else
{
/* Set the thread priority to default osPriorityNormal*/
priority = osPriorityISR - osPriorityNormal;
/* Initialize the name_ptr to NULL */
name_ptr = NULL;
/* Initialize the stack_size to RTOS2_DEFAULT_THREAD_STACK_SIZE */
stack_size = RTOS2_DEFAULT_THREAD_STACK_SIZE;
/* Check if the argument is not NULL */
if (argument != NULL)
{
/* Set the entry_input */
entry_input = (ULONG) argument;
}
/* Allocate the stack for the thread to be created */
stack_start = MemAlloc(stack_size, RTOS2_BYTE_POOL_STACK_TYPE);
if (stack_start == NULL)
{
/* Return NULL pointer in case of error */
return (NULL);
}
/* Allocate the thread_ptr structure for the thread to be created */
thread_ptr = (TX_THREAD *)MemAlloc(sizeof(TX_THREAD), RTOS2_BYTE_POOL_HEAP_TYPE);
if (thread_ptr == NULL)
{
/* Free the already allocated memory for thread stack */
MemFree(stack_start);
/* Return NULL pointer in case of error */
return (NULL);
}
}
/* Call the tx_thread_create function to create the new thread.
Note: By default the preempt_threshold shall be deactivated by setting
its value to the priority or deactivated using
TX_DISABLE_PREEMPTION_THRESHOLD */
if (tx_thread_create(thread_ptr, name_ptr, (void(*)(ULONG))func, entry_input, stack_start, stack_size, priority,
priority, RTOS2_DEFAULT_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
/* Check if the memory for thread control block has been internally
allocated */
if ((attr->cb_mem == NULL) || (attr == NULL))
{
/* Free the already allocated memory for thread control block */
MemFree(thread_ptr);
}
/* Check if the memory for thread stack has been internally allocated */
if ((attr->stack_mem == NULL) || (attr == NULL))
{
/* Free the already allocated memory for thread stack */
MemFree(stack_start);
}
/* Return NULL pointer in case of error */
thread_ptr = NULL;
}
else
{
/* Check if the thread shall be created joinable */
if ((attr != NULL) && (attr->attr_bits == osThreadJoinable))
{
/* Set the thread to Joinable state */
thread_ptr->tx_thread_detached_joinable = osThreadJoinable;
}
else
{
/* Set the thread to Detached state */
thread_ptr->tx_thread_detached_joinable = osThreadDetached;
}
}
}
return ((osThreadId_t)thread_ptr);
}
/**
* @brief The function osThreadGetName returns the pointer to the name_ptr
* string of the thread identified by parameter thread_id or NULL in
* case of an error.
* Note : This function cannot be called from Interrupt Service
* Routines.
* @param [in] thread_id thread ID obtained by osThreadNew or osThreadGetId
* @retval name_ptr as null-terminated string.
*/
const char *osThreadGetName(osThreadId_t thread_id)
{
/* For ThreadX the control block pointer is the thread identifier */
TX_THREAD *thread_ptr = (TX_THREAD *)thread_id;
/* The output name_ptr as null-terminated string */
CHAR *name_ptr = NULL;
/* Check if this API is called from Interrupt Service Routines, the thread_id
is NULL or thread_id->tx_thread_id != TX_THREAD_ID */
if (IS_IRQ_MODE() || (thread_ptr == NULL) || (thread_ptr->tx_thread_id != TX_THREAD_ID))
{
/* Return NULL in case of an error */
name_ptr = NULL;
}
else
{
/* Call the tx_thread_info_get to get the thread name_ptr */
if (tx_thread_info_get(thread_ptr, &name_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != TX_SUCCESS)
{
/* Return NULL in case of an error */
name_ptr = NULL;
}
}
return (name_ptr);
}
/**
* @brief The function osThreadGetId returns the thread object ID of the
* currently running thread or NULL in case of an error.
* Note : This function may be called from Interrupt Service Routines.
* @param none
* @retval thread ID for reference by other functions or NULL in case of error.
*/
osThreadId_t osThreadGetId(void)
{
/* For ThreadX the control block pointer is the thread identifier */
osThreadId_t thread_id;
/* Call the tx_thread_identify to get the control block pointer of the
currently executing thread. */
thread_id = (osThreadId_t)tx_thread_identify();
return (thread_id);