This demonstration provides:
, FreeRTOS  (FreeRTOSv202406.04-LTS)

The usage of two different ethernet stacks, using sockets
. Selectable by define
  . LWIP 2.2.1
    . Lwip-tiva specifics port
      Based on https://github.com/alairjunior/lwip-tiva:
      . Making sure ethernet priority is set higher than RTOS

  . FreeRTOS-Plus-TCP (**)

. MbedTls 3.6.6 (used by open62541)
  . Using hardware AES/SHA256 processing
    Can be set to software handling by commenting out:
      #define MBEDTLS_AES_ALT
      #define MBEDTLS_AES_SETKEY_ENC_ALT
      #define MBEDTLS_AES_SETKEY_DEC_ALT
      #define MBEDTLS_SHA256_ALT

. Open62541 (Opc UA)


The demonstration provides the following services:
. Ping (ICMP), integrated functionality of the ethernet stacks
. Very basic web server on port 80
. Locator server on port 23
. OpcUa on port 4840
  . Provides a single ADC endpoint
  . Authentication:
    User    : admin
    Password: admin


-------------------------------------------------------------------------

Files/directories:

README.TXT                          This file


/.vscode                            Visual Studio Code settings
                                    Note: Some setting contain hardcoded path/file
                                          references and need to be adjusted accordingly
/_obj                               Intermediate compilation files (can be discarded)
/bin                                Target directory for compile images
/driverlib                          Tiva source files
/drivers                            Board specific source files
/inc                                Tiva source files
/project                            Project source files
  /certificates                     Generated certificates and certificate source files
  /open62541                        Open62541 generated files/configuration
/third_party                        Third party souce code
  /FreeRTOS                         FreeRTOS
  /FreeRTOS-Plus-TCP                FreeRTOS ethernet stack
  /lwip                             LwIp ethernet stack
  /lwip-contrib                     Tiva specific LwIp port part
  /mbedtls                          MbedTls (used by open62541)
  /open62541                        Opc Ua
    /build                          Generated source files
    /CMakeLists.txt                 Modified source file (disable Lwip/FreeRTOS checks)
    /src/server/ua_server_binary.c  Modified source file (timestamp synchronization)
    /arch/freertos/clock_freertos.c Modified source file (timestamp synchronization)
/utils                              Tiva source files


Generate_Certificate.sh             Generates a new certificate (results under ./project/certificates)
makedefs                            Make file include file
Makefile                            Make file


Make_Clean_All.bat                  Helper script
Make_Clean_All_LwIp.bat             Helper script
Make_Clean_All_LwIp_OpcUa.bat       Helper script
Make_Clean_All_LwIp_OpcUa.sh        Helper script
Make_Clean_All_LwIp.sh              Helper script
Make_Clean_All.sh                   Helper script
Make_Clean_Debug.bat                Helper script
Make_Clean_Debug_LwIp.bat           Helper script
Make_Clean_Debug_LwIp_OpcUa.bat     Helper script
Make_Clean_Debug_LwIp_OpcUa.sh      Helper script
Make_Clean_Debug_LwIp.sh            Helper script
Make_Clean_Debug.sh                 Helper script


Check_Files.sh                      Additional helper script
Check_Same_Names.sh                 Additional helper script
Check_Subdirectories.sh             Additional helper script
Check_UsedUnusedFiles.py/sh         Additional helper script



-------------------------------------------------------------------------


