Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_cleanup.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_cleanup.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_cleanup.c	(revision 67)
@@ -0,0 +1,239 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_thread.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_event_flags_cleanup                             PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function processes event flags timeout and thread terminate    */
+/*    actions that require the event flags data structures to be cleaned  */
+/*    up.                                                                 */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    thread_ptr                        Pointer to suspended thread's     */
+/*                                        control block                   */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    None                                                                */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_system_resume          Resume thread service             */
+/*    _tx_thread_system_ni_resume       Non-interruptable resume thread   */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    _tx_thread_timeout                Thread timeout processing         */
+/*    _tx_thread_terminate              Thread terminate processing       */
+/*    _tx_thread_wait_abort             Thread wait abort processing      */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+VOID  _tx_event_flags_cleanup(TX_THREAD  *thread_ptr, ULONG suspension_sequence)
+{
+
+#ifndef TX_NOT_INTERRUPTABLE
+TX_INTERRUPT_SAVE_AREA
+#endif
+
+TX_EVENT_FLAGS_GROUP        *group_ptr;
+UINT                        suspended_count;
+TX_THREAD                   *suspension_head;
+TX_THREAD                   *next_thread;
+TX_THREAD                   *previous_thread;
+
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+    /* Disable interrupts to remove the suspended thread from the event flags group.  */
+    TX_DISABLE
+
+    /* Determine if the cleanup is still required.  */
+    if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_event_flags_cleanup))
+    {
+
+        /* Check for valid suspension sequence.  */
+        if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
+        {
+
+            /* Setup pointer to event flags control block.  */
+            group_ptr =  TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
+
+            /* Check for a NULL event flags control block pointer.  */
+            if (group_ptr != TX_NULL)
+            {
+
+                /* Is the group pointer ID valid?  */
+                if (group_ptr -> tx_event_flags_group_id == TX_EVENT_FLAGS_ID)
+                {
+
+                    /* Determine if there are any thread suspensions.  */
+                    if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
+                    {
+#else
+
+                        /* Setup pointer to event flags control block.  */
+                        group_ptr =  TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
+#endif
+
+                        /* Yes, we still have thread suspension!  */
+
+                        /* Clear the suspension cleanup flag.  */
+                        thread_ptr -> tx_thread_suspend_cleanup =  TX_NULL;
+
+                        /* Pickup the suspended count.  */
+                        suspended_count =  group_ptr -> tx_event_flags_group_suspended_count;
+
+                        /* Pickup the suspension head.  */
+                        suspension_head =  group_ptr -> tx_event_flags_group_suspension_list;
+
+                        /* Determine if the cleanup is being done while a set operation was interrupted.  If the
+                           suspended count is non-zero and the suspension head is NULL, the list is being processed
+                           and cannot be touched from here. The suspension list removal will instead take place
+                           inside the event flag set code.  */
+                        if (suspension_head != TX_NULL)
+                        {
+
+                            /* Remove the suspended thread from the list.  */
+
+                            /* Decrement the local suspension count.  */
+                            suspended_count--;
+
+                            /* Store the updated suspended count.  */
+                            group_ptr -> tx_event_flags_group_suspended_count =  suspended_count;
+
+                            /* See if this is the only suspended thread on the list.  */
+                            if (suspended_count == TX_NO_SUSPENSIONS)
+                            {
+
+                                /* Yes, the only suspended thread.  */
+
+                                /* Update the head pointer.  */
+                                group_ptr -> tx_event_flags_group_suspension_list =  TX_NULL;
+                            }
+                            else
+                            {
+
+                                /* At least one more thread is on the same suspension list.  */
+
+                                /* Update the links of the adjacent threads.  */
+                                next_thread =                                  thread_ptr -> tx_thread_suspended_next;
+                                previous_thread =                              thread_ptr -> tx_thread_suspended_previous;
+                                next_thread -> tx_thread_suspended_previous =  previous_thread;
+                                previous_thread -> tx_thread_suspended_next =  next_thread;
+
+                                /* Determine if we need to update the head pointer.  */
+                                if (suspension_head == thread_ptr)
+                                {
+
+                                    /* Update the list head pointer.  */
+                                    group_ptr -> tx_event_flags_group_suspension_list =  next_thread;
+                                }
+                            }
+                        }
+                        else
+                        {
+
+                            /* In this case, the search pointer in an interrupted event flag set must be reset.  */
+                            group_ptr -> tx_event_flags_group_reset_search =  TX_TRUE;
+                        }
+
+                        /* Now we need to determine if this cleanup is from a terminate, timeout,
+                           or from a wait abort.  */
+                        if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG)
+                        {
+
+                            /* Timeout condition and the thread still suspended on the event flags group.
+                               Setup return error status and resume the thread.  */
+
+#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
+
+                            /* Increment the total timeouts counter.  */
+                            _tx_event_flags_performance_timeout_count++;
+
+                            /* Increment the number of timeouts on this event flags group.  */
+                            group_ptr -> tx_event_flags_group____performance_timeout_count++;
+#endif
+
+                            /* Setup return status.  */
+                            thread_ptr -> tx_thread_suspend_status =  TX_NO_EVENTS;
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+                            /* Resume the thread!  */
+                            _tx_thread_system_ni_resume(thread_ptr);
+#else
+
+                           /* Temporarily disable preemption.  */
+                            _tx_thread_preempt_disable++;
+
+                            /* Restore interrupts.  */
+                            TX_RESTORE
+
+                            /* Resume the thread!  Check for preemption even though we are executing
+                               from the system timer thread right now which normally executes at the
+                               highest priority.  */
+                            _tx_thread_system_resume(thread_ptr);
+
+                            /* Disable interrupts.  */
+                            TX_DISABLE
+#endif
+                        }
+#ifndef TX_NOT_INTERRUPTABLE
+                    }
+                }
+            }
+        }
+    }
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+#endif
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_create.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_create.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_create.c	(revision 67)
@@ -0,0 +1,143 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_trace.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_event_flags_create                              PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function creates a group of 32 event flags.  All the flags are */
+/*    initially in a cleared state.                                       */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to event flags group      */
+/*                                        control block                   */
+/*    name_ptr                          Pointer to event flags name       */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_SUCCESS                        Successful completion status      */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    None                                                                */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _tx_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+TX_EVENT_FLAGS_GROUP    *next_group;
+TX_EVENT_FLAGS_GROUP    *previous_group;
+
+
+    /* Initialize event flags control block to all zeros.  */
+    TX_MEMSET(group_ptr, 0, (sizeof(TX_EVENT_FLAGS_GROUP)));
+
+    /* Setup the basic event flags group fields.  */
+    group_ptr -> tx_event_flags_group_name =             name_ptr;
+
+    /* Disable interrupts to put the event flags group on the created list.  */
+    TX_DISABLE
+
+    /* Setup the event flags ID to make it valid.  */
+    group_ptr -> tx_event_flags_group_id =  TX_EVENT_FLAGS_ID;
+
+    /* Place the group on the list of created event flag groups.  First,
+       check for an empty list.  */
+    if (_tx_event_flags_created_count == TX_EMPTY)
+    {
+
+        /* The created event flags list is empty.  Add event flag group to empty list.  */
+        _tx_event_flags_created_ptr =                         group_ptr;
+        group_ptr -> tx_event_flags_group_created_next =      group_ptr;
+        group_ptr -> tx_event_flags_group_created_previous =  group_ptr;
+    }
+    else
+    {
+
+        /* This list is not NULL, add to the end of the list.  */
+        next_group =      _tx_event_flags_created_ptr;
+        previous_group =  next_group -> tx_event_flags_group_created_previous;
+
+        /* Place the new event flag group in the list.  */
+        next_group -> tx_event_flags_group_created_previous =  group_ptr;
+        previous_group -> tx_event_flags_group_created_next =  group_ptr;
+
+        /* Setup this group's created links.  */
+        group_ptr -> tx_event_flags_group_created_previous =  previous_group;
+        group_ptr -> tx_event_flags_group_created_next =      next_group;
+    }
+
+    /* Increment the number of created event flag groups.  */
+    _tx_event_flags_created_count++;
+
+    /* Optional event flag group create extended processing.  */
+    TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
+
+    /* If trace is enabled, register this object.  */
+    TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_EVENT_FLAGS, group_ptr, name_ptr, 0, 0)
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_CREATE, group_ptr, TX_POINTER_TO_ULONG_CONVERT(&next_group), 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_EVENT_FLAGS_CREATE_INSERT
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+
+    /* Return TX_SUCCESS.  */
+    return(TX_SUCCESS);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_get.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_get.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_get.c	(revision 67)
@@ -0,0 +1,407 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_trace.h"
+#include "tx_thread.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_event_flags_get                                 PORTABLE C      */
+/*                                                           6.2.0        */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function gets the specified event flags from the group,        */
+/*    according to the get option.  The get option also specifies whether */
+/*    or not the retrieved flags are cleared.                             */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to group control block    */
+/*    requested_event_flags             Event flags requested             */
+/*    get_option                        Specifies and/or and clear options*/
+/*    actual_flags_ptr                  Pointer to place the actual flags */
+/*                                        the service retrieved           */
+/*    wait_option                       Suspension option                 */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    status                            Completion status                 */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_system_suspend         Suspend thread service            */
+/*    _tx_thread_system_ni_suspend      Non-interruptable suspend thread  */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020      William E. Lamie        Initial Version 6.0           */
+/*  09-30-2020      Yuxin Zhou              Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*  04-25-2022      Scott Larson            Modified comment(s),          */
+/*                                            handle 0 flags case,        */
+/*                                            resulting in version 6.1.11 */
+/*  10-31-2022      Scott Larson            Modified comment(s), always   */
+/*                                            return actual flags,        */
+/*                                            resulting in version 6.2.0  */
+/*                                                                        */
+/**************************************************************************/
+UINT  _tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags,
+                    UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+UINT            status;
+UINT            and_request;
+UINT            clear_request;
+ULONG           current_flags;
+ULONG           flags_satisfied;
+#ifndef TX_NOT_INTERRUPTABLE
+ULONG           delayed_clear_flags;
+#endif
+UINT            suspended_count;
+TX_THREAD       *thread_ptr;
+TX_THREAD       *next_thread;
+TX_THREAD       *previous_thread;
+#ifndef TX_NOT_INTERRUPTABLE
+UINT            interrupted_set_request;
+#endif
+
+
+    /* Disable interrupts to examine the event flags group.  */
+    TX_DISABLE
+
+#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
+
+    /* Increment the total event flags get counter.  */
+    _tx_event_flags_performance_get_count++;
+
+    /* Increment the number of event flags gets on this semaphore.  */
+    group_ptr -> tx_event_flags_group__performance_get_count++;
+#endif
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_GET, group_ptr, requested_flags, group_ptr -> tx_event_flags_group_current, get_option, TX_TRACE_EVENT_FLAGS_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_EVENT_FLAGS_GET_INSERT
+
+    /* Pickup current flags.  */
+    current_flags =  group_ptr -> tx_event_flags_group_current;
+
+    /* Return the actual event flags and apply delayed clearing.  */
+    *actual_flags_ptr =  current_flags & ~group_ptr -> tx_event_flags_group_delayed_clear;
+
+    /* Apply the event flag option mask.  */
+    and_request =  (get_option & TX_AND);
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+    /* Check for AND condition. All flags must be present to satisfy request.  */
+    if (and_request == TX_AND)
+    {
+
+        /* AND request is present.  */
+
+        /* Calculate the flags present.  */
+        flags_satisfied =  (current_flags & requested_flags);
+
+        /* Determine if they satisfy the AND request.  */
+        if (flags_satisfied != requested_flags)
+        {
+
+            /* No, not all the requested flags are present. Clear the flags present variable.  */
+            flags_satisfied =  ((ULONG) 0);
+        }
+    }
+    else
+    {
+
+        /* OR request is present. Simply or the requested flags and the current flags.  */
+        flags_satisfied =  (current_flags & requested_flags);
+    }
+
+    /* Determine if the request is satisfied.  */
+    if (flags_satisfied != ((ULONG) 0))
+    {
+
+        /* Pickup the clear bit.  */
+        clear_request =  (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
+
+        /* Determine whether or not clearing needs to take place.  */
+        if (clear_request == TX_TRUE)
+        {
+
+             /* Yes, clear the flags that satisfied this request.  */
+             group_ptr -> tx_event_flags_group_current =
+                                        group_ptr -> tx_event_flags_group_current & (~requested_flags);
+        }
+
+        /* Return success.  */
+        status =  TX_SUCCESS;
+    }
+
+#else
+
+    /* Pickup delayed clear flags.  */
+    delayed_clear_flags =  group_ptr -> tx_event_flags_group_delayed_clear;
+
+    /* Determine if there are any delayed clear operations pending.  */
+    if (delayed_clear_flags != ((ULONG) 0))
+    {
+
+        /* Yes, apply them to the current flags.  */
+        current_flags =  current_flags & (~delayed_clear_flags);
+    }
+
+    /* Check for AND condition. All flags must be present to satisfy request.  */
+    if (and_request == TX_AND)
+    {
+
+        /* AND request is present.  */
+
+        /* Calculate the flags present.  */
+        flags_satisfied =  (current_flags & requested_flags);
+
+        /* Determine if they satisfy the AND request.  */
+        if (flags_satisfied != requested_flags)
+        {
+
+            /* No, not all the requested flags are present. Clear the flags present variable.  */
+            flags_satisfied =  ((ULONG) 0);
+        }
+    }
+    else
+    {
+
+        /* OR request is present. Simply AND together the requested flags and the current flags
+           to see if any are present.  */
+        flags_satisfied =  (current_flags & requested_flags);
+    }
+
+    /* Determine if the request is satisfied.  */
+    if (flags_satisfied != ((ULONG) 0))
+    {
+
+        /* Yes, this request can be handled immediately.  */
+
+        /* Pickup the clear bit.  */
+        clear_request =  (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
+
+        /* Determine whether or not clearing needs to take place.  */
+        if (clear_request == TX_TRUE)
+        {
+
+            /* Set interrupted set request flag to false.  */
+            interrupted_set_request =  TX_FALSE;
+
+            /* Determine if the suspension list is being processed by an interrupted
+               set request.  */
+            if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
+            {
+
+                if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL)
+                {
+
+                    /* Set the interrupted set request flag.  */
+                    interrupted_set_request =  TX_TRUE;
+                }
+            }
+
+            /* Was a set request interrupted?  */
+            if (interrupted_set_request == TX_TRUE)
+            {
+
+                /* A previous set operation is was interrupted, we need to defer the
+                   event clearing until the set operation is complete.  */
+
+                /* Remember the events to clear.  */
+                group_ptr -> tx_event_flags_group_delayed_clear =
+                                        group_ptr -> tx_event_flags_group_delayed_clear | requested_flags;
+            }
+            else
+            {
+
+                /* Yes, clear the flags that satisfied this request.  */
+                group_ptr -> tx_event_flags_group_current =
+                                        group_ptr -> tx_event_flags_group_current & ~requested_flags;
+            }
+        }
+
+        /* Set status to success.  */
+        status =  TX_SUCCESS;
+    }
+
+#endif
+    else
+    {
+        /* flags_satisfied is 0.  */
+        /* Determine if the request specifies suspension.  */
+        if (wait_option != TX_NO_WAIT)
+        {
+
+            /* Determine if the preempt disable flag is non-zero OR the requested events is 0.  */
+            if ((_tx_thread_preempt_disable != ((UINT) 0)) || (requested_flags == (UINT) 0))
+            {
+
+                /* Suspension is not allowed if the preempt disable flag is non-zero at this point,
+                   or if requested_flags is 0, return error completion.  */
+                status =  TX_NO_EVENTS;
+            }
+            else
+            {
+
+                /* Prepare for suspension of this thread.  */
+
+#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
+
+                /* Increment the total event flags suspensions counter.  */
+                _tx_event_flags_performance_suspension_count++;
+
+                /* Increment the number of event flags suspensions on this semaphore.  */
+                group_ptr -> tx_event_flags_group___performance_suspension_count++;
+#endif
+
+                /* Pickup thread pointer.  */
+                TX_THREAD_GET_CURRENT(thread_ptr)
+
+                /* Setup cleanup routine pointer.  */
+                thread_ptr -> tx_thread_suspend_cleanup =  &(_tx_event_flags_cleanup);
+
+                /* Remember which event flags we are looking for.  */
+                thread_ptr -> tx_thread_suspend_info =  requested_flags;
+
+                /* Save the get option as well.  */
+                thread_ptr -> tx_thread_suspend_option =  get_option;
+
+                /* Save the destination for the current events.  */
+                thread_ptr -> tx_thread_additional_suspend_info =  (VOID *) actual_flags_ptr;
+
+                /* Setup cleanup information, i.e. this event flags group control
+                   block.  */
+                thread_ptr -> tx_thread_suspend_control_block =  (VOID *) group_ptr;
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+                /* Increment the suspension sequence number, which is used to identify
+                   this suspension event.  */
+                thread_ptr -> tx_thread_suspension_sequence++;
+#endif
+
+                /* Pickup the suspended count.  */
+                suspended_count =  group_ptr -> tx_event_flags_group_suspended_count;
+
+                /* Setup suspension list.  */
+                if (suspended_count == TX_NO_SUSPENSIONS)
+                {
+
+                    /* No other threads are suspended.  Setup the head pointer and
+                       just setup this threads pointers to itself.  */
+                    group_ptr -> tx_event_flags_group_suspension_list =   thread_ptr;
+                    thread_ptr -> tx_thread_suspended_next =              thread_ptr;
+                    thread_ptr -> tx_thread_suspended_previous =          thread_ptr;
+                }
+                else
+                {
+
+                    /* This list is not NULL, add current thread to the end. */
+                    next_thread =                                   group_ptr -> tx_event_flags_group_suspension_list;
+                    thread_ptr -> tx_thread_suspended_next =        next_thread;
+                    previous_thread =                               next_thread -> tx_thread_suspended_previous;
+                    thread_ptr -> tx_thread_suspended_previous =    previous_thread;
+                    previous_thread -> tx_thread_suspended_next =   thread_ptr;
+                    next_thread -> tx_thread_suspended_previous =   thread_ptr;
+                }
+
+                /* Increment the number of threads suspended.  */
+                group_ptr -> tx_event_flags_group_suspended_count++;
+
+                /* Set the state to suspended.  */
+                thread_ptr -> tx_thread_state =    TX_EVENT_FLAG;
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+                /* Call actual non-interruptable thread suspension routine.  */
+                _tx_thread_system_ni_suspend(thread_ptr, wait_option);
+
+                /* Return the completion status.  */
+                status =  thread_ptr -> tx_thread_suspend_status;
+#else
+
+                /* Set the suspending flag.  */
+                thread_ptr -> tx_thread_suspending =  TX_TRUE;
+
+                /* Setup the timeout period.  */
+                thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  wait_option;
+
+                /* Temporarily disable preemption.  */
+                _tx_thread_preempt_disable++;
+
+                /* Restore interrupts.  */
+                TX_RESTORE
+
+                /* Call actual thread suspension routine.  */
+                _tx_thread_system_suspend(thread_ptr);
+
+                /* Disable interrupts.  */
+                TX_DISABLE
+
+                /* Return the completion status.  */
+                status =  thread_ptr -> tx_thread_suspend_status;
+#endif
+            }
+        }
+        else
+        {
+
+            /* Immediate return, return error completion.  */
+            status =  TX_NO_EVENTS;
+        }
+    }
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+
+    /* Return completion status.  */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_set.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_set.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_event_flags_set.c	(revision 67)
@@ -0,0 +1,625 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_trace.h"
+#include "tx_thread.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_event_flags_set                                 PORTABLE C      */
+/*                                                           6.1.11       */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function sets the specified flags in the event group based on  */
+/*    the set option specified.  All threads suspended on the group whose */
+/*    get request can now be satisfied are resumed.                       */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to group control block    */
+/*    flags_to_set                      Event flags to set                */
+/*    set_option                        Specified either AND or OR        */
+/*                                        operation on the event flags    */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_SUCCESS                        Always returns success            */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_system_preempt_check   Check for preemption              */
+/*    _tx_thread_system_resume          Resume thread service             */
+/*    _tx_thread_system_ni_resume       Non-interruptable resume thread   */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020      William E. Lamie        Initial Version 6.0           */
+/*  09-30-2020      Yuxin Zhou              Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*  04-25-2022      William E. Lamie        Modified comment(s), and      */
+/*                                            added corrected preemption  */
+/*                                            check logic, resulting in   */
+/*                                            version 6.1.11              */
+/*                                                                        */
+/**************************************************************************/
+UINT  _tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+TX_THREAD       *thread_ptr;
+TX_THREAD       *next_thread_ptr;
+TX_THREAD       *next_thread;
+TX_THREAD       *previous_thread;
+TX_THREAD       *satisfied_list;
+TX_THREAD       *last_satisfied;
+TX_THREAD       *suspended_list;
+UINT            suspended_count;
+ULONG           current_event_flags;
+ULONG           requested_flags;
+ULONG           flags_satisfied;
+ULONG           *suspend_info_ptr;
+UINT            and_request;
+UINT            get_option;
+UINT            clear_request;
+UINT            preempt_check;
+#ifndef TX_NOT_INTERRUPTABLE
+UINT            interrupted_set_request;
+#endif
+#ifndef TX_DISABLE_NOTIFY_CALLBACKS
+VOID            (*events_set_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *notify_group_ptr);
+#endif
+
+
+    /* Disable interrupts to remove the semaphore from the created list.  */
+    TX_DISABLE
+
+#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
+
+    /* Increment the total event flags set counter.  */
+    _tx_event_flags_performance_set_count++;
+
+    /* Increment the number of event flags sets on this semaphore.  */
+    group_ptr -> tx_event_flags_group_performance_set_count++;
+#endif
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_SET, group_ptr, flags_to_set, set_option, group_ptr -> tx_event_flags_group_suspended_count, TX_TRACE_EVENT_FLAGS_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_EVENT_FLAGS_SET_INSERT
+
+    /* Determine how to set this group's event flags.  */
+    if ((set_option & TX_EVENT_FLAGS_AND_MASK) == TX_AND)
+    {
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+        /* Set interrupted set request flag to false.  */
+        interrupted_set_request =  TX_FALSE;
+
+        /* Determine if the suspension list is being processed by an interrupted
+           set request.  */
+        if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
+        {
+
+            if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL)
+            {
+
+                /* Set the interrupted set request flag.  */
+                interrupted_set_request =  TX_TRUE;
+            }
+        }
+
+        /* Was a set request interrupted?  */
+        if (interrupted_set_request == TX_TRUE)
+        {
+
+            /* A previous set operation was interrupted, we need to defer the
+               event clearing until the set operation is complete.  */
+
+            /* Remember the events to clear.  */
+            group_ptr -> tx_event_flags_group_delayed_clear =
+                                        group_ptr -> tx_event_flags_group_delayed_clear | ~flags_to_set;
+        }
+        else
+        {
+#endif
+
+            /* Previous set operation was not interrupted, simply clear the
+               specified flags by "ANDing" the flags into the current events
+               of the group.  */
+            group_ptr -> tx_event_flags_group_current =
+                group_ptr -> tx_event_flags_group_current & flags_to_set;
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+        }
+#endif
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+    }
+    else
+    {
+
+#ifndef TX_DISABLE_NOTIFY_CALLBACKS
+
+        /* Pickup the notify callback routine for this event flag group.  */
+        events_set_notify =  group_ptr -> tx_event_flags_group_set_notify;
+#endif
+
+        /* "OR" the flags into the current events of the group.  */
+        group_ptr -> tx_event_flags_group_current =
+            group_ptr -> tx_event_flags_group_current | flags_to_set;
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+        /* Determine if there are any delayed flags to clear.  */
+        if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0))
+        {
+
+            /* Yes, we need to neutralize the delayed clearing as well.  */
+            group_ptr -> tx_event_flags_group_delayed_clear =
+                                        group_ptr -> tx_event_flags_group_delayed_clear & ~flags_to_set;
+        }
+#endif
+
+        /* Clear the preempt check flag.  */
+        preempt_check =  TX_FALSE;
+
+        /* Pickup the thread suspended count.  */
+        suspended_count =  group_ptr -> tx_event_flags_group_suspended_count;
+
+        /* Determine if there are any threads suspended on the event flag group.  */
+        if (group_ptr -> tx_event_flags_group_suspension_list != TX_NULL)
+        {
+
+            /* Determine if there is just a single thread waiting on the event
+               flag group.  */
+            if (suspended_count == ((UINT) 1))
+            {
+
+                /* Single thread waiting for event flags.  Bypass the multiple thread
+                   logic.  */
+
+                /* Setup thread pointer.  */
+                thread_ptr =  group_ptr -> tx_event_flags_group_suspension_list;
+
+                /* Pickup the current event flags.  */
+                current_event_flags =  group_ptr -> tx_event_flags_group_current;
+
+                /* Pickup the suspend information.  */
+                requested_flags =  thread_ptr -> tx_thread_suspend_info;
+
+                /* Pickup the suspend option.  */
+                get_option =  thread_ptr -> tx_thread_suspend_option;
+
+                /* Isolate the AND selection.  */
+                and_request =  (get_option & TX_AND);
+
+                /* Check for AND condition. All flags must be present to satisfy request.  */
+                if (and_request == TX_AND)
+                {
+
+                    /* AND request is present.  */
+
+                    /* Calculate the flags present.  */
+                    flags_satisfied =  (current_event_flags & requested_flags);
+
+                    /* Determine if they satisfy the AND request.  */
+                    if (flags_satisfied != requested_flags)
+                    {
+
+                        /* No, not all the requested flags are present. Clear the flags present variable.  */
+                        flags_satisfied =  ((ULONG) 0);
+                    }
+                }
+                else
+                {
+
+                    /* OR request is present. Simply or the requested flags and the current flags.  */
+                    flags_satisfied =  (current_event_flags & requested_flags);
+                }
+
+                /* Determine if the request is satisfied.  */
+                if (flags_satisfied != ((ULONG) 0))
+                {
+
+                    /* Yes, resume the thread and apply any event flag
+                       clearing.  */
+
+                    /* Return the actual event flags that satisfied the request.  */
+                    suspend_info_ptr =   TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
+                    *suspend_info_ptr =  current_event_flags;
+
+                    /* Pickup the clear bit.  */
+                    clear_request =  (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
+
+                    /* Determine whether or not clearing needs to take place.  */
+                    if (clear_request == TX_TRUE)
+                    {
+
+                        /* Yes, clear the flags that satisfied this request.  */
+                        group_ptr -> tx_event_flags_group_current =  group_ptr -> tx_event_flags_group_current & (~requested_flags);
+                    }
+
+                    /* Clear the suspension information in the event flag group.  */
+                    group_ptr -> tx_event_flags_group_suspension_list =  TX_NULL;
+                    group_ptr -> tx_event_flags_group_suspended_count =  TX_NO_SUSPENSIONS;
+
+                    /* Clear cleanup routine to avoid timeout.  */
+                    thread_ptr -> tx_thread_suspend_cleanup =  TX_NULL;
+
+                    /* Put return status into the thread control block.  */
+                    thread_ptr -> tx_thread_suspend_status =  TX_SUCCESS;
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+                    /* Resume the thread!  */
+                    _tx_thread_system_ni_resume(thread_ptr);
+#else
+
+                    /* Temporarily disable preemption.  */
+                    _tx_thread_preempt_disable++;
+
+                    /* Restore interrupts.  */
+                    TX_RESTORE
+
+                    /* Resume thread.  */
+                    _tx_thread_system_resume(thread_ptr);
+
+                    /* Disable interrupts to remove the semaphore from the created list.  */
+                    TX_DISABLE
+#endif
+                }
+            }
+            else
+            {
+
+                /* Otherwise, the event flag requests of multiple threads must be
+                   examined.  */
+
+                /* Setup thread pointer, keep a local copy of the head pointer.  */
+                suspended_list =  group_ptr -> tx_event_flags_group_suspension_list;
+                thread_ptr =      suspended_list;
+
+                /* Clear the suspended list head pointer to thwart manipulation of
+                   the list in ISR's while we are processing here.  */
+                group_ptr -> tx_event_flags_group_suspension_list =  TX_NULL;
+
+                /* Setup the satisfied thread pointers.  */
+                satisfied_list =  TX_NULL;
+                last_satisfied =  TX_NULL;
+
+                /* Pickup the current event flags.  */
+                current_event_flags =  group_ptr -> tx_event_flags_group_current;
+
+                /* Disable preemption while we process the suspended list.  */
+                _tx_thread_preempt_disable++;
+
+                /* Since we have temporarily disabled preemption globally, set the preempt 
+                   check flag to check for any preemption condition - including from 
+                   unrelated ISR processing.  */
+                preempt_check =  TX_TRUE;
+
+                /* Loop to examine all of the suspended threads. */
+                do
+                {
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+                    /* Restore interrupts temporarily.  */
+                    TX_RESTORE
+
+                    /* Disable interrupts again.  */
+                    TX_DISABLE
+#endif
+
+                    /* Determine if we need to reset the search.  */
+                    if (group_ptr -> tx_event_flags_group_reset_search != TX_FALSE)
+                    {
+
+                        /* Clear the reset search flag.  */
+                        group_ptr -> tx_event_flags_group_reset_search =  TX_FALSE;
+
+                        /* Move the thread pointer to the beginning of the search list.  */
+                        thread_ptr =  suspended_list;
+
+                        /* Reset the suspended count.  */
+                        suspended_count =  group_ptr -> tx_event_flags_group_suspended_count;
+
+                        /* Update the current events with any new ones that might
+                           have been set in a nested set events call from an ISR.  */
+                        current_event_flags =  current_event_flags | group_ptr -> tx_event_flags_group_current;
+                    }
+
+                    /* Save next thread pointer.  */
+                    next_thread_ptr =  thread_ptr -> tx_thread_suspended_next;
+
+                    /* Pickup the suspend information.  */
+                    requested_flags =  thread_ptr -> tx_thread_suspend_info;
+
+                    /* Pickup this thread's suspension get option.  */
+                    get_option =  thread_ptr -> tx_thread_suspend_option;
+
+                    /* Isolate the AND selection.  */
+                    and_request =  (get_option & TX_AND);
+
+                    /* Check for AND condition. All flags must be present to satisfy request.  */
+                    if (and_request == TX_AND)
+                    {
+
+                        /* AND request is present.  */
+
+                        /* Calculate the flags present.  */
+                        flags_satisfied =  (current_event_flags & requested_flags);
+
+                        /* Determine if they satisfy the AND request.  */
+                        if (flags_satisfied != requested_flags)
+                        {
+
+                            /* No, not all the requested flags are present. Clear the flags present variable.  */
+                            flags_satisfied =  ((ULONG) 0);
+                        }
+                    }
+                    else
+                    {
+
+                        /* OR request is present. Simply or the requested flags and the current flags.  */
+                        flags_satisfied =  (current_event_flags & requested_flags);
+                    }
+
+                    /* Check to see if the thread had a timeout or wait abort during the event search processing.
+                       If so, just set the flags satisfied to ensure the processing here removes the thread from
+                       the suspension list.  */
+                    if (thread_ptr -> tx_thread_state != TX_EVENT_FLAG)
+                    {
+
+                       /* Simply set the satisfied flags to 1 in order to remove the thread from the suspension list.  */
+                        flags_satisfied =  ((ULONG) 1);
+                    }
+
+                    /* Determine if the request is satisfied.  */
+                    if (flags_satisfied != ((ULONG) 0))
+                    {
+
+                        /* Yes, this request can be handled now.  */
+
+                        /* Determine if the thread is still suspended on the event flag group. If not, a wait
+                           abort must have been done from an ISR.  */
+                        if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG)
+                        {
+
+                            /* Return the actual event flags that satisfied the request.  */
+                            suspend_info_ptr =   TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
+                            *suspend_info_ptr =  current_event_flags;
+
+                            /* Pickup the clear bit.  */
+                            clear_request =  (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
+
+                            /* Determine whether or not clearing needs to take place.  */
+                            if (clear_request == TX_TRUE)
+                            {
+
+                                /* Yes, clear the flags that satisfied this request.  */
+                                group_ptr -> tx_event_flags_group_current =  group_ptr -> tx_event_flags_group_current & ~requested_flags;
+                            }
+
+                            /* Prepare for resumption of the first thread.  */
+
+                            /* Clear cleanup routine to avoid timeout.  */
+                            thread_ptr -> tx_thread_suspend_cleanup =  TX_NULL;
+
+                            /* Put return status into the thread control block.  */
+                            thread_ptr -> tx_thread_suspend_status =  TX_SUCCESS;
+                        }
+
+                        /* We need to remove the thread from the suspension list and place it in the
+                           expired list.  */
+
+                        /* See if this is the only suspended thread on the list.  */
+                        if (thread_ptr == thread_ptr -> tx_thread_suspended_next)
+                        {
+
+                            /* Yes, the only suspended thread.  */
+
+                            /* Update the head pointer.  */
+                            suspended_list =  TX_NULL;
+                        }
+                        else
+                        {
+
+                            /* At least one more thread is on the same expiration list.  */
+
+                            /* Update the links of the adjacent threads.  */
+                            next_thread =                                  thread_ptr -> tx_thread_suspended_next;
+                            previous_thread =                              thread_ptr -> tx_thread_suspended_previous;
+                            next_thread -> tx_thread_suspended_previous =  previous_thread;
+                            previous_thread -> tx_thread_suspended_next =  next_thread;
+
+                            /* Update the list head pointer, if removing the head of the
+                               list.  */
+                            if (suspended_list == thread_ptr)
+                            {
+
+                                /* Yes, head pointer needs to be updated.  */
+                                suspended_list =  thread_ptr -> tx_thread_suspended_next;
+                            }
+                        }
+
+                        /* Decrement the suspension count.  */
+                        group_ptr -> tx_event_flags_group_suspended_count--;
+
+                        /* Place this thread on the expired list.  */
+                        if (satisfied_list == TX_NULL)
+                        {
+
+                            /* First thread on the satisfied list.  */
+                            satisfied_list =  thread_ptr;
+                            last_satisfied =  thread_ptr;
+
+                            /* Setup initial next pointer.  */
+                            thread_ptr -> tx_thread_suspended_next =  TX_NULL;
+                        }
+                        else
+                        {
+
+                            /* Not the first thread on the satisfied list.  */
+
+                            /* Link it up at the end.  */
+                            last_satisfied -> tx_thread_suspended_next =  thread_ptr;
+                            thread_ptr -> tx_thread_suspended_next =      TX_NULL;
+                            last_satisfied =                              thread_ptr;
+                        }
+                    }
+
+                    /* Copy next thread pointer to working thread ptr.  */
+                    thread_ptr =  next_thread_ptr;
+
+                    /* Decrement the suspension count.  */
+                    suspended_count--;
+
+                } while (suspended_count != TX_NO_SUSPENSIONS);
+
+                /* Setup the group's suspension list head again.  */
+                group_ptr -> tx_event_flags_group_suspension_list =  suspended_list;
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+                /* Determine if there is any delayed event clearing to perform.  */
+                if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0))
+                {
+
+                    /* Perform the delayed event clearing.  */
+                    group_ptr -> tx_event_flags_group_current =
+                        group_ptr -> tx_event_flags_group_current & ~(group_ptr -> tx_event_flags_group_delayed_clear);
+
+                    /* Clear the delayed event flag clear value.  */
+                    group_ptr -> tx_event_flags_group_delayed_clear =  ((ULONG) 0);
+                }
+#endif
+
+                /* Restore interrupts.  */
+                TX_RESTORE
+
+                /* Walk through the satisfied list, setup initial thread pointer. */
+                thread_ptr =  satisfied_list;
+                while(thread_ptr != TX_NULL)
+                {
+
+                    /* Get next pointer first.  */
+                    next_thread_ptr =  thread_ptr -> tx_thread_suspended_next;
+
+                    /* Disable interrupts.  */
+                    TX_DISABLE
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+                    /* Resume the thread!  */
+                    _tx_thread_system_ni_resume(thread_ptr);
+
+                    /* Restore interrupts.  */
+                    TX_RESTORE
+#else
+
+                    /* Disable preemption again.  */
+                    _tx_thread_preempt_disable++;
+
+                    /* Restore interrupt posture.  */
+                    TX_RESTORE
+
+                    /* Resume the thread.  */
+                    _tx_thread_system_resume(thread_ptr);
+#endif
+
+                    /* Move next thread to current.  */
+                    thread_ptr =  next_thread_ptr;
+                }
+
+                /* Disable interrupts.  */
+                TX_DISABLE
+
+                /* Release thread preemption disable.  */
+                _tx_thread_preempt_disable--;
+            }
+        }
+        else
+        {
+
+            /* Determine if we need to set the reset search field.  */
+            if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
+            {
+
+                /* We interrupted a search of an event flag group suspension
+                   list.  Make sure we reset the search.  */
+                group_ptr -> tx_event_flags_group_reset_search =  TX_TRUE;
+            }
+        }
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+
+#ifndef TX_DISABLE_NOTIFY_CALLBACKS
+
+        /* Determine if a notify callback is required.  */
+        if (events_set_notify != TX_NULL)
+        {
+
+            /* Call application event flags set notification.  */
+            (events_set_notify)(group_ptr);
+        }
+#endif
+
+        /* Determine if a check for preemption is necessary.  */
+        if (preempt_check == TX_TRUE)
+        {
+
+            /* Yes, one or more threads were resumed, check for preemption.  */
+            _tx_thread_system_preempt_check();
+        }
+    }
+
+    /* Return completion status.  */
+    return(TX_SUCCESS);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_resume.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_resume.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_resume.c	(revision 67)
@@ -0,0 +1,583 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Thread                                                              */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_trace.h"
+#include "tx_thread.h"
+#include "tx_initialize.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_thread_resume                                   PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function processes application resume thread services. Actual  */
+/*    thread resumption is performed in the core service.                 */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    thread_ptr                            Pointer to thread to resume   */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    status                                Service return status         */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_system_resume          Resume thread                     */
+/*    _tx_thread_system_ni_resume       Non-interruptable resume thread   */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _tx_thread_resume(TX_THREAD *thread_ptr)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+UINT        status;
+TX_THREAD   *saved_thread_ptr;
+UINT        saved_threshold =  ((UINT) 0);
+
+#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
+UINT            priority;
+ULONG           priority_bit;
+TX_THREAD       *head_ptr;
+TX_THREAD       *tail_ptr;
+TX_THREAD       *execute_ptr;
+TX_THREAD       *current_thread;
+ULONG           combined_flags;
+
+#ifdef TX_ENABLE_EVENT_TRACE
+TX_TRACE_BUFFER_ENTRY       *entry_ptr;
+ULONG                       time_stamp =  ((ULONG) 0);
+#endif
+
+#if TX_MAX_PRIORITIES > 32
+UINT            map_index;
+#endif
+
+
+#ifdef TX_ENABLE_STACK_CHECKING
+
+    /* Check this thread's stack.  */
+    TX_THREAD_STACK_CHECK(thread_ptr)
+#endif
+#endif
+
+    /* Lockout interrupts while the thread is being resumed.  */
+    TX_DISABLE
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_THREAD_RESUME_INSERT
+
+    /* Determine if the thread is suspended or in the process of suspending.
+       If so, call the thread resume processing.  */
+    if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
+    {
+
+        /* Determine if the create call is being called from initialization.  */
+        if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
+        {
+
+            /* Yes, this resume call was made from initialization.  */
+
+            /* Pickup the current thread execute pointer, which corresponds to the
+               highest priority thread ready to execute.  Interrupt lockout is
+               not required, since interrupts are assumed to be disabled during
+               initialization.  */
+            saved_thread_ptr =  _tx_thread_execute_ptr;
+
+            /* Determine if there is thread ready for execution.  */
+            if (saved_thread_ptr != TX_NULL)
+            {
+
+                /* Yes, a thread is ready for execution when initialization completes.  */
+
+                /* Save the current preemption-threshold.  */
+                saved_threshold =  saved_thread_ptr -> tx_thread_preempt_threshold;
+
+                /* For initialization, temporarily set the preemption-threshold to the
+                   priority level to make sure the highest-priority thread runs once
+                   initialization is complete.  */
+                saved_thread_ptr -> tx_thread_preempt_threshold =  saved_thread_ptr -> tx_thread_priority;
+            }
+        }
+        else
+        {
+
+            /* Simply set the saved thread pointer to NULL.  */
+            saved_thread_ptr =  TX_NULL;
+        }
+
+#ifndef TX_INLINE_THREAD_RESUME_SUSPEND
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+        /* Resume the thread!  */
+        _tx_thread_system_ni_resume(thread_ptr);
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+#else
+
+        /* Temporarily disable preemption.  */
+        _tx_thread_preempt_disable++;
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+
+        /* Call the actual resume service to resume the thread.  */
+        _tx_thread_system_resume(thread_ptr);
+#endif
+
+        /* Determine if the thread's preemption-threshold needs to be restored.  */
+        if (saved_thread_ptr != TX_NULL)
+        {
+
+            /* Yes, restore the previous highest-priority thread's preemption-threshold. This
+               can only happen if this routine is called from initialization.  */
+            saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
+        }
+
+#ifdef TX_MISRA_ENABLE
+
+        /* Disable interrupts.  */
+        TX_DISABLE
+
+        /* Setup successful return status.  */
+        status =  TX_SUCCESS;
+#else
+
+        /* Return successful completion.  */
+        return(TX_SUCCESS);
+#endif
+
+
+#else
+
+        /* In-line thread resumption processing follows, which is effectively just taking the
+           logic in tx_thread_system_resume.c and placing it here!  */
+
+        /* Resume the thread!  */
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+        /* If trace is enabled, save the current event pointer.  */
+        entry_ptr =  _tx_trace_buffer_current_ptr;
+#endif
+
+        /* Log the thread status change.  */
+        TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&execute_ptr), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+        /* Save the time stamp for later comparison to verify that
+           the event hasn't been overwritten by the time we have
+           computed the next thread to execute.  */
+        if (entry_ptr != TX_NULL)
+        {
+
+            /* Save time stamp.  */
+            time_stamp =  entry_ptr -> tx_trace_buffer_entry_time_stamp;
+        }
+#endif
+
+        /* Make this thread ready.  */
+
+        /* Change the state to ready.  */
+        thread_ptr -> tx_thread_state =  TX_READY;
+
+        /* Pickup priority of thread.  */
+        priority =  thread_ptr -> tx_thread_priority;
+
+        /* Thread state change.  */
+        TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)
+
+        /* Log the thread status change.  */
+        TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+        /* Increment the total number of thread resumptions.  */
+        _tx_thread_performance_resume_count++;
+
+        /* Increment this thread's resume count.  */
+        thread_ptr -> tx_thread_performance_resume_count++;
+#endif
+
+        /* Determine if there are other threads at this priority that are
+           ready.  */
+        head_ptr =  _tx_thread_priority_list[priority];
+        if (head_ptr == TX_NULL)
+        {
+
+            /* First thread at this priority ready.  Add to the front of the list.  */
+            _tx_thread_priority_list[priority] =       thread_ptr;
+            thread_ptr -> tx_thread_ready_next =       thread_ptr;
+            thread_ptr -> tx_thread_ready_previous =   thread_ptr;
+
+#if TX_MAX_PRIORITIES > 32
+
+            /* Calculate the index into the bit map array.  */
+            map_index =  priority/((UINT) 32);
+
+            /* Set the active bit to remember that the priority map has something set.  */
+            TX_DIV32_BIT_SET(priority, priority_bit)
+            _tx_thread_priority_map_active =  _tx_thread_priority_map_active | priority_bit;
+#endif
+
+            /* Or in the thread's priority bit.  */
+            TX_MOD32_BIT_SET(priority, priority_bit)
+            _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] | priority_bit;
+
+            /* Determine if this newly ready thread is the highest priority.  */
+            if (priority < _tx_thread_highest_priority)
+            {
+
+                /* A new highest priority thread is present. */
+
+                /* Update the highest priority variable.  */
+                _tx_thread_highest_priority =  priority;
+
+                /* Pickup the execute pointer. Since it is going to be referenced multiple
+                   times, it is placed in a local variable.  */
+                execute_ptr =  _tx_thread_execute_ptr;
+
+                /* Determine if no thread is currently executing.  */
+                if (execute_ptr == TX_NULL)
+                {
+
+                    /* Simply setup the execute pointer.  */
+                    _tx_thread_execute_ptr =  thread_ptr;
+                }
+                else
+                {
+
+                    /* Another thread has been scheduled for execution.  */
+
+                    /* Check to see if this is a higher priority thread and determine if preemption is allowed.  */
+                    if (priority < execute_ptr -> tx_thread_preempt_threshold)
+                    {
+
+#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
+
+                        /* Determine if the preempted thread had preemption-threshold set.  */
+                        if (execute_ptr -> tx_thread_preempt_threshold != execute_ptr -> tx_thread_priority)
+                        {
+
+#if TX_MAX_PRIORITIES > 32
+
+                            /* Calculate the index into the bit map array.  */
+                            map_index =  (execute_ptr -> tx_thread_priority)/((UINT) 32);
+
+                            /* Set the active bit to remember that the preempt map has something set.  */
+                            TX_DIV32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
+                            _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active | priority_bit;
+#endif
+
+                            /* Remember that this thread was preempted by a thread above the thread's threshold.  */
+                            TX_MOD32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
+                            _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
+                        }
+#endif
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                        /* Determine if the caller is an interrupt or from a thread.  */
+                        if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
+                        {
+
+                            /* Caller is a thread, so this is a solicited preemption.  */
+                            _tx_thread_performance_solicited_preemption_count++;
+
+                            /* Increment the thread's solicited preemption counter.  */
+                            execute_ptr -> tx_thread_performance_solicited_preemption_count++;
+                        }
+                        else
+                        {
+
+                            if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
+                            {
+
+                                /* Caller is an interrupt, so this is an interrupt preemption.  */
+                                _tx_thread_performance_interrupt_preemption_count++;
+
+                                /* Increment the thread's interrupt preemption counter.  */
+                                execute_ptr -> tx_thread_performance_interrupt_preemption_count++;
+                            }
+                        }
+
+                        /* Remember the thread that preempted this thread.  */
+                        execute_ptr -> tx_thread_performance_last_preempting_thread =  thread_ptr;
+#endif
+
+                        /* Yes, modify the execute thread pointer.  */
+                        _tx_thread_execute_ptr =  thread_ptr;
+
+#ifndef TX_MISRA_ENABLE
+
+                        /* If MISRA is not-enabled, insert a preemption and return in-line for performance.  */
+
+                        /* Determine if the thread's preemption-threshold needs to be restored.  */
+                        if (saved_thread_ptr != TX_NULL)
+                        {
+
+                            /* Yes, restore the previous highest-priority thread's preemption-threshold. This
+                               can only happen if this routine is called from initialization.  */
+                            saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
+                        }
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                        /* Is the execute pointer different?  */
+                        if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
+                        {
+
+                            /* Move to next entry.  */
+                            _tx_thread_performance__execute_log_index++;
+
+                            /* Check for wrap condition.  */
+                            if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
+                            {
+
+                                /* Set the index to the beginning.  */
+                                _tx_thread_performance__execute_log_index =  ((UINT) 0);
+                            }
+
+                            /* Log the new execute pointer.  */
+                            _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
+                        }
+#endif
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+                        /* Check that the event time stamp is unchanged.  A different
+                           timestamp means that a later event wrote over the thread
+                           resume event. In that case, do nothing here.  */
+                        if (entry_ptr != TX_NULL)
+                        {
+
+                            /* Is the timestamp the same?  */
+                            if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+                            {
+
+                                /* Timestamp is the same, set the "next thread pointer" to NULL. This can
+                                   be used by the trace analysis tool to show idle system conditions.  */
+                                entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+                            }
+                        }
+#endif
+
+                        /* Restore interrupts.  */
+                        TX_RESTORE
+
+#ifdef TX_ENABLE_STACK_CHECKING
+
+                        /* Pickup the next execute pointer.  */
+                        thread_ptr =  _tx_thread_execute_ptr;
+
+                        /* Check this thread's stack.  */
+                        TX_THREAD_STACK_CHECK(thread_ptr)
+#endif
+
+                        /* Now determine if preemption should take place. This is only possible if the current thread pointer is
+                           not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
+                        TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
+                        if (combined_flags == ((ULONG) 0))
+                        {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                            /* There is another thread ready to run and will be scheduled upon return.  */
+                            _tx_thread_performance_non_idle_return_count++;
+#endif
+
+                            /* Preemption is needed - return to the system!  */
+                            _tx_thread_system_return();
+                        }
+
+                        /* Return in-line when MISRA is not enabled.  */
+                        return(TX_SUCCESS);
+#endif
+                    }
+                }
+            }
+        }
+        else
+        {
+
+            /* No, there are other threads at this priority already ready.  */
+
+            /* Just add this thread to the priority list.  */
+            tail_ptr =                                 head_ptr -> tx_thread_ready_previous;
+            tail_ptr -> tx_thread_ready_next =         thread_ptr;
+            head_ptr -> tx_thread_ready_previous =     thread_ptr;
+            thread_ptr -> tx_thread_ready_previous =   tail_ptr;
+            thread_ptr -> tx_thread_ready_next =       head_ptr;
+        }
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+        /* Determine if we should log the execute pointer.  */
+
+        /* Is the execute pointer different?  */
+        if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
+        {
+
+            /* Move to next entry.  */
+            _tx_thread_performance__execute_log_index++;
+
+            /* Check for wrap condition.  */
+            if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
+            {
+
+                /* Set the index to the beginning.  */
+                _tx_thread_performance__execute_log_index =  ((UINT) 0);
+            }
+
+            /* Log the new execute pointer.  */
+            _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
+        }
+#endif
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+        /* Check that the event time stamp is unchanged.  A different
+           timestamp means that a later event wrote over the thread
+           resume event. In that case, do nothing here.  */
+        if (entry_ptr != TX_NULL)
+        {
+
+            /* Is the timestamp the same?  */
+            if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+            {
+
+                /* Timestamp is the same, set the "next thread pointer" to NULL. This can
+                   be used by the trace analysis tool to show idle system conditions.  */
+#ifdef TX_MISRA_ENABLE
+              entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#else
+              entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#endif
+            }
+        }
+#endif
+
+        /* Determine if the thread's preemption-threshold needs to be restored.  */
+        if (saved_thread_ptr != TX_NULL)
+        {
+
+            /* Yes, restore the previous highest-priority thread's preemption-threshold. This
+               can only happen if this routine is called from initialization.  */
+            saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
+        }
+
+        /* Setup successful return status.  */
+        status =  TX_SUCCESS;
+#endif
+    }
+    else if (thread_ptr -> tx_thread_delayed_suspend == TX_TRUE)
+    {
+
+        /* Clear the delayed suspension.  */
+        thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;
+
+        /* Setup delayed suspend lifted return status.  */
+        status =  TX_SUSPEND_LIFTED;
+    }
+    else
+    {
+
+        /* Setup invalid resume return status.  */
+        status =  TX_RESUME_ERROR;
+    }
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+
+#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
+
+    /* Pickup thread pointer.  */
+    TX_THREAD_GET_CURRENT(current_thread)
+
+    /* Determine if a preemption condition is present.  */
+    if (current_thread != _tx_thread_execute_ptr)
+    {
+
+#ifdef TX_ENABLE_STACK_CHECKING
+
+        /* Pickup the next execute pointer.  */
+        thread_ptr =  _tx_thread_execute_ptr;
+
+        /* Check this thread's stack.  */
+        TX_THREAD_STACK_CHECK(thread_ptr)
+#endif
+
+        /* Now determine if preemption should take place. This is only possible if the current thread pointer is
+           not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
+        TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
+        if (combined_flags == ((ULONG) 0))
+        {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+            /* There is another thread ready to run and will be scheduled upon return.  */
+            _tx_thread_performance_non_idle_return_count++;
+#endif
+
+            /* Preemption is needed - return to the system!  */
+            _tx_thread_system_return();
+        }
+    }
+#endif
+
+    /* Return completion status. */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_suspend.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_suspend.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/tx_thread_suspend.c	(revision 67)
@@ -0,0 +1,849 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Thread                                                              */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+#define TX_SOURCE_CODE
+
+/* Include necessary system files.  */
+#include "tx_api.h"
+#include "tx_trace.h"
+#include "tx_thread.h"
+#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
+#ifndef TX_NO_TIMER
+#include "tx_timer.h"
+#endif
+#endif
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _tx_thread_suspend                                  PORTABLE C      */
+/*                                                           6.1.1        */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function handles application suspend requests.  If the suspend */
+/*    requires actual processing, this function calls the actual suspend  */
+/*    thread routine.                                                     */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    thread_ptr                            Pointer to thread to suspend  */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    status                                Return completion status      */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_system_suspend         Actual thread suspension          */
+/*    _tx_thread_system_ni_suspend      Non-interruptable suspend thread  */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*  10-16-2020     Yuxin Zhou               Modified comment(s), and      */
+/*                                            added type cast to address  */
+/*                                            a MISRA compliance issue,   */
+/*                                            resulting in version 6.1.1  */
+/*                                                                        */
+/**************************************************************************/
+UINT  _tx_thread_suspend(TX_THREAD *thread_ptr)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+TX_THREAD  *current_thread;
+UINT        status;
+
+
+#ifndef TX_INLINE_THREAD_RESUME_SUSPEND
+
+    /* Lockout interrupts while the thread is being suspended.  */
+    TX_DISABLE
+
+    /* Pickup thread pointer.  */
+    TX_THREAD_GET_CURRENT(current_thread)
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_THREAD_SUSPEND_INSERT
+
+    /* Check the specified thread's current status.  */
+    if (thread_ptr -> tx_thread_state == TX_READY)
+    {
+
+        /* Initialize status to success.  */
+        status =  TX_SUCCESS;
+
+        /* Determine if we are in a thread context.  */
+        if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
+        {
+
+            /* Yes, we are in a thread context.  */
+
+            /* Determine if the current thread is also the suspending thread.  */
+            if (current_thread == thread_ptr)
+            {
+
+                /* Now determine if the preempt disable flag is non-zero.  */
+                if (_tx_thread_preempt_disable != ((UINT) 0))
+                {
+
+                    /* Current thread cannot suspend when the preempt disable flag is non-zero,
+                       return an error.  */
+                    status =  TX_SUSPEND_ERROR;
+                }
+            }
+        }
+
+        /* Determine if the status is still successful.  */
+        if (status == TX_SUCCESS)
+        {
+
+            /* Set the state to suspended.  */
+            thread_ptr -> tx_thread_state =    TX_SUSPENDED;
+
+#ifdef TX_NOT_INTERRUPTABLE
+
+            /* Call actual non-interruptable thread suspension routine.  */
+            _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
+
+            /* Restore interrupts.  */
+            TX_RESTORE
+#else
+
+            /* Set the suspending flag. */
+            thread_ptr -> tx_thread_suspending =  TX_TRUE;
+
+            /* Setup for no timeout period.  */
+            thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0);
+
+            /* Temporarily disable preemption.  */
+            _tx_thread_preempt_disable++;
+
+            /* Restore interrupts.  */
+            TX_RESTORE
+
+            /* Call actual thread suspension routine.  */
+            _tx_thread_system_suspend(thread_ptr);
+#endif
+
+#ifdef TX_MISRA_ENABLE
+
+            /* Disable interrupts.  */
+            TX_DISABLE
+
+            /* Return success.  */
+            status =  TX_SUCCESS;
+#else
+
+            /* If MISRA is not enabled, return directly.  */
+            return(TX_SUCCESS);
+#endif
+        }
+    }
+    else if (thread_ptr -> tx_thread_state == TX_TERMINATED)
+    {
+
+        /* Thread is terminated.  */
+        status =  TX_SUSPEND_ERROR;
+    }
+    else if (thread_ptr -> tx_thread_state == TX_COMPLETED)
+    {
+
+        /* Thread is completed.  */
+        status =  TX_SUSPEND_ERROR;
+    }
+    else if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
+    {
+
+        /* Already suspended, just set status to success.  */
+        status =  TX_SUCCESS;
+    }
+    else
+    {
+
+        /* Just set the delayed suspension flag.  */
+        thread_ptr -> tx_thread_delayed_suspend =  TX_TRUE;
+
+        /* Set status to success.  */
+        status =  TX_SUCCESS;
+    }
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+
+    /* Always return success, since this function does not perform error
+       checking.  */
+    return(status);
+
+#else
+
+    /* In-line thread suspension processing follows, which is effectively just taking the
+       logic in tx_thread_system_suspend.c and placing it here!  */
+
+UINT            priority;
+UINT            base_priority;
+ULONG           priority_map;
+ULONG           priority_bit;
+ULONG           combined_flags;
+TX_THREAD       *ready_next;
+TX_THREAD       *ready_previous;
+
+#if TX_MAX_PRIORITIES > 32
+UINT            map_index;
+#endif
+
+#ifdef TX_ENABLE_EVENT_TRACE
+TX_TRACE_BUFFER_ENTRY       *entry_ptr;
+ULONG                       time_stamp =  ((ULONG) 0);
+#endif
+
+
+    /* Pickup thread pointer.  */
+    TX_THREAD_GET_CURRENT(current_thread)
+
+#ifdef TX_ENABLE_STACK_CHECKING
+
+    /* Check this thread's stack.  */
+    TX_THREAD_STACK_CHECK(thread_ptr)
+#endif
+
+    /* Lockout interrupts while the thread is being suspended.  */
+    TX_DISABLE
+
+#ifndef TX_NO_TIMER
+
+    /* Determine if this is the current thread.  */
+    if (thread_ptr == current_thread)
+    {
+
+        /* Yes, current thread is suspending - reset time slice for current thread.  */
+        _tx_timer_time_slice =  thread_ptr -> tx_thread_new_time_slice;
+    }
+#endif
+
+    /* If trace is enabled, insert this event into the trace buffer.  */
+    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
+
+    /* Log this kernel call.  */
+    TX_EL_THREAD_SUSPEND_INSERT
+
+    /* Check the specified thread's current status.  */
+    if (thread_ptr -> tx_thread_state == TX_READY)
+    {
+
+        /* Initialize status to success.  */
+        status =  TX_SUCCESS;
+
+        /* Determine if we are in a thread context.  */
+        if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
+        {
+
+            /* Yes, we are in a thread context.  */
+
+            /* Determine if the current thread is also the suspending thread.  */
+            if (current_thread == thread_ptr)
+            {
+
+                /* Now determine if the preempt disable flag is non-zero.  */
+                if (_tx_thread_preempt_disable != ((UINT) 0))
+                {
+
+                    /* Current thread cannot suspend when the preempt disable flag is non-zero,
+                       return an error.  */
+                    status =  TX_SUSPEND_ERROR;
+                }
+            }
+        }
+
+        /* Determine if the status is still successful.  */
+        if (status == TX_SUCCESS)
+        {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+            /* Increment the thread's suspend count.  */
+            thread_ptr -> tx_thread_performance_suspend_count++;
+
+            /* Increment the total number of thread suspensions.  */
+            _tx_thread_performance_suspend_count++;
+#endif
+
+            /* Set the state to suspended.  */
+            thread_ptr -> tx_thread_state =    TX_SUSPENDED;
+
+            /* Thread state change.  */
+            TX_THREAD_STATE_CHANGE(thread_ptr, TX_SUSPENDED)
+
+            /* Log the thread status change.  */
+            TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+            /* If trace is enabled, save the current event pointer.  */
+            entry_ptr =  _tx_trace_buffer_current_ptr;
+#endif
+
+            /* Log the thread status change.  */
+            TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND, thread_ptr, ((ULONG) thread_ptr -> tx_thread_state), TX_POINTER_TO_ULONG_CONVERT(&priority), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+            /* Save the time stamp for later comparison to verify that
+               the event hasn't been overwritten by the time we have
+               computed the next thread to execute.  */
+            if (entry_ptr != TX_NULL)
+            {
+
+                /* Save time stamp.  */
+                time_stamp =  entry_ptr -> tx_trace_buffer_entry_time_stamp;
+            }
+#endif
+
+            /* Pickup priority of thread.  */
+            priority =  thread_ptr -> tx_thread_priority;
+
+            /* Pickup the previous and next ready thread pointers.  */
+            ready_next =      thread_ptr -> tx_thread_ready_next;
+            ready_previous =  thread_ptr -> tx_thread_ready_previous;
+
+            /* Determine if there are other threads at this priority that are
+               ready.  */
+            if (ready_next != thread_ptr)
+            {
+
+                /* Yes, there are other threads at this priority ready.  */
+
+                /* Just remove this thread from the priority list.  */
+                ready_next -> tx_thread_ready_previous =    ready_previous;
+                ready_previous -> tx_thread_ready_next =    ready_next;
+
+                /* Determine if this is the head of the priority list.  */
+                if (_tx_thread_priority_list[priority] == thread_ptr)
+                {
+
+                    /* Update the head pointer of this priority list.  */
+                    _tx_thread_priority_list[priority] =  ready_next;
+
+#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
+
+#if TX_MAX_PRIORITIES > 32
+
+                    /* Calculate the index into the bit map array.  */
+                    map_index =  priority/((UINT) 32);
+#endif
+
+                    /* Check for a thread preempted that had preemption threshold set.  */
+                    if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
+                    {
+
+                        /* Ensure that this thread's priority is clear in the preempt map.  */
+                        TX_MOD32_BIT_SET(priority, priority_bit)
+                        _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
+
+#if TX_MAX_PRIORITIES > 32
+
+                        /* Determine if there are any other bits set in this preempt map.  */
+                        if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
+                        {
+
+                            /* No, clear the active bit to signify this preempt map has nothing set.  */
+                            TX_DIV32_BIT_SET(priority, priority_bit)
+                            _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
+                        }
+#endif
+                    }
+#endif
+                }
+            }
+            else
+            {
+
+                /* This is the only thread at this priority ready to run.  Set the head
+                   pointer to NULL.  */
+                _tx_thread_priority_list[priority] =    TX_NULL;
+
+#if TX_MAX_PRIORITIES > 32
+
+                /* Calculate the index into the bit map array.  */
+                map_index =  priority/((UINT) 32);
+#endif
+
+                /* Clear this priority bit in the ready priority bit map.  */
+                TX_MOD32_BIT_SET(priority, priority_bit)
+                _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
+
+#if TX_MAX_PRIORITIES > 32
+
+                /* Determine if there are any other bits set in this priority map.  */
+                if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
+                {
+
+                    /* No, clear the active bit to signify this priority map has nothing set.  */
+                    TX_DIV32_BIT_SET(priority, priority_bit)
+                    _tx_thread_priority_map_active =  _tx_thread_priority_map_active & (~(priority_bit));
+                }
+#endif
+
+#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
+
+                /* Check for a thread preempted that had preemption-threshold set.  */
+                if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
+                {
+
+                    /* Ensure that this thread's priority is clear in the preempt map.  */
+                    TX_MOD32_BIT_SET(priority, priority_bit)
+                    _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
+
+#if TX_MAX_PRIORITIES > 32
+
+                    /* Determine if there are any other bits set in this preempt map.  */
+                    if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
+                    {
+
+                        /* No, clear the active bit to signify this preempted map has nothing set.  */
+                        TX_DIV32_BIT_SET(priority, priority_bit)
+                        _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
+                    }
+#endif
+                }
+#endif
+
+#if TX_MAX_PRIORITIES > 32
+
+                /* Calculate the index to find the next highest priority thread ready for execution.  */
+                priority_map =    _tx_thread_priority_map_active;
+
+                /* Determine if there is anything.   */
+                if (priority_map != ((ULONG) 0))
+                {
+
+                    /* Calculate the lowest bit set in the priority map. */
+                    TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
+                }
+
+                /* Calculate the base priority as well.  */
+                base_priority =  map_index * ((UINT) 32);
+#else
+
+                /* Setup the base priority to zero.  */
+                base_priority =   ((UINT) 0);
+#endif
+
+                /* Setup working variable for the priority map.  */
+                priority_map =    _tx_thread_priority_maps[MAP_INDEX];
+
+                /* Make a quick check for no other threads ready for execution.  */
+                if (priority_map == ((ULONG) 0))
+                {
+
+                    /* Nothing else is ready.  Set highest priority and execute thread
+                       accordingly.  */
+                    _tx_thread_highest_priority =  ((UINT) TX_MAX_PRIORITIES);
+                    _tx_thread_execute_ptr =       TX_NULL;
+
+#ifndef TX_MISRA_ENABLE
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+                    /* Check that the event time stamp is unchanged.  A different
+                       timestamp means that a later event wrote over the thread
+                       suspend event. In that case, do nothing here.  */
+                    if (entry_ptr != TX_NULL)
+                    {
+
+                        /* Is the timestamp the same?  */
+                        if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+                        {
+
+                            /* Timestamp is the same, set the "next thread pointer" to the new value of the
+                               next thread to execute. This can be used by the trace analysis tool to keep
+                               track of next thread execution.  */
+                            entry_ptr -> tx_trace_buffer_entry_information_field_4 =  0;
+                        }
+                    }
+#endif
+
+                    /* Restore interrupts.  */
+                    TX_RESTORE
+
+                    /* Determine if preemption should take place. This is only possible if the current thread pointer is
+                       not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
+                    TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
+                    if (combined_flags == ((ULONG) 0))
+                    {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                        /* Yes, increment the return to idle return count.  */
+                        _tx_thread_performance_idle_return_count++;
+#endif
+
+                        /* Preemption is needed - return to the system!  */
+                        _tx_thread_system_return();
+                    }
+
+                    /* Return to caller.  */
+                    return(TX_SUCCESS);
+#endif
+                }
+                else
+                {
+
+                    /* Calculate the lowest bit set in the priority map. */
+                    TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
+
+                    /* Setup the next highest priority variable.  */
+                    _tx_thread_highest_priority =  base_priority + priority_bit;
+                }
+            }
+
+            /* Determine if this thread is the thread designated to execute.  */
+            if (thread_ptr == _tx_thread_execute_ptr)
+            {
+
+                /* Pickup the highest priority thread to execute.  */
+                _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority];
+
+#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
+
+                /* Determine if a previous thread with preemption-threshold was preempted.  */
+#if TX_MAX_PRIORITIES > 32
+                if (_tx_thread_preempted_map_active != ((ULONG) 0))
+#else
+                if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
+#endif
+                {
+
+                    /* Yes, there was a thread preempted when it was using preemption-threshold.  */
+
+#ifndef TX_NOT_INTERRUPTABLE
+
+                    /* Disable preemption.  */
+                    _tx_thread_preempt_disable++;
+
+                    /* Restore interrupts.  */
+                    TX_RESTORE
+
+                    /* Interrupts are enabled briefly here to keep the interrupt
+                       lockout time deterministic.  */
+
+                    /* Disable interrupts again.  */
+                    TX_DISABLE
+
+                    /* Decrement the preemption disable variable.  */
+                    _tx_thread_preempt_disable--;
+#endif
+
+                    /* Calculate the thread with preemption threshold set that
+                       was interrupted by a thread above the preemption level.  */
+
+#if TX_MAX_PRIORITIES > 32
+
+                    /* Calculate the index to find the next highest priority thread ready for execution.  */
+                    priority_map =    _tx_thread_preempted_map_active;
+
+                    /* Calculate the lowest bit set in the priority map. */
+                    TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
+
+                    /* Calculate the base priority as well.  */
+                    base_priority =  map_index * ((UINT) 32);
+#else
+
+                    /* Setup the base priority to zero.  */
+                    base_priority =   ((UINT) 0);
+#endif
+
+                    /* Setup temporary preempted map.  */
+                    priority_map =  _tx_thread_preempted_maps[MAP_INDEX];
+
+                    /* Calculate the lowest bit set in the priority map. */
+                    TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
+
+                    /* Setup the highest priority preempted thread.  */
+                    priority =  base_priority + priority_bit;
+
+                    /* Determine if the next highest priority thread is above the highest priority threshold value.  */
+                    if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold))
+                    {
+
+                        /* Thread not allowed to execute until earlier preempted thread finishes or lowers its
+                           preemption-threshold.  */
+                        _tx_thread_execute_ptr =  _tx_thread_priority_list[priority];
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+                        /* Check that the event time stamp is unchanged.  A different
+                           timestamp means that a later event wrote over the thread
+                           suspend event. In that case, do nothing here.  */
+                        if (entry_ptr != TX_NULL)
+                        {
+
+                            /* Is the timestamp the same?  */
+                            if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+                            {
+
+                                /* Timestamp is the same, set the "next thread pointer" to the new value of the
+                                   next thread to execute. This can be used by the trace analysis tool to keep
+                                   track of next thread execution.  */
+#ifdef TX_MISRA_ENABLE
+                                entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#else
+                                entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#endif
+                            }
+                        }
+#endif
+
+                        /* Clear the corresponding bit in the preempted map, since the preemption has been restored.  */
+                        TX_MOD32_BIT_SET(priority, priority_bit)
+                        _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
+
+#if TX_MAX_PRIORITIES > 32
+
+                        /* Determine if there are any other bits set in this preempt map.  */
+                        if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
+                        {
+
+                            /* No, clear the active bit to signify this preempt map has nothing set.  */
+                            TX_DIV32_BIT_SET(priority, priority_bit)
+                            _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
+                        }
+#endif
+                    }
+                }
+#endif
+
+#ifndef TX_MISRA_ENABLE
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                /* Is the execute pointer different?  */
+                if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
+                {
+
+                    /* Move to next entry.  */
+                    _tx_thread_performance__execute_log_index++;
+
+                    /* Check for wrap condition.  */
+                    if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
+                    {
+
+                        /* Set the index to the beginning.  */
+                        _tx_thread_performance__execute_log_index =  ((UINT) 0);
+                    }
+
+                    /* Log the new execute pointer.  */
+                    _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
+                }
+#endif
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+                /* Check that the event time stamp is unchanged.  A different
+                   timestamp means that a later event wrote over the thread
+                   suspend event. In that case, do nothing here.  */
+                if (entry_ptr != TX_NULL)
+                {
+
+                    /* Is the timestamp the same?  */
+                    if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+                    {
+
+                        /* Timestamp is the same, set the "next thread pointer" to the new value of the
+                           next thread to execute. This can be used by the trace analysis tool to keep
+                           track of next thread execution.  */
+                        entry_ptr -> tx_trace_buffer_entry_information_field_4 =  0;
+                    }
+                }
+#endif
+
+                /* Restore interrupts.  */
+                TX_RESTORE
+
+                /* Determine if preemption should take place. This is only possible if the current thread pointer is
+                   not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
+                TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
+                if (combined_flags == ((ULONG) 0))
+                {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                    /* No, there is another thread ready to run and will be scheduled upon return.  */
+                    _tx_thread_performance_non_idle_return_count++;
+#endif
+
+                    /* Preemption is needed - return to the system!  */
+                    _tx_thread_system_return();
+                }
+
+                /* Return to caller.  */
+                return(TX_SUCCESS);
+#endif
+            }
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+            /* Is the execute pointer different?  */
+            if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
+            {
+
+                /* Move to next entry.  */
+                _tx_thread_performance__execute_log_index++;
+
+                /* Check for wrap condition.  */
+                if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
+                {
+
+                    /* Set the index to the beginning.  */
+                    _tx_thread_performance__execute_log_index =  ((UINT) 0);
+                }
+
+                /* Log the new execute pointer.  */
+                _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
+            }
+#endif
+
+#ifdef TX_ENABLE_EVENT_TRACE
+
+            /* Check that the event time stamp is unchanged.  A different
+               timestamp means that a later event wrote over the thread
+               suspend event. In that case, do nothing here.  */
+            if (entry_ptr != TX_NULL)
+            {
+
+                /* Is the timestamp the same?  */
+                if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
+                {
+
+                    /* Timestamp is the same, set the "next thread pointer" to the new value of the
+                       next thread to execute. This can be used by the trace analysis tool to keep
+                       track of next thread execution.  */
+#ifdef TX_MISRA_ENABLE
+                    entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#else
+                    entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
+#endif
+                }
+            }
+#endif
+
+            /* Restore interrupts.  */
+            TX_RESTORE
+
+            /* Determine if a preemption condition is present.  */
+            if (current_thread != _tx_thread_execute_ptr)
+            {
+
+#ifdef TX_ENABLE_STACK_CHECKING
+
+                /* Pickup the next execute pointer.  */
+                thread_ptr =  _tx_thread_execute_ptr;
+
+                /* Check this thread's stack.  */
+                TX_THREAD_STACK_CHECK(thread_ptr)
+#endif
+
+                /* Determine if preemption should take place. This is only possible if the current thread pointer is
+                   not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
+                TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
+                if (combined_flags == ((ULONG) 0))
+                {
+
+#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
+
+                    /* Determine if an idle system return is present.  */
+                    if (_tx_thread_execute_ptr == TX_NULL)
+                    {
+
+                        /* Yes, increment the return to idle return count.  */
+                        _tx_thread_performance_idle_return_count++;
+                    }
+                    else
+                    {
+
+                        /* No, there is another thread ready to run and will be scheduled upon return.  */
+                        _tx_thread_performance_non_idle_return_count++;
+                    }
+#endif
+
+                    /* Preemption is needed - return to the system!  */
+                    _tx_thread_system_return();
+                }
+            }
+
+            /* Disable interrupts.  */
+            TX_DISABLE
+
+            /* Return success.  */
+            status =  TX_SUCCESS;
+        }
+    }
+    else if (thread_ptr -> tx_thread_state == TX_TERMINATED)
+    {
+
+        /* Thread is terminated.  */
+        status =  TX_SUSPEND_ERROR;
+    }
+    else if (thread_ptr -> tx_thread_state == TX_COMPLETED)
+    {
+
+        /* Thread is completed.  */
+        status =  TX_SUSPEND_ERROR;
+    }
+    else if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
+    {
+
+        /* Already suspended, just set status to success.  */
+        status =  TX_SUCCESS;
+    }
+    else
+    {
+
+        /* Just set the delayed suspension flag.  */
+        thread_ptr -> tx_thread_delayed_suspend =  TX_TRUE;
+
+        /* Set status to success.  */
+        status =  TX_SUCCESS;
+    }
+
+    /* Restore interrupts.  */
+    TX_RESTORE
+
+    /* Return completion status.  */
+    return(status);
+#endif
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_create.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_create.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_create.c	(revision 67)
@@ -0,0 +1,205 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_initialize.h"
+#include "tx_thread.h"
+#include "tx_timer.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _txe_event_flags_create                             PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function checks for errors in the event flag creation function */
+/*    call.                                                               */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to event flags group      */
+/*                                        control block                   */
+/*    name_ptr                          Pointer to event flags name       */
+/*    event_control_block_size          Size of event flags control block */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_GROUP_ERROR                    Invalid event flag group pointer  */
+/*    TX_CALLER_ERROR                   Invalid calling function          */
+/*    status                            Actual completion status          */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_event_flags_create            Actual create function            */
+/*    _tx_thread_system_preempt_check   Check for preemption              */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _txe_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr, UINT event_control_block_size)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+UINT                        status;
+ULONG                       i;
+TX_EVENT_FLAGS_GROUP        *next_group;
+#ifndef TX_TIMER_PROCESS_IN_ISR
+TX_THREAD                   *thread_ptr;
+#endif
+
+
+    /* Default status to success.  */
+    status =  TX_SUCCESS;
+
+    /* Check for an invalid event flags group pointer.  */
+    if (group_ptr == TX_NULL)
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+
+    /* Now check for proper control block size.  */
+    else if (event_control_block_size != (sizeof(TX_EVENT_FLAGS_GROUP)))
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+    else
+    {
+
+        /* Disable interrupts.  */
+        TX_DISABLE
+
+        /* Increment the preempt disable flag.  */
+        _tx_thread_preempt_disable++;
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+
+        /* Next see if it is already in the created list.  */
+        next_group =   _tx_event_flags_created_ptr;
+        for (i = ((ULONG) 0); i < _tx_event_flags_created_count; i++)
+        {
+
+            /* Determine if this group matches the event flags group in the list.  */
+            if (group_ptr == next_group)
+            {
+
+                break;
+            }
+            else
+            {
+
+                /* Move to the next group.  */
+                next_group =  next_group -> tx_event_flags_group_created_next;
+            }
+        }
+
+        /* Disable interrupts.  */
+        TX_DISABLE
+
+        /* Decrement the preempt disable flag.  */
+        _tx_thread_preempt_disable--;
+
+        /* Restore interrupts.  */
+        TX_RESTORE
+
+        /* Check for preemption.  */
+        _tx_thread_system_preempt_check();
+
+        /* At this point, check to see if there is a duplicate event flag group.  */
+        if (group_ptr == next_group)
+        {
+
+            /* Group is already created, return appropriate error code.  */
+            status =  TX_GROUP_ERROR;
+        }
+        else
+        {
+
+#ifndef TX_TIMER_PROCESS_IN_ISR
+
+            /* Pickup thread pointer.  */
+            TX_THREAD_GET_CURRENT(thread_ptr)
+
+            /* Check for invalid caller of this function.  First check for a calling thread.  */
+            if (thread_ptr == &_tx_timer_thread)
+            {
+
+                /* Invalid caller of this function, return appropriate error code.  */
+                status =  TX_CALLER_ERROR;
+            }
+#endif
+
+            /* Check for interrupt call.  */
+            if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
+            {
+
+                /* Now, make sure the call is from an interrupt and not initialization.  */
+                if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
+                {
+
+                    /* Invalid caller of this function, return appropriate error code.  */
+                    status =  TX_CALLER_ERROR;
+                }
+            }
+        }
+    }
+
+    /* Determine if everything is okay.  */
+    if (status == TX_SUCCESS)
+    {
+
+        /* Call actual event flags create function.  */
+        status =  _tx_event_flags_create(group_ptr, name_ptr);
+    }
+
+    /* Return completion status.  */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_get.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_get.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_get.c	(revision 67)
@@ -0,0 +1,179 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_thread.h"
+#include "tx_timer.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _txe_event_flags_get                                PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function checks for errors in the event flags get function     */
+/*    call.                                                               */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to group control block    */
+/*    requested_event_flags             Event flags requested             */
+/*    get_option                        Specifies and/or and clear options*/
+/*    actual_flags_ptr                  Pointer to place the actual flags */
+/*                                        the service retrieved           */
+/*    wait_option                       Suspension option                 */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_GROUP_ERROR                    Invalid event flags group pointer */
+/*    TX_PTR_ERROR                      Invalid actual flags pointer      */
+/*    TX_WAIT_ERROR                     Invalid wait option               */
+/*    TX_OPTION_ERROR                   Invalid get option                */
+/*    TX_CALLER_ERROR                   Invalid caller of this function   */
+/*    status                            Actual completion status          */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_event_flags_get               Actual event flags get function   */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _txe_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags,
+                    UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option)
+{
+
+UINT            status;
+
+#ifndef TX_TIMER_PROCESS_IN_ISR
+TX_THREAD       *current_thread;
+#endif
+
+
+    /* Default status to success.  */
+    status =  TX_SUCCESS;
+
+    /* Check for an invalid event flag group pointer.  */
+    if (group_ptr == TX_NULL)
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+
+    /* Now check for invalid event group ID.  */
+    else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID)
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+
+    /* Check for an invalid destination for actual flags.  */
+    else if (actual_flags_ptr == TX_NULL)
+    {
+
+        /* Null destination pointer, return appropriate error.  */
+        status =  TX_PTR_ERROR;
+    }
+    else
+    {
+
+        /* Check for a wait option error.  Only threads are allowed any form of
+           suspension.  */
+        if (wait_option != TX_NO_WAIT)
+        {
+
+            /* Is the call from an ISR or Initialization?  */
+            if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
+            {
+
+                /* A non-thread is trying to suspend, return appropriate error code.  */
+                status =  TX_WAIT_ERROR;
+            }
+#ifndef TX_TIMER_PROCESS_IN_ISR
+            else
+            {
+
+                /* Pickup thread pointer.  */
+                TX_THREAD_GET_CURRENT(current_thread)
+
+                /* Is the current thread the timer thread?  */
+                if (current_thread == &_tx_timer_thread)
+                {
+
+                    /* A non-thread is trying to suspend, return appropriate error code.  */
+                    status =  TX_WAIT_ERROR;
+                }
+            }
+#endif
+        }
+    }
+
+    /* Is everything still okay?  */
+    if (status == TX_SUCCESS)
+    {
+
+        /* Check for invalid get option.  */
+        if (get_option > TX_AND_CLEAR)
+        {
+
+            /* Invalid get events option, return appropriate error.  */
+            status =  TX_OPTION_ERROR;
+        }
+    }
+
+    /* Determine if everything is okay.  */
+    if (status == TX_SUCCESS)
+    {
+
+        /* Call actual event flags get function.  */
+        status =  _tx_event_flags_get(group_ptr, requested_flags, get_option, actual_flags_ptr, wait_option);
+    }
+
+    /* Return completion status.  */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_set.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_set.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_event_flags_set.c	(revision 67)
@@ -0,0 +1,128 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Event Flags                                                         */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_event_flags.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _txe_event_flags_set                                PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function checks for errors in the set event flags function     */
+/*    call.                                                               */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    group_ptr                         Pointer to group control block    */
+/*    flags_to_set                      Event flags to set                */
+/*    set_option                        Specified either AND or OR        */
+/*                                        operation on the event flags    */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_GROUP_ERROR                    Invalid event flags group pointer */
+/*    TX_OPTION_ERROR                   Invalid set option                */
+/*    status                            Actual completion status          */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_event_flags_set               Actual set event flags function   */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _txe_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option)
+{
+
+UINT        status;
+
+
+    /* Default status to success.  */
+    status =  TX_SUCCESS;
+
+    /* Check for an invalid event flag group pointer.  */
+    if (group_ptr == TX_NULL)
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+
+    /* Now check for invalid event flag group ID.  */
+    else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID)
+    {
+
+        /* Event flags group pointer is invalid, return appropriate error code.  */
+        status =  TX_GROUP_ERROR;
+    }
+    else
+    {
+
+        /* Check for invalid set option.  */
+        if (set_option != TX_AND)
+        {
+
+            if (set_option != TX_OR)
+            {
+
+                /* Invalid set events option, return appropriate error.  */
+                status =  TX_OPTION_ERROR;
+            }
+        }
+    }
+
+    /* Determine if everything is okay.  */
+    if (status == TX_SUCCESS)
+    {
+
+        /* Call actual event flags set function.  */
+        status =  _tx_event_flags_set(group_ptr, flags_to_set, set_option);
+    }
+
+    /* Return completion status.  */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_resume.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_resume.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_resume.c	(revision 67)
@@ -0,0 +1,103 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Thread                                                              */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_thread.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _txe_thread_resume                                  PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function checks for errors in the resume thread function call. */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    thread_ptr                            Pointer to thread to resume   */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_THREAD_ERROR                       Invalid thread pointer        */
+/*    status                                Actual completion status      */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_resume                     Actual thread resume function */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application Code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _txe_thread_resume(TX_THREAD *thread_ptr)
+{
+
+UINT    status;
+
+
+    /* Check for an invalid thread pointer.  */
+    if (thread_ptr == TX_NULL)
+    {
+
+        /* Thread pointer is invalid, return appropriate error code.  */
+        status =  TX_THREAD_ERROR;
+    }
+
+    /* Now check for invalid thread ID.  */
+    else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
+    {
+
+        /* Thread pointer is invalid, return appropriate error code.  */
+        status =  TX_THREAD_ERROR;
+    }
+    else
+    {
+
+        /* Call actual thread resume function.  */
+        status =  _tx_thread_resume(thread_ptr);
+    }
+
+    /* Return completion status.  */
+    return(status);
+}
+
Index: ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_suspend.c
===================================================================
--- ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_suspend.c	(revision 67)
+++ ctrl/firmware/Main/CubeMX/Middlewares/ST/threadx/common/src/txe_thread_suspend.c	(revision 67)
@@ -0,0 +1,105 @@
+/**************************************************************************/
+/*                                                                        */
+/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
+/*                                                                        */
+/*       This software is licensed under the Microsoft Software License   */
+/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
+/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
+/*       and in the root directory of this software.                      */
+/*                                                                        */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**                                                                       */
+/** ThreadX Component                                                     */
+/**                                                                       */
+/**   Thread                                                              */
+/**                                                                       */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+
+/* Include necessary system files.  */
+
+#include "tx_api.h"
+#include "tx_thread.h"
+
+
+/**************************************************************************/
+/*                                                                        */
+/*  FUNCTION                                               RELEASE        */
+/*                                                                        */
+/*    _txe_thread_suspend                                 PORTABLE C      */
+/*                                                           6.1          */
+/*  AUTHOR                                                                */
+/*                                                                        */
+/*    William E. Lamie, Microsoft Corporation                             */
+/*                                                                        */
+/*  DESCRIPTION                                                           */
+/*                                                                        */
+/*    This function checks for errors in the thread suspend function      */
+/*    call.                                                               */
+/*                                                                        */
+/*  INPUT                                                                 */
+/*                                                                        */
+/*    thread_ptr                            Pointer to thread to suspend  */
+/*                                                                        */
+/*  OUTPUT                                                                */
+/*                                                                        */
+/*    TX_THREAD_ERROR                       Invalid thread pointer        */
+/*    TX_CALLER_ERROR                       Invalid caller of function    */
+/*    status                                Actual completion status      */
+/*                                                                        */
+/*  CALLS                                                                 */
+/*                                                                        */
+/*    _tx_thread_suspend                    Actual thread suspension      */
+/*                                                                        */
+/*  CALLED BY                                                             */
+/*                                                                        */
+/*    Application code                                                    */
+/*                                                                        */
+/*  RELEASE HISTORY                                                       */
+/*                                                                        */
+/*    DATE              NAME                      DESCRIPTION             */
+/*                                                                        */
+/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
+/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
+/*                                            resulting in version 6.1    */
+/*                                                                        */
+/**************************************************************************/
+UINT  _txe_thread_suspend(TX_THREAD *thread_ptr)
+{
+
+UINT    status;
+
+
+    /* Check for an invalid thread pointer.  */
+    if (thread_ptr == TX_NULL)
+    {
+
+        /* Thread pointer is invalid, return appropriate error code.  */
+        status =  TX_THREAD_ERROR;
+    }
+
+    /* Now check for invalid thread ID.  */
+    else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
+    {
+
+        /* Thread pointer is invalid, return appropriate error code.  */
+        status =  TX_THREAD_ERROR;
+    }
+    else
+    {
+
+        /* Call actual thread suspend function.  */
+        status =  _tx_thread_suspend(thread_ptr);
+    }
+
+    /* Return completion status.  */
+    return(status);
+}
+
