1 /* This is a small demo of the high-performance ThreadX kernel.  It includes examples of eight
2    threads of different priorities, using a message queue, semaphore, mutex, event flags group,
3    byte pool, and block pool.  */
4 
5 #include "tx_api.h"
6 #include "board_setup.h"
7 
8 #define DEMO_STACK_SIZE         1024
9 #define DEMO_BYTE_POOL_SIZE     9120
10 #define DEMO_BLOCK_POOL_SIZE    100
11 #define DEMO_QUEUE_SIZE         100
12 
13 
14 /* Define TraceX trace oblects */
15 #define TRACE_BUFFER_SIZE       (4 * 1024)
16 #define TRACE_OBJECTS_COUNT     20
17 /* Define TraceX trace buffer */
18 UCHAR tx_trace_buffer[TRACE_BUFFER_SIZE];
19 
20 
21 /* Define the ThreadX object control blocks...  */
22 
23 TX_THREAD               thread_0;
24 TX_THREAD               thread_1;
25 TX_THREAD               thread_2;
26 TX_THREAD               thread_3;
27 TX_THREAD               thread_4;
28 TX_THREAD               thread_5;
29 TX_THREAD               thread_6;
30 TX_THREAD               thread_7;
31 TX_QUEUE                queue_0;
32 TX_SEMAPHORE            semaphore_0;
33 TX_MUTEX                mutex_0;
34 TX_EVENT_FLAGS_GROUP    event_flags_0;
35 TX_BYTE_POOL            byte_pool_0;
36 TX_BLOCK_POOL           block_pool_0;
37 
38 
39 /* Define demo timer */
40 #define DEMO_TIMER_PERIOD     10
41 #define DEMO_TIMER_VALUE      0xaaaaaaaa
42 TX_TIMER                timer_0;
43 ULONG           timer_0_counter;
44 
45 
46 /* Define the counters used in the demo application...  */
47 
48 ULONG           thread_0_counter;
49 ULONG           thread_1_counter;
50 ULONG           thread_1_messages_sent;
51 ULONG           thread_2_counter;
52 ULONG           thread_2_messages_received;
53 ULONG           thread_3_counter;
54 ULONG           thread_4_counter;
55 ULONG           thread_5_counter;
56 ULONG           thread_6_counter;
57 ULONG           thread_7_counter;
58 
59 
60 /* Define thread prototypes.  */
61 
62 void    thread_0_entry(ULONG thread_input);
63 void    thread_1_entry(ULONG thread_input);
64 void    thread_2_entry(ULONG thread_input);
65 void    thread_3_and_4_entry(ULONG thread_input);
66 void    thread_5_entry(ULONG thread_input);
67 void    thread_6_and_7_entry(ULONG thread_input);
68 void    my_stack_error_handler(TX_THREAD *thread_ptr);
69 void    my_timer_function(ULONG timer_input);
70 
71 
72 /* Define main entry point.  */
73 
main()74 void main()
75 {
76     /* Setup the hardware. */
77     hardware_setup();
78 
79     /* Enter the ThreadX kernel.  */
80     tx_kernel_enter();
81 }
82 
83 
84 /* Define what the initial system looks like.  */
85 
tx_application_define(void * first_unused_memory)86 void    tx_application_define(void *first_unused_memory)
87 {
88 
89 CHAR    *pointer = TX_NULL;
90 UINT    status;
91 
92 	/* Enable event tracing using the global �trace_buffer� memory and supporting
93    	   a maximum of TRACE_OBJECTS_COUNT ThreadX objects in the registry.  */
94 	if ((status = tx_trace_enable(tx_trace_buffer, TRACE_BUFFER_SIZE, TRACE_OBJECTS_COUNT)) != TX_SUCCESS)
95 	{
96 		while (1);
97 	}
98 
99 	/* Register thread stack error notification callback */
100 	if ((status = tx_thread_stack_error_notify(my_stack_error_handler)) != TX_SUCCESS)
101 	{
102 		while (1);
103 	}
104 
105     /* Create a byte memory pool from which to allocate the thread stacks.  */
106 	status = tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
107 	if (status != TX_SUCCESS)
108 	{
109 		while (1);
110 	}
111 
112     /* Put system definition stuff in here, e.g. thread creates and other assorted
113        create information.  */
114 
115     /* Allocate the stack for thread 0.  */
116 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
117 	if (status != TX_SUCCESS)
118 	{
119 		while (1);
120 	}
121 
122     /* Create the main thread.  */
123 	status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
124             pointer, DEMO_STACK_SIZE,
125             1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
126 	if (status != TX_SUCCESS)
127 	{
128 		while (1);
129 	}
130 
131     /* Allocate the stack for thread 1.  */
132 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
133 	if (status != TX_SUCCESS)
134 	{
135 		while (1);
136 	}
137 
138     /* Create threads 1 and 2. These threads pass information through a ThreadX
139        message queue.  It is also interesting to note that these threads have a time
140        slice.  */
141 	status = tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
142             pointer, DEMO_STACK_SIZE,
143             16, 16, 4, TX_AUTO_START);
144 	if (status != TX_SUCCESS)
145 	{
146 		while (1);
147 	}
148 
149     /* Allocate the stack for thread 2.  */
150 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
151 	if (status != TX_SUCCESS)
152 	{
153 		while (1);
154 	}
155 
156 	status = tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
157             pointer, DEMO_STACK_SIZE,
158             16, 16, 4, TX_AUTO_START);
159 	if (status != TX_SUCCESS)
160 	{
161 		while (1);
162 	}
163 
164     /* Allocate the stack for thread 3.  */
165 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
166 	if (status != TX_SUCCESS)
167 	{
168 		while (1);
169 	}
170 
171     /* Create threads 3 and 4.  These threads compete for a ThreadX counting semaphore.
172        An interesting thing here is that both threads share the same instruction area.  */
173 	status = tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
174             pointer, DEMO_STACK_SIZE,
175             8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
176 	if (status != TX_SUCCESS)
177 	{
178 		while (1);
179 	}
180 
181     /* Allocate the stack for thread 4.  */
182 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
183 	if (status != TX_SUCCESS)
184 	{
185 		while (1);
186 	}
187 
188 	status = tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
189             pointer, DEMO_STACK_SIZE,
190             8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
191 	if (status != TX_SUCCESS)
192 	{
193 		while (1);
194 	}
195 
196     /* Allocate the stack for thread 5.  */
197 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
198 	if (status != TX_SUCCESS)
199 	{
200 		while (1);
201 	}
202 
203     /* Create thread 5.  This thread simply pends on an event flag which will be set
204        by thread_0.  */
205 	status = tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
206             pointer, DEMO_STACK_SIZE,
207             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
208 	if (status != TX_SUCCESS)
209 	{
210 		while (1);
211 	}
212 
213     /* Allocate the stack for thread 6.  */
214 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
215 	if (status != TX_SUCCESS)
216 	{
217 		while (1);
218 	}
219 
220     /* Create threads 6 and 7.  These threads compete for a ThreadX mutex.  */
221 	status = tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
222             pointer, DEMO_STACK_SIZE,
223             8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
224 	if (status != TX_SUCCESS)
225 	{
226 		while (1);
227 	}
228 
229     /* Allocate the stack for thread 7.  */
230 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
231 	if (status != TX_SUCCESS)
232 	{
233 		while (1);
234 	}
235 
236 	status = tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
237             pointer, DEMO_STACK_SIZE,
238             8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
239 	if (status != TX_SUCCESS)
240 	{
241 		while (1);
242 	}
243 
244     /* Allocate the message queue.  */
245 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
246 	if (status != TX_SUCCESS)
247 	{
248 		while (1);
249 	}
250 
251     /* Create the message queue shared by threads 1 and 2.  */
252 	status = tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
253 	if (status != TX_SUCCESS)
254 	{
255 		while (1);
256 	}
257 
258     /* Create the semaphore used by threads 3 and 4.  */
259 	status = tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
260 	if (status != TX_SUCCESS)
261 	{
262 		while (1);
263 	}
264 
265     /* Create the event flags group used by threads 1 and 5.  */
266 	status = tx_event_flags_create(&event_flags_0, "event flags 0");
267 	if (status != TX_SUCCESS)
268 	{
269 		while (1);
270 	}
271 
272     /* Create the mutex used by thread 6 and 7 without priority inheritance.  */
273 	status = tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
274 	if (status != TX_SUCCESS)
275 	{
276 		while (1);
277 	}
278 
279     /* Allocate the memory for a small block pool.  */
280 	status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
281 	if (status != TX_SUCCESS)
282 	{
283 		while (1);
284 	}
285 
286     /* Create a block memory pool to allocate a message buffer from.  */
287 	status = tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
288 	if (status != TX_SUCCESS)
289 	{
290 		while (1);
291 	}
292 
293     /* Allocate a block and release the block memory.  */
294 	status = tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
295 	if (status != TX_SUCCESS)
296 	{
297 		while (1);
298 	}
299 
300     /* Release the block back to the pool.  */
301 	status = tx_block_release(pointer);
302 	if (status != TX_SUCCESS)
303 	{
304 		while (1);
305 	}
306 
307     /* Create the periodic timer. */
308 	status = tx_timer_create(&timer_0, "timer 0", my_timer_function, (ULONG) DEMO_TIMER_VALUE, DEMO_TIMER_PERIOD, DEMO_TIMER_PERIOD, TX_AUTO_ACTIVATE);
309 	if (status != TX_SUCCESS)
310 	{
311 		while (1);
312 	}
313 }
314 
315 
316 
317 /* Define the test threads.  */
318 
thread_0_entry(ULONG thread_input)319 void    thread_0_entry(ULONG thread_input)
320 {
321 
322 UINT    status;
323 
324 
325     /* This thread simply sits in while-forever-sleep loop.  */
326     while(1)
327     {
328 
329         /* Increment the thread counter.  */
330         thread_0_counter++;
331 
332         /* Sleep for 10 ticks.  */
333         tx_thread_sleep(10);
334 
335         /* Set event flag 0 to wakeup thread 5.  */
336         status =  tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
337 
338         /* Check status.  */
339         if (status != TX_SUCCESS)
340             break;
341     }
342 }
343 
344 
thread_1_entry(ULONG thread_input)345 void    thread_1_entry(ULONG thread_input)
346 {
347 
348 UINT    status;
349 
350 
351     /* This thread simply sends messages to a queue shared by thread 2.  */
352     while(1)
353     {
354 
355         /* Increment the thread counter.  */
356         thread_1_counter++;
357 
358         /* Send message to queue 0.  */
359         status =  tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
360 
361         /* Check completion status.  */
362         if (status != TX_SUCCESS)
363             break;
364 
365         /* Increment the message sent.  */
366         thread_1_messages_sent++;
367     }
368 }
369 
370 
thread_2_entry(ULONG thread_input)371 void    thread_2_entry(ULONG thread_input)
372 {
373 
374 ULONG   received_message;
375 UINT    status;
376 
377     /* This thread retrieves messages placed on the queue by thread 1.  */
378     while(1)
379     {
380 
381         /* Increment the thread counter.  */
382         thread_2_counter++;
383 
384         /* Retrieve a message from the queue.  */
385         status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
386 
387         /* Check completion status and make sure the message is what we
388            expected.  */
389         if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
390             break;
391 
392         /* Otherwise, all is okay.  Increment the received message count.  */
393         thread_2_messages_received++;
394     }
395 }
396 
397 
thread_3_and_4_entry(ULONG thread_input)398 void    thread_3_and_4_entry(ULONG thread_input)
399 {
400 
401 UINT    status;
402 
403 
404     /* This function is executed from thread 3 and thread 4.  As the loop
405        below shows, these function compete for ownership of semaphore_0.  */
406     while(1)
407     {
408 
409         /* Increment the thread counter.  */
410         if (thread_input == 3)
411             thread_3_counter++;
412         else
413             thread_4_counter++;
414 
415         /* Get the semaphore with suspension.  */
416         status =  tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
417 
418         /* Check status.  */
419         if (status != TX_SUCCESS)
420             break;
421 
422         /* Sleep for 2 ticks to hold the semaphore.  */
423         tx_thread_sleep(2);
424 
425         /* Release the semaphore.  */
426         status =  tx_semaphore_put(&semaphore_0);
427 
428         /* Check status.  */
429         if (status != TX_SUCCESS)
430             break;
431     }
432 }
433 
434 
thread_5_entry(ULONG thread_input)435 void    thread_5_entry(ULONG thread_input)
436 {
437 
438 UINT    status;
439 ULONG   actual_flags;
440 
441 
442     /* This thread simply waits for an event in a forever loop.  */
443     while(1)
444     {
445 
446         /* Increment the thread counter.  */
447         thread_5_counter++;
448 
449         /* Wait for event flag 0.  */
450         status =  tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
451                                                 &actual_flags, TX_WAIT_FOREVER);
452 
453         /* Check status.  */
454         if ((status != TX_SUCCESS) || (actual_flags != 0x1))
455             break;
456     }
457 }
458 
459 
thread_6_and_7_entry(ULONG thread_input)460 void    thread_6_and_7_entry(ULONG thread_input)
461 {
462 
463 UINT    status;
464 
465 
466     /* This function is executed from thread 6 and thread 7.  As the loop
467        below shows, these function compete for ownership of mutex_0.  */
468     while(1)
469     {
470 
471         /* Increment the thread counter.  */
472         if (thread_input == 6)
473             thread_6_counter++;
474         else
475             thread_7_counter++;
476 
477         /* Get the mutex with suspension.  */
478         status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
479 
480         /* Check status.  */
481         if (status != TX_SUCCESS)
482             break;
483 
484         /* Get the mutex again with suspension.  This shows
485            that an owning thread may retrieve the mutex it
486            owns multiple times.  */
487         status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
488 
489         /* Check status.  */
490         if (status != TX_SUCCESS)
491             break;
492 
493         /* Sleep for 2 ticks to hold the mutex.  */
494         tx_thread_sleep(2);
495 
496         /* Release the mutex.  */
497         status =  tx_mutex_put(&mutex_0);
498 
499         /* Check status.  */
500         if (status != TX_SUCCESS)
501             break;
502 
503         /* Release the mutex again.  This will actually
504            release ownership since it was obtained twice.  */
505         status =  tx_mutex_put(&mutex_0);
506 
507         /* Check status.  */
508         if (status != TX_SUCCESS)
509             break;
510     }
511 }
512 
513 
my_stack_error_handler(TX_THREAD * thread_ptr)514 void my_stack_error_handler(TX_THREAD *thread_ptr)
515 {
516     while(1);
517 }
518 
519 
my_timer_function(ULONG timer_input)520 void my_timer_function(ULONG timer_input)
521 {
522     /* Increment the thread counter.  */
523     timer_0_counter++;
524 
525     if (timer_input != DEMO_TIMER_VALUE)
526         while(1);
527 }
528 
529