// ******************************************************************************
//
//
//  Version/Date    Comment
//   2026.05.28     - First release
// ******************************************************************************

#include "tm4c129xnczad.h"
#include "utils/ustdlib.h"
#include "utils/uartstdio.h"
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "rtos_hw_drivers.h"

#include <FreeRTOS.h>
#include <task.h>


// For stubs
#include <sys/time.h>
#include <sys/stat.h>


//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
  void __error__(char *pcFilename, uint32_t ui32Line) { }
#endif


void vApplicationStackOverflowHook        ( TaskHandle_t pxTask, char * pcTaskName );
void vApplicationMallocFailedHook         ( void );
void vApplicationIdleHook                 ( void );
void vApplicationTickHook                 ( void );
void TasksNetworking_StartNetworkingTasks ( uint32_t ui32SysClock );


/* Set up the hardware ready to run this demo. */
static uint32_t prvSetupHardware( void );


/*-----------------------------------------------------------*/


int main( void )
{
  uint32_t l_ui32SysClock;
  /* Prepare the hardware to run this demo. */
  l_ui32SysClock = prvSetupHardware();

  TasksNetworking_StartNetworkingTasks( l_ui32SysClock );
  return 0;
}


/*-----------------------------------------------------------*/


static uint32_t prvSetupHardware( void )
{
  SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);
  uint32_t l_ui32SysClock;
  l_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                           SYSCTL_OSC_MAIN |
                                           SYSCTL_USE_PLL |
                                           SYSCTL_CFG_VCO_480), 120000000);
  PinoutSet(true, false);
  UARTStdioConfig(0, 115200, l_ui32SysClock);

  configPRINTF( ("\033[2J\033[H") );
#ifdef FREERTOS_PLUS_TCP
  configPRINTF( ("FreeRTOS plus TCP\n\n") );
#endif
#ifdef FREERTOS_PLUS_LWIP
  #ifdef FREERTOS_PLUS_OPCUA
    configPRINTF( ("FreeRTOS plus LwIp and Opc Ua\n\n") );
  #else
    configPRINTF( ("FreeRTOS plus LwIp\n\n") );
  #endif
#endif
  return l_ui32SysClock;
}


/*-----------------------------------------------------------*/


void vApplicationMallocFailedHook( void )
{
  /* Called if a call to pvPortMalloc() fails because there is insufficient
    * free memory available in the FreeRTOS heap.  pvPortMalloc() is called
    * internally by FreeRTOS API functions that create tasks, queues, software
    * timers, and semaphores.  The size of the FreeRTOS heap is set by the
    * configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
  taskDISABLE_INTERRUPTS();

  for( ; ; )
  {
  }
}


/*-----------------------------------------------------------*/


void vApplicationStackOverflowHook( TaskHandle_t pxTask,
                                    char * pcTaskName )
{
  ( void ) pcTaskName;
  ( void ) pxTask;

  /* Run time stack overflow checking is performed if
    * configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
    * function is called if a stack overflow is detected. */
  taskDISABLE_INTERRUPTS();

  for( ; ; )
  {
  }
}


/*-----------------------------------------------------------*/


void vApplicationIdleHook( void )
{
  /* This is just a trivial example of an idle hook.  It is called on each
    * cycle of the idle task.  It must *NOT* attempt to block.  In this case the
    * idle task just queries the amount of FreeRTOS heap that remains.  See the
    * memory management section on the https://www.FreeRTOS.org web site for memory
    * management options.  If there is a lot of heap memory free then the
    * configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up
    * RAM. */
}


/*-----------------------------------------------------------*/


void vApplicationTickHook( void )
{
}


/*-----------------------------------------------------------*/


void vAssertCalled( void )
{
  volatile unsigned long looping = 0;

  taskENTER_CRITICAL();
  {
    // Use the debugger to set ul to a non-zero value in order to step out
    // of this function to determine why it was called
    while( looping == 0LU )
    {
      portNOP();
    }
  }
  taskEXIT_CRITICAL();
}


/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
 * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
 * used by the Idle task. */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
  /* If the buffers to be provided to the Idle task are declared inside this
  * function then they must be declared static - otherwise they will be allocated on
  * the stack and so not exists after this function exits. */
  static StaticTask_t xIdleTaskTCB;
  static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];

  /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
    * state will be stored. */
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;

  /* Pass out the array that will be used as the Idle task's stack. */
  *ppxIdleTaskStackBuffer = uxIdleTaskStack;

  /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
    * Note that, as the array is necessarily of type StackType_t,
    * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}



#include <string.h>
#include "FreeRTOS.h"

void* __wrap_malloc(size_t size)
{
  return pvPortMalloc(size);
}

void __wrap_free(void *ptr)
{
  vPortFree(ptr);
}

void* __wrap_calloc(size_t nmemb, size_t size)
{
  size_t total_size = nmemb * size;
  void *ptr = pvPortMalloc(total_size);
  if (ptr) {
    memset(ptr, 0, total_size);
  }
  return ptr;
}

void* __wrap_realloc(void *ptr, size_t size)
{
  if (size == 0)
  {
    vPortFree(ptr);
    return NULL;
  }
  if (!ptr)
  {
    return pvPortMalloc(size);
  }

  void *new_ptr = pvPortMalloc(size);
  if (new_ptr)
  {
    // NOTE: heap_4.c doesn't track sizes publicly.
    // For a perfectly safe realloc, we copy up to 'size' bytes.
    // open62541 typically calls realloc to grow arrays.
    memcpy(new_ptr, ptr, size);
    vPortFree(ptr);
  }
  return new_ptr;
}


/*-----------------------------------------------------------*/

// Stubs (without this each will generate a warning about 'warning: XX is not implemented and will always fail')
int _close       (int file)                       { return  -1; }
int _fstat       (int file, void *st)             { return   0; }
int _getpid      (void)                           { return   1; }
int _kill        (pid_t pid, int sig)             { (void)pid; (void)sig; return -1; }
int _isatty      (int file)                       { return   1; }
int _lseek       (int file, int ptr, int dir)     { return   0; }
int _read        (int file, char *ptr, int len)   { return   0; }
int _write       (int file, char *ptr, int len)   { return len; }
int _gettimeofday(struct timeval *tv, void *tzvp) { if (tv) {tv->tv_sec = 0; tv->tv_usec = 0; } return 0; }
int _stat        (char *file, struct stat *st)    { return 0; }