Use 'Generate_Certificate.sh' to generate new certicates (assumes some tools are
present on the host system)
Note that the generated certificate has no (valid) host name, which can trigger
a warning/error by clients


 (**)  When using OpcUa (open62541), only LwIp is supported
 (***) For open62541 we need to generate the supporting files
       and make some modifications
       Linux:
        > cd ./project/open62541
        > rm -rf build
        > mkdir build
        > cd build

        We need to disable LWIP and FreeRTOS checks
        > nano ../../../third_party/open62541/CMakeLists.txt
        Find the 'if(UA_ARCHITECTURE_LWIP)'     block and comment out all code there:
          if(UA_ARCHITECTURE_LWIP)
              # Assume lwip is provided as a library.
              # Directly include the source files here if required.
              #
              # Example settings (POSIX Port):
              # LWIP_INCLUDE_DIRS ../lwip/contrib/ports/unix/port/include;
              #                   ../lwip/contrib/ports/unix/posixlib;
              #                   ../lwip/contrib/ports/unix/posixlib/include;
              #                   ../lwip/src/include
              # LWIP_LIBRARIES    ../lwip/contrib/ports/unix/lib/build/liblwip.so
          #    find_package(LWIP REQUIRED)
          #    list(APPEND open62541_LIBRARIES ${LWIP_LIBRARIES})
          endif()

        Find the 'if(UA_ARCHITECTURE_FREERTOS)' block and comment out all code there:
          if(UA_ARCHITECTURE_FREERTOS)
              # Assume the FreeRTOS POSIX "Simulator".
              # Change this to directly include the source files if required.
          #    set(FREERTOS_KERNEL_PATH "~/software/FreeRTOSv202411.00/FreeRTOS/Source" CACHE STRING "")
          #    set(FREERTOS_PORT_PATH "~/software/FreeRTOSv202411.00/FreeRTOS/Demo/Posix_GCC" CACHE STRING "")
          #    include(arch/freertos/freertos.cmake)
          #    include_directories(${FREERTOS_PORT_PATH} "${FREERTOS_KERNEL_PATH}/include")
          #    include_directories("${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/Posix")
          #    add_compile_definitions(projCOVERAGE_TEST=0)
          #    add_compile_definitions(projENABLE_TRACING=0)
          #    list(APPEND open62541_LIBRARIES freertos_config freertos_kernel)
          endif()

        > cmake -DUA_ARCHITECTURE=freertos-lwip ../../../third_party/open62541/
        > cmake --build . --target open62541-code-generation
        > rm -rf bin CMakeFiles doc doc_src
        > rm * 2>/dev/null

       Windows (command prompt):
        > cd .\project\open62541
        > rmdir build
        > mkdir build
        > cd build
        > set PATH=..\..\..\..\..\Tools\Compiler\cmake-windows\bin;..\..\..\..\..\Tools\Compiler\python-windows
        > set "PWD=%cd%"
        > set "PWD=%PWD:\=/%"

        We need to 'hardcode' the path to the node compiler
        > echo python314.zip > ..\..\..\..\..\Tools\Compiler\python-windows\python314._pth
        > echo . >> ..\..\..\..\..\Tools\Compiler\python-windows\python314._pth
        > echo. >> ..\..\..\..\..\Tools\Compiler\python-windows\python314._pth
        > echo %PWD%/../../../third_party/open62541/tools >> ..\..\..\..\..\Tools\Compiler\python-windows\python314._pth
        > echo %PWD%/../../../third_party/open62541/tools/nodeset_compiler >> ..\..\..\..\..\Tools\Compiler\python-windows\python314._pth

        > edit ..\..\..\third_party\open62541\CMakeLists.txt
        Find the 'if(UA_ARCHITECTURE_LWIP)'     block and comment out all code there
          See Linux part
        Find the 'if(UA_ARCHITECTURE_FREERTOS)' block and comment out all code there
          See Linux part

        > cmake -G "MinGW Makefiles" ^
                -DCMAKE_SYSTEM_NAME=Generic ^
                -DCMAKE_TRY_COMPILE_TARGET_TYPE="STATIC_LIBRARY" ^
                -DUA_ARCHITECTURE=freertos-lwip ^
                -DCMAKE_C_COMPILER="%PWD%/../../../../../Tools/Compiler/arm-none-eabi-windows/bin/arm-none-eabi-gcc.exe" ^
                -DCMAKE_MAKE_PROGRAM="%PWD%/../../../../../Tools/Compiler/gnumake-4.3-x64.exe" ^
                ../../../third_party/open62541/
        > cmake --build . --target open62541-code-generation
        > rmdir /s /q bin CMakeFiles doc doc_src
        > del /q *


        The following changes were made to the config.h file afterwards (see current config.h
        file for the latest changes):

          #ifndef UA_LOGLEVEL /* allows overriding UA_LOGLEVEL from an external Makefile */
            #ifdef DEBUG
              #define UA_LOGLEVEL 100
            #else
              #define UA_LOGLEVEL 700
            #endif
          #endif
          /* #undef UA_ENABLE_AMALGAMATION */
          /* #undef UA_ENABLE_METHODCALLS */
          /* #undef UA_ENABLE_NODEMANAGEMENT */
          #define UA_ENABLE_SUBSCRIPTIONS
          /* #undef UA_ENABLE_PUBSUB */
          /* #undef UA_ENABLE_PUBSUB_FILE_CONFIG */
          /* #undef UA_ENABLE_PUBSUB_INFORMATIONMODEL */
          /* #undef #define UA_ENABLE_DA */
          /* #undef UA_ENABLE_DIAGNOSTICS */
          /* #undef UA_ENABLE_HISTORIZING */
          /* #undef UA_ENABLE_SUBSCRIPTIONS_EVENTS */
          /* #undef UA_ENABLE_JSON_ENCODING */
          /* #undef UA_ENABLE_JSON_ENCODING_LEGACY */
          /* #undef UA_ENABLE_XML_ENCODING */
          /* #undef UA_ENABLE_MQTT */
          /* #undef UA_ENABLE_NODESET_INJECTOR */
          /* #undef UA_INFORMATION_MODEL_AUTOLOAD */
          #define UA_ENABLE_ENCRYPTION_MBEDTLS
          /* #undef UA_ENABLE_GDS_PUSHMANAGEMENT */
          /* #undef UA_ENABLE_TPM2_SECURITY */
          /* #undef UA_ENABLE_ENCRYPTION_OPENSSL */
          /* #undef UA_ENABLE_ENCRYPTION_LIBRESSL */
          #if defined(UA_ENABLE_ENCRYPTION_MBEDTLS) || defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
          #define UA_ENABLE_ENCRYPTION
          #endif
          /* #undef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

          /* Multithreading */
          // #define UA_MULTITHREADING 100
          #define UA_MULTITHREADING 0

          /* Advanced Options */
          /* #undef UA_ENABLE_STATUSCODE_DESCRIPTIONS */
          /* #undef UA_ENABLE_TYPEDESCRIPTION */
          /* #undef UA_ENABLE_INLINABLE_EXPORT */
          /* #undef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS */
          /* #undef UA_ENABLE_DETERMINISTIC_RNG */
          /* #undef UA_ENABLE_DISCOVERY */
          /* #undef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD */
          /* #undef UA_ENABLE_DISCOVERY_MULTICAST_AVAHI */
          #if defined(UA_ENABLE_DISCOVERY_MULTICAST_MDNSD) || defined(UA_ENABLE_DISCOVERY_MULTICAST_AVAHI)
          #define UA_ENABLE_DISCOVERY_MULTICAST
          #endif
          /* #undef UA_ENABLE_QUERY */
          /* #undef UA_ENABLE_MALLOC_SINGLETON */
          /* #undef UA_ENABLE_DISCOVERY_SEMAPHORE */
          /* #undef UA_GENERATED_NAMESPACE_ZERO */
          /* #undef UA_GENERATED_NAMESPACE_ZERO_FULL */
          /* #undef UA_ENABLE_PUBSUB_SKS */

          /* Options for Debugging */
          /* #undef UA_DEBUG */
          #ifdef DEBUG
            #define UA_DEBUG
          #endif
          /* #undef UA_DEBUG_DUMP_PKGS */
          /* #undef UA_DEBUG_FILE_LINE_INFO */





