/***************************************************************************
 * Copyright (C) 2026 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.
 * 
 * AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
 * The AI-generated portions may be considered public domain (CC0-1.0)
 * and not subject to the project's licence. The human contributor has
 * reviewed and verified that the code is correct.
 * 
 * SPDX-License-Identifier: MIT and CC0-1.0
 **************************************************************************/

// Some portions generated by Codex (gpt 5.4).
/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** ThreadX Component                                                     */
/**                                                                       */
/**   Initialize                                                          */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/


#define TX_SOURCE_CODE


/* Include necessary system files.  */

#include "tx_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma comment (lib, "Winmm.lib")

/* Define various Win32 objects used by the ThreadX port.  */

TX_WIN32_CRITICAL_SECTION       _tx_win32_critical_section;
HANDLE                          _tx_win32_scheduler_semaphore;
HANDLE                          _tx_win32_scheduler_wake_event;
DWORD                           _tx_win32_scheduler_id;
ULONG                           _tx_win32_global_int_disabled_flag;
LARGE_INTEGER                   _tx_win32_time_stamp;
ULONG                           _tx_win32_system_error;
HANDLE                          _tx_win32_timer_handle;
HANDLE                          _tx_win32_timer_thread_handle;
HANDLE                          _tx_win32_isr_semaphore;
UINT                            _tx_win32_timer_waiting;
extern TX_THREAD                *_tx_thread_current_ptr;


/* Define simulated timer interrupt.  This is done inside a thread, which is
   how other interrupts may be defined as well.  See code below for an
   example.  */

UINT                            _tx_win32_timer_id;
VOID CALLBACK                   _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
static VOID                     _tx_win32_timer_start(VOID);
static DWORD WINAPI             _tx_win32_timer_thread_entry(LPVOID thread_input);


#ifdef TX_WIN32_DEBUG_ENABLE

extern ULONG                    _tx_thread_system_state;
extern UINT                     _tx_thread_preempt_disable;
extern TX_THREAD                *_tx_thread_current_ptr;
extern TX_THREAD                *_tx_thread_execute_ptr;


/* Define the maximum size of the Win32 debug array.  */

#ifndef TX_WIN32_DEBUG_EVENT_SIZE
#define TX_WIN32_DEBUG_EVENT_SIZE           400
#endif


/* Define debug log in order to debug Win32 issues with this port.  */

typedef struct TX_WIN32_DEBUG_ENTRY_STRUCT
{
    char                                    *tx_win32_debug_entry_action;
    LARGE_INTEGER                           tx_win32_debug_entry_timestamp;
    char                                    *tx_win32_debug_entry_file;
    unsigned long                           tx_win32_debug_entry_line;
    TX_WIN32_CRITICAL_SECTION               tx_win32_debug_entry_critical_section;
    unsigned long                           tx_win32_debug_entry_int_disabled_flag;
    ULONG                                   tx_win32_debug_entry_system_state;
    UINT                                    tx_win32_debug_entry_preempt_disable;
    TX_THREAD                               *tx_win32_debug_entry_current_thread;
    DWORD                                   tx_win32_debug_entry_current_thread_id;
    TX_THREAD                               *tx_win32_debug_entry_execute_thread;
    DWORD                                   tx_win32_debug_entry_execute_thread_id;
    DWORD                                   tx_win32_debug_entry_running_id;
} TX_WIN32_DEBUG_ENTRY;


/* Define the circular array of Win32 debug entries.  */

TX_WIN32_DEBUG_ENTRY    _tx_win32_debug_entry_array[TX_WIN32_DEBUG_EVENT_SIZE];


/* Define the Win32 debug index.  */

unsigned long           _tx_win32_debug_entry_index =  0;


