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