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 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   System Management (System)                                          */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 //#define GX_SOURCE_CODE
22 
23 /* Include necessary system files.  */
24 
25 #include "gx_api.h"
26 #include "gx_system.h"
27 #include "gx_system_rtos_bind.h"
28 
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _gx_system_rtos_bind                                PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Kenneth Maxwell, Microsoft Corporation                              */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This file contains a small set of shell functions used to bind GUIX */
43 /*    to a generic RTOS. GUIX is by default configured to run with the    */
44 /*    ThreadX RTOS, but you can port to another RTOS by defining the      */
45 /*    pre-processor directive GX_DISABLE_THREADX_BINDING and completing   */
46 /*    the implementation of the functions found in this file.             */
47 /*    Refer to the GUIX User Guide for more information.                  */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    Refer to GUIX User Guide                                            */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    Refer to GUIX User Guide                                            */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    Refer to GUIX User Guide                                            */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    GUIX system serives                                                 */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
70 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
71 /*                                            resulting in version 6.1    */
72 /*                                                                        */
73 /**************************************************************************/
74 
75 #ifndef GX_THREADX_BINDING
76 
77 /* This is an example of a generic RTOS binding. We have #ifdefed this code out
78    of the GUIX library build, so that the user attempting to port to a new RTOS
79    will intentionally observe a series of linker errors. These functions need to
80    be implemented in a way that works correctly with the target RTOS.
81 */
82 
83 #if defined(GUIX_BINDING_UCOS_III)
84 
85 #include "os.h"
86 
87 #ifndef OS_CFG_TICK_RATE_HZ
88 #define OS_CFG_TICK_RATE_HZ 100
89 #endif
90 
91 #define GX_TIMER_TASK_PRIORITY   (GX_SYSTEM_THREAD_PRIORITY + 1)
92 #define GX_TIMER_TASK_STACK_SIZE 512
93 void guix_timer_task_entry(void *);
94 
95 /* a few global status variables */
96 GX_BOOL guix_timer_event_pending;
97 
98 /* define stack space for GUIX task */
99 CPU_STK guix_task_stack[GX_THREAD_STACK_SIZE];
100 
101 /* define stack space for timer task */
102 CPU_STK guix_timer_task_stack[GX_TIMER_TASK_STACK_SIZE];
103 
104 /* define semaphore for lock/unlock macros */
105 OS_MUTEX guix_system_lock_mutex;
106 
107 OS_ERR uc_error;
108 OS_TCB guix_tcb;
109 OS_TCB guix_timer_tcb;
110 
111 /* a custom event structure, to hold event and linked list */
112 
113 typedef struct guix_linked_event_struct
114 {
115     GX_EVENT                         event_data;        /* the GUIX event structure */
116     struct guix_linked_event_struct *next;              /* add link member          */
117 } GUIX_LINKED_EVENT;
118 
119 
120 /* a custom fifo event queue structure */
121 
122 typedef struct guix_event_queue_struct
123 {
124     GUIX_LINKED_EVENT *first;           /* first (oldest) event in fifo */
125     GUIX_LINKED_EVENT *last;            /* last (newest) event in fifo  */
126     GUIX_LINKED_EVENT *free;            /* linked list of free events   */
127     GUIX_LINKED_EVENT *free_end;        /* end of the free list         */
128     OS_SEM             count_sem;       /* number of queued events      */
129     OS_MUTEX           lock;            /* lock to protect queue update */
130 } GUIX_EVENT_QUEUE;
131 
132 /* an array of GX_EVENTs used to implement fifo queue */
133 
134 GUIX_LINKED_EVENT guix_event_array[GX_MAX_QUEUE_EVENTS];
135 GUIX_EVENT_QUEUE  guix_event_queue;
136 
137 /* rtos initialize: perform any setup that needs to be done before the GUIX task runs here */
gx_generic_rtos_initialize(VOID)138 VOID   gx_generic_rtos_initialize(VOID)
139 {
140 int Loop;
141 GUIX_LINKED_EVENT *current;
142 
143     guix_timer_event_pending = GX_FALSE;
144     OSMutexCreate(&guix_system_lock_mutex, "gx_system_lock", &uc_error);
145 
146     /* initialize a custom fifo queue structure */
147 
148     guix_event_queue.first = GX_NULL;
149     guix_event_queue.last = GX_NULL;
150     guix_event_queue.free = guix_event_array;
151 
152     current = guix_event_queue.free;
153 
154     /* link all the structures together */
155     for (Loop = 0; Loop < GX_MAX_QUEUE_EVENTS - 1; Loop++)
156     {
157         current -> next = (current + 1);
158         current = current -> next;
159     }
160     current -> next = GX_NULL;                /* terminate the list */
161     guix_event_queue.free_end = current;
162 
163     /* create mutex for lock access to this queue */
164     OSMutexCreate(&guix_event_queue.lock, "gx_queue_lock", &uc_error);
165 
166     /* create counting semaphore to track queue entries */
167     OSSemCreate(&guix_event_queue.count_sem, "gx_queue_count", 0, &uc_error);
168 }
169 
170 VOID (*gx_system_thread_entry)(ULONG);
171 
172 // A small shell function to convert the void * arg expected by uC/OS to
173 // a ULONG parameter expected by GUIX thread entry
gx_system_thread_entry_shell(void * parg)174 void gx_system_thread_entry_shell(void *parg)
175 {
176     gx_system_thread_entry((ULONG) parg);
177 }
178 
179 /* thread_start: start the GUIX thread running. */
gx_generic_thread_start(VOID (* guix_thread_entry)(ULONG))180 UINT   gx_generic_thread_start(VOID(*guix_thread_entry)(ULONG))
181 {
182 
183     /* save the GUIX system thread entry function pointer */
184     gx_system_thread_entry = guix_thread_entry;
185 
186     /* create the main GUIX task */
187 
188     OSTaskCreate(&guix_tcb, "guix_task",
189                  gx_system_thread_entry_shell,
190                  GX_NULL,
191                  GX_SYSTEM_THREAD_PRIORITY,
192                  &guix_task_stack[0],
193                  GX_THREAD_STACK_SIZE - 1,
194                  GX_THREAD_STACK_SIZE,
195                  0, 0, GX_NULL, OS_OPT_TASK_NONE, &uc_error);
196 
197     /* create a simple task to generate timer events into GUIX */
198     OSTaskCreate(&guix_timer_tcb, "guix_timer_task",
199                  guix_timer_task_entry,
200                  GX_NULL,
201                  GX_TIMER_TASK_PRIORITY,
202                  &guix_timer_task_stack[0],
203                  GX_TIMER_TASK_STACK_SIZE -1,
204                  GX_TIMER_TASK_STACK_SIZE,
205                  0, 0, GX_NULL, OS_OPT_TASK_NONE, &uc_error);
206 
207     /* suspend the timer task until needed */
208     OSTaskSuspend(&guix_timer_tcb, &uc_error);
209     return GX_SUCCESS;
210 }
211 
212 /* event_post: push an event into the fifo event queue */
gx_generic_event_post(GX_EVENT * event_ptr)213 UINT   gx_generic_event_post(GX_EVENT *event_ptr)
214 {
215 GUIX_LINKED_EVENT *linked_event;
216 
217     /* lock down the guix event queue */
218     OSMutexPend(&guix_event_queue.lock, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
219 
220     /* grab a free event slot */
221     if (!guix_event_queue.free)
222     {
223         /* there are no free events, return failure */
224         OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
225         return GX_FAILURE;
226     }
227 
228     linked_event = guix_event_queue.free;
229     guix_event_queue.free = guix_event_queue.free->next;
230 
231     if (!guix_event_queue.free)
232     {
233         guix_event_queue.free_end = GX_NULL;
234     }
235 
236     /* copy the event data into this slot */
237     linked_event -> event_data = *event_ptr;
238     linked_event -> next = GX_NULL;
239 
240     /* insert this event into fifo queue */
241     if (guix_event_queue.last)
242     {
243         guix_event_queue.last -> next = linked_event;
244     }
245     else
246     {
247         guix_event_queue.first = linked_event;
248     }
249     guix_event_queue.last = linked_event;
250 
251     /* Unlock the guix queue */
252     OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
253 
254     /* increment event count */
255     OSSemPost(&guix_event_queue.count_sem, OS_OPT_POST_ALL, &uc_error);
256     return GX_SUCCESS;
257 }
258 
259 /* event_fold: update existing matching event, otherwise post new event */
gx_generic_event_fold(GX_EVENT * event_ptr)260 UINT   gx_generic_event_fold(GX_EVENT *event_ptr)
261 {
262 GUIX_LINKED_EVENT *pTest;
263 
264     /* Lock down the guix queue */
265 
266     OSMutexPend(&guix_event_queue.lock, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
267 
268     // see if the same event is already in the queue:
269     pTest = guix_event_queue.first;
270 
271     while (pTest)
272     {
273         if (pTest -> event_data.gx_event_type == event_ptr -> gx_event_type)
274         {
275             /* found matching event, update it and return */
276             pTest -> event_data.gx_event_payload.gx_event_ulongdata = event_ptr -> gx_event_payload.gx_event_ulongdata;
277             OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
278             return GX_SUCCESS;
279         }
280         pTest = pTest -> next;
281     }
282 
283     /* did not find a match, push new event */
284 
285     OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
286     gx_generic_event_post(event_ptr);
287     return GX_SUCCESS;
288 }
289 
290 
291 /* event_pop: pop oldest event from fifo queue, block if wait and no events exist */
gx_generic_event_pop(GX_EVENT * put_event,GX_BOOL wait)292 UINT   gx_generic_event_pop(GX_EVENT *put_event, GX_BOOL wait)
293 {
294     if (!wait)
295     {
296         if (guix_event_queue.first == GX_NULL)
297         {
298             /* the queue is empty, just return */
299             return GX_FAILURE;
300         }
301     }
302 
303     /* wait for an event to arrive in queue */
304     OSSemPend(&guix_event_queue.count_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
305 
306     /* lock down the queue */
307     OSMutexPend(&guix_event_queue.lock, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
308 
309     /* copy the event into destination */
310     *put_event = guix_event_queue.first -> event_data;
311 
312     /* link this event holder back into free list */
313     if (guix_event_queue.free_end)
314     {
315         guix_event_queue.free_end -> next = guix_event_queue.first;
316     }
317     else
318     {
319         guix_event_queue.free = guix_event_queue.first;
320     }
321 
322     guix_event_queue.free_end = guix_event_queue.first;
323     guix_event_queue.first = guix_event_queue.first -> next;
324     guix_event_queue.free_end -> next = GX_NULL;
325 
326     if (!guix_event_queue.first)
327     {
328         guix_event_queue.last = GX_NULL;
329     }
330 
331     /* check for popping out a timer event */
332     if (put_event -> gx_event_type == GX_EVENT_TIMER)
333     {
334         guix_timer_event_pending = GX_FALSE;
335     }
336 
337     /* unlock the queue */
338     OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
339     return GX_SUCCESS;
340 }
341 
342 /* event_purge: delete events targetted to particular widget */
gx_generic_event_purge(GX_WIDGET * target)343 VOID   gx_generic_event_purge(GX_WIDGET *target)
344 {
345 GX_BOOL Purge;
346 GUIX_LINKED_EVENT *pTest;
347 
348     /* Lock down the guix queue */
349 
350     OSMutexPend(&guix_event_queue.lock, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
351 
352     // look for events targetted to widget or widget children:
353     pTest = guix_event_queue.first;
354 
355     while (pTest)
356     {
357         Purge = GX_FALSE;
358 
359         if (pTest ->event_data.gx_event_target)
360         {
361             if (pTest -> event_data.gx_event_target == target)
362             {
363                 Purge = GX_TRUE;
364             }
365             else
366             {
367                 gx_widget_child_detect(target, pTest->event_data.gx_event_target, &Purge);
368             }
369             if (Purge)
370             {
371                 pTest ->event_data.gx_event_target = GX_NULL;
372                 pTest->event_data.gx_event_type = 0;
373             }
374         }
375         pTest = pTest -> next;
376     }
377 
378     OSMutexPost(&guix_event_queue.lock, OS_OPT_POST_NONE, &uc_error);
379 }
380 
381 /* start the RTOS timer */
gx_generic_timer_start(VOID)382 VOID   gx_generic_timer_start(VOID)
383 {
384     OSTaskResume(&guix_timer_tcb, &uc_error);
385 }
386 
387 /* stop the RTOS timer */
gx_generic_timer_stop(VOID)388 VOID   gx_generic_timer_stop(VOID)
389 {
390     OSTaskSuspend(&guix_timer_tcb, &uc_error);
391 }
392 
393 /* lock the system protection mutex */
gx_generic_system_mutex_lock(VOID)394 VOID   gx_generic_system_mutex_lock(VOID)
395 {
396     OSMutexPend(&guix_system_lock_mutex, 0, OS_OPT_PEND_BLOCKING, NULL, &uc_error);
397 
398 }
399 
400 /* unlock system protection mutex */
gx_generic_system_mutex_unlock(VOID)401 VOID   gx_generic_system_mutex_unlock(VOID)
402 {
403     OSMutexPost(&guix_system_lock_mutex, OS_OPT_POST_NONE, &uc_error);
404 }
405 
406 /* return number of low-level system timer ticks. Used for pen speed caculations */
gx_generic_system_time_get(VOID)407 ULONG  gx_generic_system_time_get(VOID)
408 {
409     return((ULONG)OSTimeGet(&uc_error));
410 }
411 
412 /* thread_identify: return current thread identifier, cast as VOID * */
gx_generic_thread_identify(VOID)413 VOID  *gx_generic_thread_identify(VOID)
414 {
415     return((VOID *)OSTCBCurPtr);
416 }
417 
418 /* a simple task to drive the GUIX timer mechanism */
guix_timer_task_entry(void * unused)419 void guix_timer_task_entry(void *unused)
420 {
421 int TickCount = OS_CFG_TICK_RATE_HZ / GX_TICKS_SECOND;
422 
423     if (TickCount <= 0)
424     {
425         TickCount = 1;
426     }
427 
428     while (1)
429     {
430         OSTimeDly(TickCount, OS_OPT_TIME_DLY, &uc_error);
431 
432         /* prevent sending timer events faster than they can be processed */
433         if (!guix_timer_event_pending)
434         {
435             guix_timer_event_pending = GX_TRUE;
436             _gx_system_timer_expiration(0);
437         }
438     }
439 }
440 
gx_generic_time_delay(int ticks)441 VOID gx_generic_time_delay(int ticks)
442 {
443     OSTimeDly(ticks, OS_OPT_TIME_DLY, &uc_error);
444 }
445 
446 
447 #endif  /* Binding for UCOS-III enabled */
448 
449 #if defined(GUIX_BINDING_UCOS_II)
450 
451 #include "ucos_ii.h"
452 
453 #define TIMER_TASK_PRIORITY   (GX_SYSTEM_THREAD_PRIORITY + 1)
454 #define TIMER_TASK_STACK_SIZE 512
455 void guix_timer_task_entry(void *);
456 
457 /* a few global status variables */
458 GX_BOOL guix_timer_event_pending;
459 INT8U   guix_uc_err = 0;
460 
461 /* define stack space for GUIX task */
462 OS_STK guix_task_stack[GX_THREAD_STACK_SIZE];
463 OS_STK guix_task_stack[GX_THREAD_STACK_SIZE];
464 
465 /* define stack space for timer task */
466 OS_STK guix_timer_task_stack[TIMER_TASK_STACK_SIZE];
467 
468 /* define semaphore for lock/unlock macros */
469 OS_EVENT *guix_system_lock_semaphore;
470 
471 /* a custom event structure, to hold event and linked list */
472 
473 typedef struct guix_linked_event_struct
474 {
475     GX_EVENT                         event_data;        /* the GUIX event structure */
476     struct guix_linked_event_struct *next;              /* add link member          */
477 } GUIX_LINKED_EVENT;
478 
479 
480 /* a custom fifo event queue structure */
481 
482 typedef struct guix_event_queue_struct
483 {
484     GUIX_LINKED_EVENT *first;           /* first (oldest) event in fifo */
485     GUIX_LINKED_EVENT *last;            /* last (newest) event in fifo  */
486     GUIX_LINKED_EVENT *free;            /* linked list of free events   */
487     GUIX_LINKED_EVENT *free_end;        /* end of the free list         */
488     OS_EVENT          *count_sem;       /* number of queued events      */
489     OS_EVENT          *lock_sem;        /* lock to protect queue update */
490 } GUIX_EVENT_QUEUE;
491 
492 /* an array of GX_EVENTs used to implement fifo queue */
493 
494 GUIX_LINKED_EVENT guix_event_array[GX_MAX_QUEUE_EVENTS];
495 GUIX_EVENT_QUEUE  guix_event_queue;
496 
497 /* rtos initialize: perform any setup that needs to be done before the GUIX task runs here */
gx_generic_rtos_initialize(VOID)498 VOID   gx_generic_rtos_initialize(VOID)
499 {
500 int Loop;
501 GUIX_LINKED_EVENT *current;
502 
503     guix_timer_event_pending = GX_FALSE;
504     guix_system_lock_semaphore = OSSemCreate(1);
505 
506     /* initialize a custom fifo queue structure */
507 
508     guix_event_queue.first = GX_NULL;
509     guix_event_queue.last = GX_NULL;
510     guix_event_queue.free = guix_event_array;
511 
512     current = guix_event_queue.free;
513 
514     /* link all the structures together */
515     for (Loop = 0; Loop < GX_MAX_QUEUE_EVENTS - 1; Loop++)
516     {
517         current -> next = (current + 1);
518         current = current -> next;
519     }
520     current -> next = GX_NULL;                /* terminate the list */
521     guix_event_queue.free_end = current;
522 
523     /* create mutex for lock access to this queue */
524     guix_event_queue.lock_sem = OSSemCreate(1);
525 
526     /* create counting semaphore to track queue entries */
527     guix_event_queue.count_sem = OSSemCreate(0);
528 }
529 
530 /* A variable to store GUIX thread entry function pointer */
531 VOID (*gx_thread_entry)(ULONG);
532 
533 /* a simple shell function to convert the UCOS (void *)
534    parameter to the GUIX ULONG param type. */
guix_thread_entry_shell(void * ptr)535 void guix_thread_entry_shell(void *ptr)
536 {
537     gx_thread_entry((ULONG) ptr);
538 }
539 
540 /* thread_start: start the GUIX thread running. */
gx_generic_thread_start(VOID (* guix_thread_entry)(ULONG))541 UINT   gx_generic_thread_start(VOID(*guix_thread_entry)(ULONG))
542 {
543     /* save pointer to GUIX thread entry function */
544     gx_thread_entry = guix_thread_entry;
545 
546     /* create the main GUIX task */
547     OSTaskCreate(guix_thread_entry_shell, (void *)0,
548                  &guix_task_stack[GX_THREAD_STACK_SIZE - 1], GX_SYSTEM_THREAD_PRIORITY);
549 
550     /* create a simple task to generate timer events into GUIX */
551     OSTaskCreate(guix_timer_task_entry, (void *)0,
552                  &guix_timer_task_stack[TIMER_TASK_STACK_SIZE - 1], TIMER_TASK_PRIORITY);
553 
554     /* suspend the timer task until needed */
555     OSTaskSuspend(TIMER_TASK_PRIORITY);
556     return GX_SUCCESS;
557 }
558 
559 /* event_post: push an event into the fifo event queue */
gx_generic_event_post(GX_EVENT * event_ptr)560 UINT   gx_generic_event_post(GX_EVENT *event_ptr)
561 {
562 GUIX_LINKED_EVENT *linked_event;
563 
564     /* lock down the guix event queue */
565     OSSemPend(guix_event_queue.lock_sem, 0, &guix_uc_err);
566 
567     /* grab a free event slot */
568     if (!guix_event_queue.free)
569     {
570         /* there are no free events, return failure */
571         OSSemPost(guix_event_queue.lock_sem);
572         return GX_FAILURE;
573     }
574 
575     linked_event = guix_event_queue.free;
576     guix_event_queue.free = guix_event_queue.free->next;
577 
578     if (!guix_event_queue.free)
579     {
580         guix_event_queue.free_end = GX_NULL;
581     }
582 
583     /* copy the event data into this slot */
584     linked_event -> event_data = *event_ptr;
585     linked_event -> next = GX_NULL;
586 
587     /* insert this event into fifo queue */
588     if (guix_event_queue.last)
589     {
590         guix_event_queue.last -> next = linked_event;
591     }
592     else
593     {
594         guix_event_queue.first = linked_event;
595     }
596     guix_event_queue.last = linked_event;
597 
598     /* Unlock the guix queue */
599     OSSemPost(guix_event_queue.lock_sem);
600 
601     /* increment event count */
602     OSSemPost(guix_event_queue.count_sem);
603     return GX_SUCCESS;
604 }
605 
606 /* event_fold: update existing matching event, otherwise post new event */
gx_generic_event_fold(GX_EVENT * event_ptr)607 UINT   gx_generic_event_fold(GX_EVENT *event_ptr)
608 {
609 GUIX_LINKED_EVENT *pTest;
610 
611     /* Lock down the guix queue */
612 
613     OSSemPend(guix_event_queue.lock_sem, 0, &guix_uc_err);
614 
615     // see if the same event is already in the queue:
616     pTest = guix_event_queue.first;
617 
618     while (pTest)
619     {
620         if (pTest -> event_data.gx_event_type == event_ptr -> gx_event_type)
621         {
622             /* found matching event, update it and return */
623             pTest -> event_data.gx_event_payload.gx_event_ulongdata = event_ptr -> gx_event_payload.gx_event_ulongdata;
624             OSSemPost(guix_event_queue.lock_sem);
625             return GX_SUCCESS;
626         }
627         pTest = pTest -> next;
628     }
629 
630     /* did not find a match, push new event */
631 
632     OSSemPost(guix_event_queue.lock_sem);
633     gx_generic_event_post(event_ptr);
634     return GX_SUCCESS;
635 }
636 
637 
638 /* event_pop: pop oldest event from fifo queue, block if wait and no events exist */
gx_generic_event_pop(GX_EVENT * put_event,GX_BOOL wait)639 UINT   gx_generic_event_pop(GX_EVENT *put_event, GX_BOOL wait)
640 {
641     if (!wait)
642     {
643         if (guix_event_queue.first == GX_NULL)
644         {
645             /* the queue is empty, just return */
646             OSSemPost(guix_event_queue.lock_sem);
647             return GX_FAILURE;
648         }
649     }
650 
651     /* wait for an event to arrive in queue */
652     OSSemPend(guix_event_queue.count_sem, 0, &guix_uc_err);
653 
654     /* lock down the queue */
655     OSSemPend(guix_event_queue.lock_sem, 0, &guix_uc_err);
656 
657     /* copy the event into destination */
658     *put_event = guix_event_queue.first -> event_data;
659 
660     /* link this event holder back into free list */
661     if (guix_event_queue.free_end)
662     {
663         guix_event_queue.free_end -> next = guix_event_queue.first;
664     }
665     else
666     {
667         guix_event_queue.free = guix_event_queue.first;
668     }
669 
670     guix_event_queue.free_end = guix_event_queue.first;
671     guix_event_queue.first = guix_event_queue.first -> next;
672     guix_event_queue.free_end -> next = GX_NULL;
673 
674     if (!guix_event_queue.first)
675     {
676         guix_event_queue.last = GX_NULL;
677     }
678 
679     /* check for popping out a timer event */
680     if (put_event -> gx_event_type == GX_EVENT_TIMER)
681     {
682         guix_timer_event_pending = GX_FALSE;
683     }
684 
685     /* unlock the queue */
686     OSSemPost(guix_event_queue.lock_sem);
687     return GX_SUCCESS;
688 }
689 
690 /* event_purge: delete events targetted to particular widget */
gx_generic_event_purge(GX_WIDGET * target)691 VOID   gx_generic_event_purge(GX_WIDGET *target)
692 {
693 GX_BOOL Purge;
694 GUIX_LINKED_EVENT *pTest;
695 
696     /* Lock down the guix queue */
697 
698     OSSemPend(guix_event_queue.lock_sem, 0, &guix_uc_err);
699 
700     // look for events targetted to widget or widget children:
701     pTest = guix_event_queue.first;
702 
703     while (pTest)
704     {
705         Purge = GX_FALSE;
706 
707         if (pTest ->event_data.gx_event_target)
708         {
709             if (pTest -> event_data.gx_event_target == target)
710             {
711                 Purge = GX_TRUE;
712             }
713             else
714             {
715                 gx_widget_child_detect(target, pTest->event_data.gx_event_target, &Purge);
716             }
717             if (Purge)
718             {
719                 pTest ->event_data.gx_event_target = GX_NULL;
720                 pTest->event_data.gx_event_type = 0;
721             }
722         }
723         pTest = pTest -> next;
724     }
725 
726     OSSemPost(guix_event_queue.lock_sem);
727 }
728 
729 /* start the RTOS timer */
gx_generic_timer_start(VOID)730 VOID   gx_generic_timer_start(VOID)
731 {
732     OSTaskResume(TIMER_TASK_PRIORITY);
733 }
734 
735 /* stop the RTOS timer */
gx_generic_timer_stop(VOID)736 VOID   gx_generic_timer_stop(VOID)
737 {
738     OSTaskSuspend(TIMER_TASK_PRIORITY);
739 }
740 
741 /* lock the system protection mutex */
gx_generic_system_mutex_lock(VOID)742 VOID   gx_generic_system_mutex_lock(VOID)
743 {
744     OSSemPend(guix_system_lock_semaphore, 0, &guix_uc_err);
745 }
746 
747 /* unlock system protection mutex */
gx_generic_system_mutex_unlock(VOID)748 VOID   gx_generic_system_mutex_unlock(VOID)
749 {
750     OSSemPost(guix_system_lock_semaphore);
751 }
752 
753 /* return number of low-level system timer ticks. Used for pen speed caculations */
gx_generic_system_time_get(VOID)754 ULONG  gx_generic_system_time_get(VOID)
755 {
756     return((ULONG)OSTimeGet());
757 }
758 
759 /* thread_identify: return current thread identifier, cast as VOID * */
gx_generic_thread_identify(VOID)760 VOID  *gx_generic_thread_identify(VOID)
761 {
762     return((VOID *)OSTCBCur);
763 }
764 
765 /* a simple task to drive the GUIX timer mechanism */
guix_timer_task_entry(VOID * unused)766 VOID guix_timer_task_entry(VOID *unused)
767 {
768 int TickCount = OS_TICKS_PER_SEC / GX_TICKS_SECOND;
769 
770     if (TickCount <= 0)
771     {
772         TickCount = 1;
773     }
774 
775     while (1)
776     {
777         OSTimeDly(TickCount);
778 
779         /* prevent sending timer events faster than they can be processed */
780         if (!guix_timer_event_pending)
781         {
782             guix_timer_event_pending = GX_TRUE;
783             _gx_system_timer_expiration(0);
784         }
785     }
786 }
787 
gx_generic_time_delay(int ticks)788 VOID gx_generic_time_delay(int ticks)
789 {
790     OSTimeDly(ticks);
791 }
792 
793 
794 #endif /* Binding for UCOS-II enabled */
795 
796 #endif  /* if !ThreadX */
797 
798 
799