/* Now define the debug entry function.  */
void    _tx_win32_debug_entry_insert(char *action, char *file, unsigned long line)
{


    /* Get the time stamp.  */
    QueryPerformanceCounter((LARGE_INTEGER *)&_tx_win32_time_stamp);

    /* Setup the debug entry.  */
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_action =             action;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_timestamp =          _tx_win32_time_stamp;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_file =               file;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_line =               line;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_critical_section =   _tx_win32_critical_section;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_int_disabled_flag =  _tx_win32_global_int_disabled_flag;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_system_state =       _tx_thread_system_state;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_preempt_disable =    _tx_thread_preempt_disable;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread =     _tx_thread_current_ptr;
    if (_tx_thread_current_ptr)
        _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id =  _tx_thread_current_ptr -> tx_thread_win32_thread_id;
    else
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id =  0;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread =     _tx_thread_execute_ptr;
    if (_tx_thread_execute_ptr)
        _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id =  _tx_thread_execute_ptr -> tx_thread_win32_thread_id;
    else
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id =  0;
    _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_running_id =         GetCurrentThreadId();

    /* Now move to the next entry.  */
    _tx_win32_debug_entry_index++;

    /* Determine if we need to wrap the list.  */
    if (_tx_win32_debug_entry_index >= TX_WIN32_DEBUG_EVENT_SIZE)
    {

        /* Yes, wrap the list!  */
        _tx_win32_debug_entry_index =  0;
    }
}

#endif


/* Define the ThreadX timer interrupt handler.  */

void            _tx_timer_interrupt(void);


/* Define other external function references.  */

VOID            _tx_initialize_low_level(VOID);
VOID            _tx_thread_context_save(VOID);
VOID            _tx_thread_context_restore(VOID);
VOID            _tx_win32_scheduler_wake(VOID);


/* Define other external variable references.  */

extern VOID     *_tx_initialize_unused_memory;


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _tx_initialize_low_level                          Win64/MSVC      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function is responsible for any low-level processor            */
/*    initialization, including setting up interrupt vectors, setting     */
/*    up a periodic timer interrupt source, saving the system stack       */
/*    pointer for use in ISR processing later, and finding the first      */
/*    available RAM memory address for tx_application_define.             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    CreateMutex                           Win32 create mutex            */
/*    CreateThread                          Win32 create thread           */
/*    CreateSemaphore                       Win32 create semaphore        */
/*    GetCurrentThreadId                    Win32 get current thread ID   */
/*    SetProcessAffinityMask                Win32 process affinity set    */
/*    SetThreadPriority                     Win32 set thread priority     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _tx_initialize_kernel_enter           ThreadX entry function        */
/*                                                                        */
/**************************************************************************/
VOID   _tx_initialize_low_level(VOID)
{

/* Deprecate TX_WIN32_MULTI_CORE build option and default to restricting
   execution to one core.  */

#ifndef TX_WIN32_BYPASS_AFFINITY_SETUP

    /* Limit this ThreadX simulation on Win64 to a single core.  */
    if (SetProcessAffinityMask(GetCurrentProcess(), ((DWORD_PTR) 1)) == 0)
    {

        /* Error restricting the process to one core.  */
        printf("ThreadX Win64 error restricting the process to one core!\n");
        while(1)
        {
        }
    }
#endif

    /* Pickup the first available memory address.  */

    /* Save the first available memory address.  */
    _tx_initialize_unused_memory =  malloc(TX_WIN32_MEMORY_SIZE);

    /* Pickup the unique Id of the current thread, which will also be the Id of the scheduler.  */
    _tx_win32_scheduler_id =        GetCurrentThreadId();

    /* Create the system critical section mutex. This is used by the system to block all other access,
       analogous to an interrupt lockout on an embedded target.  */
    _tx_win32_critical_section.tx_win32_critical_section_mutex_handle =  CreateMutex(NULL, FALSE, NULL);
    _tx_win32_critical_section.tx_win32_critical_section_nested_count =  0;
    _tx_win32_critical_section.tx_win32_critical_section_owner =         0;
    if (_tx_win32_critical_section.tx_win32_critical_section_mutex_handle == NULL)
    {
        printf("ThreadX Win64 error creating critical section mutex!\n");
        while(1)
        {
        }
    }

    /* Create the semaphore that regulates when the scheduler executes.  */
    _tx_win32_scheduler_semaphore =  CreateSemaphore(NULL, 0, 1, NULL);
    _tx_win32_isr_semaphore =        CreateSemaphore(NULL, 0, 1, NULL);
    if ((_tx_win32_scheduler_semaphore == NULL) || (_tx_win32_isr_semaphore == NULL))
    {
        printf("ThreadX Win64 error creating semaphores!\n");
        while(1)
        {
        }
    }

    /* Create the event that wakes the scheduler whenever the ready state changes.  */
    _tx_win32_scheduler_wake_event =  CreateEvent(NULL, FALSE, FALSE, NULL);
    if (_tx_win32_scheduler_wake_event == NULL)
    {
        printf("ThreadX Win64 error creating scheduler wake event!\n");
        while(1)
        {
        }
    }

    /* Initialize the global interrupt disabled flag.  */
    _tx_win32_global_int_disabled_flag =  TX_FALSE;
    _tx_win32_timer_waiting =             TX_FALSE;

    /* Done, return to caller.  */
}


