1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** Thread-Metric Component */
15 /** */
16 /** Porting Layer (ThreadX Example) */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21
22 /* Turn off ThreadX error checking. */
23
24 #ifndef TX_DISABLE_ERROR_CHECKING
25 #define TX_DISABLE_ERROR_CHECKING
26 #endif
27
28
29 /* For smallest size, the ThreadX library and application code should be built
30 with the following options defined (easiest to add in tx_port.h):
31
32 #define TX_ENABLE_EXECUTION_CHANGE_NOTIFY
33 #define TX_DISABLE_PREEMPTION_THRESHOLD
34 #define TX_DISABLE_NOTIFY_CALLBACKS
35 #define TX_DISABLE_REDUNDANT_CLEARING
36 #define TX_DISABLE_STACK_FILLING
37 #define TX_NOT_INTERRUPTABLE
38 #define TX_TIMER_PROCESS_IN_ISR
39
40 For the fastest performance, these additional options should also be used:
41
42 #define TX_REACTIVATE_INLINE
43 #define TX_INLINE_THREAD_RESUME_SUSPEND
44
45 */
46
47
48
49 /* Include necessary files. */
50
51 #include "tx_api.h"
52 #include "tm_api.h"
53
54
55 /* Define ThreadX mapping constants. */
56
57 #define TM_THREADX_MAX_THREADS 10
58 #define TM_THREADX_MAX_QUEUES 1
59 #define TM_THREADX_MAX_SEMAPHORES 1
60 #define TM_THREADX_MAX_MEMORY_POOLS 1
61
62
63 /* Define the default ThreadX stack size. */
64
65 #define TM_THREADX_THREAD_STACK_SIZE 2096
66
67
68 /* Define the default ThreadX queue size. */
69
70 #define TM_THREADX_QUEUE_SIZE 200
71
72
73 /* Define the default ThreadX memory pool size. */
74
75 #define TM_THREADX_MEMORY_POOL_SIZE 2048
76
77
78 /* Define the number of timer interrupt ticks per second. */
79
80 #define TM_THREADX_TICKS_PER_SECOND 100
81
82
83 /* Define ThreadX data structures. */
84
85 TX_THREAD tm_thread_array[TM_THREADX_MAX_THREADS];
86 TX_QUEUE tm_queue_array[TM_THREADX_MAX_QUEUES];
87 TX_SEMAPHORE tm_semaphore_array[TM_THREADX_MAX_SEMAPHORES];
88 TX_BLOCK_POOL tm_block_pool_array[TM_THREADX_MAX_MEMORY_POOLS];
89
90
91 /* Define ThreadX object data areas. */
92
93 unsigned char tm_thread_stack_area[TM_THREADX_MAX_THREADS*TM_THREADX_THREAD_STACK_SIZE];
94 unsigned char tm_queue_memory_area[TM_THREADX_MAX_QUEUES*TM_THREADX_QUEUE_SIZE];
95 unsigned char tm_pool_memory_area[TM_THREADX_MAX_MEMORY_POOLS*TM_THREADX_MEMORY_POOL_SIZE];
96
97
98 /* Define array to remember the test entry function. */
99
100 void *tm_thread_entry_functions[TM_THREADX_MAX_THREADS];
101
102
103 /* Remember the test initialization function. */
104
105 void (*tm_initialization_function)(void);
106
107
108 /* Define our shell entry function to match ThreadX. */
109
110 VOID tm_thread_entry(ULONG thread_input);
111
112
113 /* This function called from main performs basic RTOS initialization,
114 calls the test initialization function, and then starts the RTOS function. */
tm_initialize(void (* test_initialization_function)(void))115 void tm_initialize(void (*test_initialization_function)(void))
116 {
117
118 /* Save the test initialization function. */
119 tm_initialization_function = test_initialization_function;
120
121 /* Call the previously defined initialization function. */
122 (tm_initialization_function)();
123 }
124
125
126 /* This function takes a thread ID and priority and attempts to create the
127 file in the underlying RTOS. Valid priorities range from 1 through 31,
128 where 1 is the highest priority and 31 is the lowest. If successful,
129 the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_thread_create(int thread_id,int priority,void (* entry_function)(void))130 int tm_thread_create(int thread_id, int priority, void (*entry_function)(void))
131 {
132
133 UINT status;
134
135 /* Remember the actual thread entry. */
136 tm_thread_entry_functions[thread_id] = (void *) entry_function;
137
138 /* Create the thread under ThreadX. */
139 status = tx_thread_create(&tm_thread_array[thread_id], "Thread-Metric test", tm_thread_entry, (ULONG) thread_id,
140 &tm_thread_stack_area[thread_id*TM_THREADX_THREAD_STACK_SIZE], TM_THREADX_THREAD_STACK_SIZE,
141 (UINT) priority, (UINT) priority, TX_NO_TIME_SLICE, TX_DONT_START);
142
143 /* Determine if the thread create was successful. */
144 if (status == TX_SUCCESS)
145 return(TM_SUCCESS);
146 else
147 return(TM_ERROR);
148 }
149
150
151 /* This function resumes the specified thread. If successful, the function should
152 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_thread_resume(int thread_id)153 int tm_thread_resume(int thread_id)
154 {
155
156 UINT status;
157
158
159 /* Attempt to resume the thread. */
160 status = tx_thread_resume(&tm_thread_array[thread_id]);
161
162 /* Determine if the thread resume was successful. */
163 if (status == TX_SUCCESS)
164 return(TM_SUCCESS);
165 else
166 return(TM_ERROR);
167 }
168
169
170 /* This function suspends the specified thread. If successful, the function should
171 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_thread_suspend(int thread_id)172 int tm_thread_suspend(int thread_id)
173 {
174
175 UINT status;
176
177
178 /* Attempt to suspend the thread. */
179 status = tx_thread_suspend(&tm_thread_array[thread_id]);
180
181 /* Determine if the thread suspend was successful. */
182 if (status == TX_SUCCESS)
183 return(TM_SUCCESS);
184 else
185 return(TM_ERROR);
186 }
187
188
189 /* This function relinquishes to other ready threads at the same
190 priority. */
tm_thread_relinquish(void)191 void tm_thread_relinquish(void)
192 {
193
194 /* Relinquish to other threads at the same priority. */
195 tx_thread_relinquish();
196 }
197
198
199 /* This function suspends the specified thread for the specified number
200 of seconds. If successful, the function should return TM_SUCCESS.
201 Otherwise, TM_ERROR should be returned. */
tm_thread_sleep(int seconds)202 void tm_thread_sleep(int seconds)
203 {
204
205 /* Attempt to sleep. */
206 tx_thread_sleep(((UINT) seconds)*TM_THREADX_TICKS_PER_SECOND);
207 }
208
209
210 /* This function creates the specified queue. If successful, the function should
211 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_queue_create(int queue_id)212 int tm_queue_create(int queue_id)
213 {
214
215 UINT status;
216
217
218 /* Create the specified queue with 16-byte messages. */
219 status = tx_queue_create(&tm_queue_array[queue_id], "Thread-Metric test", TX_4_ULONG,
220 &tm_queue_memory_area[queue_id*TM_THREADX_QUEUE_SIZE], TM_THREADX_QUEUE_SIZE);
221
222 /* Determine if the queue create was successful. */
223 if (status == TX_SUCCESS)
224 return(TM_SUCCESS);
225 else
226 return(TM_ERROR);
227 }
228
229
230 /* This function sends a 16-byte message to the specified queue. If successful,
231 the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_queue_send(int queue_id,unsigned long * message_ptr)232 int tm_queue_send(int queue_id, unsigned long *message_ptr)
233 {
234
235 UINT status;
236
237
238 /* Send the 16-byte message to the specified queue. */
239 status = tx_queue_send(&tm_queue_array[queue_id], message_ptr, TX_NO_WAIT);
240
241 /* Determine if the queue send was successful. */
242 if (status == TX_SUCCESS)
243 return(TM_SUCCESS);
244 else
245 return(TM_ERROR);
246 }
247
248
249 /* This function receives a 16-byte message from the specified queue. If successful,
250 the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_queue_receive(int queue_id,unsigned long * message_ptr)251 int tm_queue_receive(int queue_id, unsigned long *message_ptr)
252 {
253
254 UINT status;
255
256
257 /* Receive a 16-byte message from the specified queue. */
258 status = tx_queue_receive(&tm_queue_array[queue_id], message_ptr, TX_NO_WAIT);
259
260 /* Determine if the queue receive was successful. */
261 if (status == TX_SUCCESS)
262 return(TM_SUCCESS);
263 else
264 return(TM_ERROR);
265 }
266
267
268 /* This function creates the specified semaphore. If successful, the function should
269 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_semaphore_create(int semaphore_id)270 int tm_semaphore_create(int semaphore_id)
271 {
272
273 UINT status;
274
275
276 /* Create semaphore. */
277 status = tx_semaphore_create(&tm_semaphore_array[semaphore_id], "Thread-Metric test", 1);
278
279 /* Determine if the semaphore create was successful. */
280 if (status == TX_SUCCESS)
281 return(TM_SUCCESS);
282 else
283 return(TM_ERROR);
284 }
285
286
287 /* This function gets the specified semaphore. If successful, the function should
288 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_semaphore_get(int semaphore_id)289 int tm_semaphore_get(int semaphore_id)
290 {
291
292 UINT status;
293
294
295 /* Get the semaphore. */
296 status = tx_semaphore_get(&tm_semaphore_array[semaphore_id], TX_NO_WAIT);
297
298 /* Determine if the semaphore get was successful. */
299 if (status == TX_SUCCESS)
300 return(TM_SUCCESS);
301 else
302 return(TM_ERROR);
303 }
304
305
306 /* This function puts the specified semaphore. If successful, the function should
307 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_semaphore_put(int semaphore_id)308 int tm_semaphore_put(int semaphore_id)
309 {
310
311 UINT status;
312
313
314 /* Put the semaphore. */
315 status = tx_semaphore_put(&tm_semaphore_array[semaphore_id]);
316
317 /* Determine if the semaphore put was successful. */
318 if (status == TX_SUCCESS)
319 return(TM_SUCCESS);
320 else
321 return(TM_ERROR);
322 }
323
324
325 /* This function creates the specified memory pool that can support one or more
326 allocations of 128 bytes. If successful, the function should
327 return TM_SUCCESS. Otherwise, TM_ERROR should be returned. */
tm_memory_pool_create(int pool_id)328 int tm_memory_pool_create(int pool_id)
329 {
330
331 UINT status;
332
333
334 /* Create the memory pool. */
335 status = tx_block_pool_create(&tm_block_pool_array[pool_id], "Thread-Metric test", 128, &tm_pool_memory_area[pool_id*TM_THREADX_MEMORY_POOL_SIZE], TM_THREADX_MEMORY_POOL_SIZE);
336
337 /* Determine if the block pool memory was successful. */
338 if (status == TX_SUCCESS)
339 return(TM_SUCCESS);
340 else
341 return(TM_ERROR);
342 }
343
344
345 /* This function allocates a 128 byte block from the specified memory pool.
346 If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
347 should be returned. */
tm_memory_pool_allocate(int pool_id,unsigned char ** memory_ptr)348 int tm_memory_pool_allocate(int pool_id, unsigned char **memory_ptr)
349 {
350
351 UINT status;
352
353
354 /* Allocate a 128-byte block from the specified memory pool. */
355 status = tx_block_allocate(&tm_block_pool_array[pool_id], (void **) memory_ptr, TX_NO_WAIT);
356
357 /* Determine if the block pool allocate was successful. */
358 if (status == TX_SUCCESS)
359 return(TM_SUCCESS);
360 else
361 return(TM_ERROR);
362 }
363
364
365 /* This function releases a previously allocated 128 byte block from the specified
366 memory pool. If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
367 should be returned. */
tm_memory_pool_deallocate(int pool_id,unsigned char * memory_ptr)368 int tm_memory_pool_deallocate(int pool_id, unsigned char *memory_ptr)
369 {
370
371 UINT status;
372
373
374 /* Release the 128-byte block back to the specified memory pool. */
375 status = tx_block_release((void *) memory_ptr);
376
377 /* Determine if the block pool release was successful. */
378 if (status == TX_SUCCESS)
379 return(TM_SUCCESS);
380 else
381 return(TM_ERROR);
382 }
383
384
385 /* This is the ThreadX thread entry. It is going to call the Thread-Metric
386 entry function saved earlier. */
tm_thread_entry(ULONG thread_input)387 VOID tm_thread_entry(ULONG thread_input)
388 {
389
390 void (*entry_function)(void);
391
392
393 /* Pickup the entry function from the saved array. */
394 entry_function = (void (*)(void)) tm_thread_entry_functions[thread_input];
395
396 /* Call the entry function. */
397 (entry_function)();
398 }
399
400
401