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