/* This routine is called after initialization is complete in order to start
   all interrupt threads.  Interrupt threads in addition to the timer may
   be added to this routine as well.  */

void _tx_initialize_start_interrupts(void)
{
    TIMECAPS tc;
    UINT     wTimerRes;

    /* Queries the timer device to determine its resolution.  */
    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
    {
        /* Error; application can't continue. */
        printf("Query timer device error.");
        while (1)
        {
        }
    }

    wTimerRes = min(max(tc.wPeriodMin, TX_TIMER_PERIODIC), tc.wPeriodMax);

    /* Request the best available timer resolution for the simulation.  */
    if (timeBeginPeriod(wTimerRes) != TIMERR_NOERROR)
    {
        printf("ThreadX Win64 error configuring timer resolution!\n");
        while (1)
        {
        }
    }

    /* Create the periodic waitable timer used to drive simulated interrupts.  */
#if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0)
    _tx_win32_timer_handle =  CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
    if (_tx_win32_timer_handle == NULL)
#endif
    {
        _tx_win32_timer_handle =  CreateWaitableTimer(NULL, FALSE, NULL);
    }

    if (_tx_win32_timer_handle == NULL)
    {
        printf("ThreadX Win64 error creating timer handle!\n");
        while (1)
        {
        }
    }

    /* Create the timer thread so interrupts are serialized through one execution context.  */
    _tx_win32_timer_thread_handle =  CreateThread(NULL, 0, _tx_win32_timer_thread_entry, NULL, 0, NULL);
    if (_tx_win32_timer_thread_handle == NULL)
    {
        printf("ThreadX Win64 error creating timer thread!\n");
        while (1)
        {
        }
    }

    SetThreadPriority(_tx_win32_timer_thread_handle, THREAD_PRIORITY_HIGHEST);

    _tx_win32_timer_id =  1;

    /* Start the first simulated tick.  */
    _tx_win32_timer_start();
}

/* Define the ThreadX system timer interrupt.  Other interrupts may be simulated
   in a similar way.  */

VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
    TX_PARAMETER_NOT_USED(wTimerID);
    TX_PARAMETER_NOT_USED(msg);
    TX_PARAMETER_NOT_USED(dwUser);
    TX_PARAMETER_NOT_USED(dw1);
    TX_PARAMETER_NOT_USED(dw2);

    /* Call ThreadX context save for interrupt preparation.  */
    _tx_thread_context_save();

    /* Call the ThreadX system timer interrupt processing.  */
    _tx_timer_interrupt();

    /* Call ThreadX context restore for interrupt completion.  */
    _tx_thread_context_restore();

    /* Wake the scheduler so it can promptly observe timer-driven work.  */
    _tx_win32_scheduler_wake();
}


static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input)
{
    TX_PARAMETER_NOT_USED(thread_input);

    /* Drive periodic simulated interrupts from a single thread.  */
    while (1)
    {
        WaitForSingleObject(_tx_win32_timer_handle, INFINITE);
        _tx_win32_timer_interrupt(0, 0, 0, 0, 0);
        _tx_win32_timer_start();
    }
}


VOID   _tx_win32_scheduler_wake(VOID)
{

    /* Wake the scheduler if it is waiting for a state change.  */
    if (_tx_win32_scheduler_wake_event != NULL)
    {
        SetEvent(_tx_win32_scheduler_wake_event);
    }
}


static VOID  _tx_win32_timer_start(VOID)
{

LARGE_INTEGER   due_time;


    /* Rearm the host timer relative to "now" to avoid burst catch-up ticks.  */
    due_time.QuadPart =  -(((LONGLONG) TX_TIMER_PERIODIC) * 10000LL);
#if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0)
    if (SetWaitableTimerEx(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, NULL, 0) == 0)
#else
    if (SetWaitableTimer(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, FALSE) == 0)
#endif
    {
        printf("ThreadX Win64 error starting timer!\n");
        while (1)
        {
        }
    }
}

