text: /*
   * FreeRTOS V202111.00
   * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of
   * this software and associated documentation files (the "Software"), to deal in
   * the Software without restriction, including without limitation the rights to
   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   * the Software, and to permit persons to whom the Software is furnished to do so,
   * subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   * https://www.FreeRTOS.org
   * https://github.com/FreeRTOS
   *
   */
  
  /***
   * See https://www.FreeRTOS.org/coresntp for configuration and usage instructions,
   ***/
  
  /* Standard includes. */
  #include <stdio.h>
  #include <time.h>
  
  /* Visual studio intrinsics used so the __debugbreak() function is available
   * should an assert get hit. */
  #include <intrin.h>
  
  /* FreeRTOS includes. */
  #include <FreeRTOS.h>
  #include "task.h"
  
  /* TCP/IP stack includes. */
  #include "FreeRTOS_IP.h"
  #include "FreeRTOS_Sockets.h"
  
  /* Demo logging includes. */
  #include "logging.h"
  
  /* mbedTLS include for configuring
   * threading functions. */
  #include "mbedtls/threading.h"
  #include "threading_alt.h"
  
  /* Demo Specific configs. */
  #include "demo_config.h"
  #include "common_demo_include.h"
  
  /*
   * Prototypes for the demos that can be started from this project.  Note the
   * SNTP demo is not actually started until the network is already, which is
   * indicated by vApplicationIPNetworkEventHook() executing - hence
   * prvStartSimpleSNTPDemo() is called from inside vApplicationIPNetworkEventHook().
   */
  static void vStartSntpDemo( void );
  
  /*
   * Just seeds the simple pseudo random number generator.
   *
   * !!! NOTE !!!
   * This is not a secure method of generating random numbers and production
   * devices should use a true random number generator (TRNG).
   */
  static void prvSRand( UBaseType_t ulSeed );
  
  /*
   * Miscellaneous initialization including preparing the logging and seeding the
   * random number generator.
   */
  static void prvMiscInitialisation( void );
  
  /* The default IP and MAC address used by the demo.  The address configuration
   * defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is
   * 1 but a DHCP server could not be contacted.  See the online documentation for
   * more information. */
  static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 };
  static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 };
  static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 };
  static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 };
  
  /* Set the following constant to pdTRUE to log using the method indicated by the
   * name of the constant, or pdFALSE to not log using the method indicated by the
   * name of the constant.  Options include to standard out (xLogToStdout), to a disk
   * file (xLogToFile), and to a UDP port (xLogToUDP).  If xLogToUDP is set to pdTRUE
   * then UDP messages are sent to the IP address configured as the UDP logging server
   * address (see the configUDP_LOGGING_ADDR0 definitions in FreeRTOSConfig.h) and
   * the port number set by configPRINT_PORT in FreeRTOSConfig.h. */
  const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE;
  
  /* Default MAC address configuration.  The demo creates a virtual network
   * connection that uses this MAC address by accessing the raw Ethernet data
   * to and from a real network connection on the host PC.  See the
   * configNETWORK_INTERFACE_TO_USE definition for information on how to configure
   * the real network connection to use. */
  const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
  
  /* Use by the pseudo random number generator. */
  static UBaseType_t ulNextRand;
  /*-----------------------------------------------------------*/
  
  int main( void )
  {
      /***
       * See https://www.FreeRTOS.org/coresntp for configuration and usage instructions.
       *
       ***/
  
      /* Miscellaneous initialization including preparing the logging and seeding
       * the random number generator. */
      prvMiscInitialisation();
  
      /* Initialize the network interface.
       *
       ***NOTE*** Tasks that use the network are created in the network event hook
       * when the network is connected and ready for use (see the implementation of
       * vApplicationIPNetworkEventHook() below).  The address values passed in here
       * are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1
       * but a DHCP server cannot be contacted. */
      FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
  
      /* Start the RTOS scheduler. */
      vTaskStartScheduler();
  
      /* If all is well, the scheduler will now be running, and the following
       * line will never be reached.  If the following line does execute, then
       * there was insufficient FreeRTOS heap memory available for the idle and/or
       * timer tasks to be created.  See the memory management section on the
       * FreeRTOS web site for more details (this is standard text that is not
       * really applicable to the Win32 simulator port). */
      for( ; ; )
      {
          __debugbreak();
      }
  }
  /*-----------------------------------------------------------*/
  
  /**
   * @brief Entry point of the demo that creates 2 tasks:
   * 1. One task represents the SNTP client that periodically synchronizes system time with
   * time from time servers.
   * 2. The other task represents a sample application time that queries the system time
   * periodically and prints it in human readable form of the YYYY-MM-DD hh:mm:ss.
   */
  void vStartSntpDemo( void )
  {
      initializeSystemClock();
  
      /* Configure mbedTLS to use FreeRTOS specific threading function. */
      mbedtls_threading_set_alt( mbedtls_platform_mutex_init,
                                 mbedtls_platform_mutex_free,
                                 mbedtls_platform_mutex_lock,
                                 mbedtls_platform_mutex_unlock );
  
      /* Create the SNTP client task that is responsible for synchronizing system time with the time servers
       * periodically. This is created as a high priority task to keep the SNTP client operation unhindered. */
      xTaskCreate( sntpTask,                 /* Function that implements the task. */
                   "SntpClientTask",         /* Text name for the task - only used for debugging. */
                   democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */
                   NULL,                     /* Task parameter - not used in this case. */
                   configMAX_PRIORITIES - 1, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */
                   NULL );
  
      /* Create the task that represents an application needing wall-clock time. */
      xTaskCreate( sampleAppTask,            /* Function that implements the task. */
                   "SampleAppTask",              /* Text name for the task - only used for debugging. */
                   democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */
                   NULL,                     /* Task parameter - not used in this case. */
                   tskIDLE_PRIORITY,         /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */
                   NULL );                   /* Used to pass out a handle to the created task - not used in this case. */
  }
  
  /*-----------------------------------------------------------*/
  
  /* Called by FreeRTOS+TCP when the network connects or disconnects.  Disconnect
   * events are only received if implemented in the MAC driver. */
  void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
  {
      uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
      char cBuffer[ 16 ];
      static BaseType_t xTasksAlreadyCreated = pdFALSE;
  
      /* If the network has just come up...*/
      if( eNetworkEvent == eNetworkUp )
      {
          /* Create the tasks that use the IP stack if they have not already been
           * created. */
          if( xTasksAlreadyCreated == pdFALSE )
          {
              /* Demos that use the network are created after the network is
               * up. */
              LogInfo( ( "---------STARTING DEMO---------\r\n" ) );
              vStartSntpDemo();
              xTasksAlreadyCreated = pdTRUE;
          }
  
          /* Print out the network configuration, which may have come from a DHCP
           * server. */
          FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress );
          FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
          LogInfo( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );
  
          FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
          LogInfo( ( "Subnet Mask: %s\r\n", cBuffer ) );
  
          FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
          LogInfo( ( "Gateway Address: %s\r\n", cBuffer ) );
  
          FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
          LogInfo( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) );
      }
  }
  /*-----------------------------------------------------------*/
  
  void vAssertCalled( const char * pcFile,
                      uint32_t ulLine )
  {
      volatile uint32_t ulBlockVariable = 0UL;
      volatile char * pcFileName = ( volatile char * ) pcFile;
      volatile uint32_t ulLineNumber = ulLine;
  
      ( void ) pcFileName;
      ( void ) ulLineNumber;
  
      printf( "vAssertCalled( %s, %u\n", pcFile, ulLine );
  
      /* Setting ulBlockVariable to a non-zero value in the debugger will allow
       * this function to be exited. */
      taskDISABLE_INTERRUPTS();
      {
          while( ulBlockVariable == 0UL )
          {
              __debugbreak();
          }
      }
      taskENABLE_INTERRUPTS();
  }
  /*-----------------------------------------------------------*/
  
  UBaseType_t uxRand( void )
  {
      const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
  
      /*
       * Utility function to generate a pseudo random number.
       *
       * !!!NOTE!!!
       * This is not a secure method of generating a random number.  Production
       * devices should use a True Random Number Generator (TRNG).
       */
      ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
      return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
  }
  /*-----------------------------------------------------------*/
  
  static void prvSRand( UBaseType_t ulSeed )
  {
      /* Utility function to seed the pseudo random number generator. */
      ulNextRand = ulSeed;
  }
  /*-----------------------------------------------------------*/
  
  static void prvMiscInitialisation( void )
  {
      time_t xTimeNow;
      uint32_t ulLoggingIPAddress;
  
      ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configUDP_LOGGING_ADDR0, configUDP_LOGGING_ADDR1, configUDP_LOGGING_ADDR2, configUDP_LOGGING_ADDR3 );
      vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT );
  
      /*
       * Seed random number generator.
       *
       * !!!NOTE!!!
       * This is not a secure method of generating a random number.  Production
       * devices should use a True Random Number Generator (TRNG).
       */
      time( &xTimeNow );
      LogDebug( ( "Seed for randomizer: %lu\n", xTimeNow ) );
      prvSRand( ( uint32_t ) xTimeNow );
      LogDebug( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) );
  }
  /*-----------------------------------------------------------*/
  
  #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
  
      const char * pcApplicationHostnameHook( void )
      {
          /* Assign the name "FreeRTOS" to this network node.  This function will
           * be called during the DHCP: the machine will be registered with an IP
           * address plus this name. */
          return mainHOST_NAME;
      }
  
  #endif
  /*-----------------------------------------------------------*/
  
  #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 )
  
      BaseType_t xApplicationDNSQueryHook( const char * pcName )
      {
          BaseType_t xReturn;
  
          /* Determine if a name lookup is for this node.  Two names are given
           * to this node: that returned by pcApplicationHostnameHook() and that set
           * by mainDEVICE_NICK_NAME. */
          if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 )
          {
              xReturn = pdPASS;
          }
          else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 )
          {
              xReturn = pdPASS;
          }
          else
          {
              xReturn = pdFAIL;
          }
  
          return xReturn;
      }
  
  #endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */
  /*-----------------------------------------------------------*/
  
  /*
   * Callback that provides the inputs necessary to generate a randomized TCP
   * Initial Sequence Number per RFC 6528.  THIS IS ONLY A DUMMY IMPLEMENTATION
   * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION
   * SYSTEMS.
   */
  extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
                                                      uint16_t usSourcePort,
                                                      uint32_t ulDestinationAddress,
                                                      uint16_t usDestinationPort )
  {
      ( void ) ulSourceAddress;
      ( void ) usSourcePort;
      ( void ) ulDestinationAddress;
      ( void ) usDestinationPort;
  
      return uxRand();
  }
  /*-----------------------------------------------------------*/
  
  /*
   * Set *pulNumber to a random number, and return pdTRUE. When the random number
   * generator is broken, it shall return pdFALSE.
   * The macros ipconfigRAND32() and configRAND32() are not in use
   * anymore in FreeRTOS+TCP.
   *
   * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER SO IS
   * NOT INTENDED FOR USE IN PRODUCTION SYSTEMS.
   */
  BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber )
  {
      *pulNumber = uxRand();
      return pdTRUE;
  }
  /*-----------------------------------------------------------*/
  
  /* 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;
  }
  /*-----------------------------------------------------------*/
  
  /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
   * application must provide an implementation of vApplicationGetTimerTaskMemory()
   * to provide the memory that is used by the Timer service task. */
  void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                       StackType_t ** ppxTimerTaskStackBuffer,
                                       uint32_t * pulTimerTaskStackSize )
  {
      /* If the buffers to be provided to the Timer 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 xTimerTaskTCB;
      static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
  
      /* Pass out a pointer to the StaticTask_t structure in which the Timer
       * task's state will be stored. */
      *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
  
      /* Pass out the array that will be used as the Timer task's stack. */
      *ppxTimerTaskStackBuffer = uxTimerTaskStack;
  
      /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
       * Note that, as the array is necessarily of type StackType_t,
       * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
      *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
  }
  /*-----------------------------------------------------------*/
  