ua_server_binary.c
Changes to sync timestamp
    ....
        return decodeHeaderSendServiceFault(server, channel, msg, requestPos,
                                            sd->responseType, requestId, retval);
    }
    else
    {
      // !!!!!
      // --- SYNC START ---
      // Cast the generic request pointer to a Header to get the time
      const UA_RequestHeader *header = (const UA_RequestHeader*)&request;

      // Some clients send 0, only sync if the time is valid
      if (header->timestamp > 0)
      {
        extern int64_t world_time_offset_100ns;
        // We only synchronize ONE time
        if (world_time_offset_100ns == UA_DATETIME_UNIX_EPOCH)
        {
          // Get what our internal clock CURRENTLY thinks it is
          UA_DateTime internal_now = UA_DateTime_now();
          // Calculate the difference (the error)
          int64_t drift = (int64_t)header->timestamp - (int64_t)internal_now;
          // Adjust the global offset by that drift
          // This makes the very next call to UA_DateTime_now() aligned
          // See clock_freertos.c
          world_time_offset_100ns += drift;
        }
      }
    }


Changes to clock_freertos.c:

// Global offset to turn uptime into world time
// Initialized to the Unix Epoch so it starts at 1970
int64_t world_time_offset_100ns = UA_DATETIME_UNIX_EPOCH;

// The current time in UTC time
UA_DateTime UA_DateTime_now(void)
{
  UA_DateTime microSeconds = ((UA_DateTime)xTaskGetTickCount()) * (1000000 / configTICK_RATE_HZ);
  // !!!!    return ((microSeconds / 1000000) * UA_DATETIME_SEC) + ((microSeconds % 1000000) * UA_DATETIME_USEC) + UA_DATETIME_UNIX_EPOCH;
  return ((microSeconds / 1000000) * UA_DATETIME_SEC) + ((microSeconds % 1000000) * UA_DATETIME_USEC) + world_time_offset_100ns;
}


-------------------------------------------------------------------------


Testing Opc Ua with UaExpert (Linux version),
or opcua-commander:
> pacman -S nodejs npm
> npx opcua-commander -u admin -p admin \
                      --endpoint opc.tcp://192.168.1.202:4840 \
                      --securityMode SignAndEncrypt \
                      --securityPolicy Basic256Sha256
