/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** ThreadX Component                                                     */
/**                                                                       */
/**   Trace                                                               */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

#define TX_SOURCE_CODE


/* Include necessary system files.  */

#include "tx_api.h"
#include "tx_trace.h"


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _tx_trace_object_register                           PORTABLE C      */
/*                                                           6.1.12       */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function registers a ThreadX system object in the trace        */
/*    registry area. This provides a mapping between the object pointers  */
/*    stored in each trace event to the actual ThreadX objects.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    object_type                           Type of system object         */
/*    object_ptr                            Address of system object      */
/*    object_name                           Name of system object         */
/*    parameter_1                           Supplemental parameter 1      */
/*    parameter_2                           Supplemental parameter 2      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/**************************************************************************/
VOID  _tx_trace_object_register(UCHAR object_type, VOID *object_ptr, CHAR *object_name, ULONG parameter_1, ULONG parameter_2)
{

#ifdef TX_ENABLE_EVENT_TRACE

UINT                            i, entries;
UINT                            found, loop_break;
TX_THREAD                       *thread_ptr;
UCHAR                           *work_ptr;
TX_TRACE_OBJECT_ENTRY           *entry_ptr;


    /* Determine if the registry area is setup.  */
    if (_tx_trace_registry_start_ptr != TX_NULL)
    {

        /* Trace buffer is enabled, proceed.  */

        /* Pickup the total entries.  */
        entries =  _tx_trace_total_registry_entries;

        /* Determine if there are available entries in the registry.  */
        if (_tx_trace_available_registry_entries != ((ULONG) 0))
        {

            /* There are more available entries, proceed.  */

            /* Initialize found to the max entries... indicating no space was found.  */
            found =       entries;
            loop_break =  TX_FALSE;

            /* Loop to find available entry.  */
            i =  _tx_trace_registry_search_start;
            do
            {

                /* Setup the registry entry pointer.  */
                work_ptr =   TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr);
                work_ptr =   TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*i));
                entry_ptr =  TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);

                /* Determine if this is the first pass building the registry. A NULL object value indicates this part
                   of the registry has never been used.  */
                if (entry_ptr -> tx_trace_object_entry_thread_pointer == (ULONG) 0)
                {

                    /* Set found to this index and break out of the loop.  */
                    found =  i;
                    loop_break =  TX_TRUE;
                }

                /* Determine if this entry matches the object pointer... we must reuse old entries left in the
                   registry.  */
                if (entry_ptr -> tx_trace_object_entry_thread_pointer == TX_POINTER_TO_ULONG_CONVERT(object_ptr))
                {

                    /* Set found to this index and break out of the loop.  */
                    found =  i;
                    loop_break =  TX_TRUE;
                }

                /* Determine if we should break out of the loop.  */
                if (loop_break == TX_TRUE)
                {

                    /* Yes, break out of the loop.  */
                    break;
                }

                /* Is this entry available?  */
                if (entry_ptr -> tx_trace_object_entry_available == TX_TRUE)
                {

                    /* Yes, determine if we have not already found an empty slot.  */
                    if (found == entries)
                    {
                        found =  i;
                    }
                    else
                    {

                        /* Setup a pointer to the found entry.  */
                        work_ptr =   TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr);
                        work_ptr =   TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*found));
                        entry_ptr =  TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);

                         if (entry_ptr -> tx_trace_object_entry_type != ((UCHAR) 0))
                         {
                            found =  i;
                         }
                    }
                }

                /* Move to the next entry.  */
                i++;

                /* Determine if we have wrapped the list.  */
                if (i >= entries)
                {

                    /* Yes, wrap to the beginning of the list.  */
                    i =  ((ULONG) 0);
                }

            } while (i != _tx_trace_registry_search_start);

            /* Now determine if an empty or reuse entry has been found.  */
            if (found < entries)
            {

                /* Decrement the number of available entries.  */
                _tx_trace_available_registry_entries--;

                /* Adjust the search index to the next entry.  */
                if ((found + ((ULONG) 1)) < entries)
                {

                    /* Start searching from the next index.  */
                    _tx_trace_registry_search_start =  found + ((ULONG) 1);
                }
                else
                {

                    /* Reset the search to the beginning of the list. */
                    _tx_trace_registry_search_start =  ((ULONG) 0);
                }

                /* Yes, an entry has been found...  */

                /* Build a pointer to the found entry.  */
                work_ptr =   TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr);
                work_ptr =   TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*found));
                entry_ptr =  TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);

                /* Populate the found entry!  */
                entry_ptr -> tx_trace_object_entry_available =       ((UCHAR) TX_FALSE);
                entry_ptr -> tx_trace_object_entry_type =            object_type;
                entry_ptr -> tx_trace_object_entry_thread_pointer =  TX_POINTER_TO_ULONG_CONVERT(object_ptr);
                entry_ptr -> tx_trace_object_entry_param_1 =         parameter_1;
                entry_ptr -> tx_trace_object_entry_param_2 =         parameter_2;

                /* Loop to copy the object name string...  */
                for (i = ((ULONG) 0); i < (((ULONG) TX_TRACE_OBJECT_REGISTRY_NAME)-((ULONG) 1)); i++)
                {

                    /* Setup work pointer to the object name character.  */
                    work_ptr =  TX_CHAR_TO_UCHAR_POINTER_CONVERT(object_name);
                    work_ptr =  TX_UCHAR_POINTER_ADD(work_ptr, i);

                    /* Determine if object_name (work_ptr) is null.  */
                    if (work_ptr == TX_NULL)
                    {
                        break;
                    }

                    /* Copy a character of the name.  */
                    entry_ptr -> tx_trace_object_entry_name[i] =  (UCHAR) *work_ptr;

                    /* Determine if we are at the end.  */
                    if (*work_ptr == ((UCHAR) 0))
                    {
                        break;
                    }
                }

                /* Null terminate the object string.  */
                entry_ptr -> tx_trace_object_entry_name[i] =  (UCHAR) 0;

                /* Determine if a thread object type is present.  */
                if (object_type == TX_TRACE_OBJECT_TYPE_THREAD)
                {

                    /* Yes, a thread object is present.  */

                    /* Setup a pointer to the thread.  */
                    thread_ptr =  TX_VOID_TO_THREAD_POINTER_CONVERT(object_ptr);

                    /* Store the thread's priority in the reserved bits.  */
                    entry_ptr -> tx_trace_object_entry_reserved1 =  ((UCHAR) 0x80) | ((UCHAR) (thread_ptr -> tx_thread_priority >> ((UCHAR) 8)));
                    entry_ptr -> tx_trace_object_entry_reserved2 =  (UCHAR) (thread_ptr -> tx_thread_priority & ((UCHAR) 0xFF));
                }
                else
                {

                    /* For all other objects, set the reserved bytes to 0.  */
                    entry_ptr -> tx_trace_object_entry_reserved1 =  ((UCHAR) 0);
                    entry_ptr -> tx_trace_object_entry_reserved2 =  ((UCHAR) 0);
                }
            }
        }
    }
#else

TX_INTERRUPT_SAVE_AREA


    /* Access input arguments just for the sake of lint, MISRA, etc.  */
    if (object_type != ((UCHAR) 0))
    {

        if (object_ptr != TX_NULL)
        {

            if (object_name != TX_NULL)
            {

                if (parameter_1 != ((ULONG) 0))
                {

                    if (parameter_2 != ((ULONG) 0))
                    {

                        /* NOP code.  */
                        TX_DISABLE
                        TX_RESTORE
                    }
                }
            }
        }
    }
#endif
}

