# **********************************************************************
# *                   (c) SEGGER Microcontroller GmbH                  *
# *                        The Embedded Experts                        *
# *                           www.segger.com                           *
# **********************************************************************
#
# -------------------------- END-OF-HEADER -----------------------------
#
# Purpose : CMake configuration for SEGGER sample application.
# Literature: https://cmake.org/cmake/help/latest/
#
# Notes:
#   (1) This sample project is designed to use a multi-config generator such as
#       MSVC MSBuild or "Ninja Multi-Config". Make sure to select such with
#       cmake "-G" switch accordingly. Using a single-config generator _may_ work, however
#       testing may fail at some places.
#
cmake_minimum_required(VERSION 3.22)

# --------------------------------------------------------------------------------------------------
# For SEGGER toolchain:
#   - CMAKE_SYSTEM_PROCESSOR must have been set (either in this file or passed via -D switch 
#     to cmake) _before_ the first call to project(...).
#   - These settings shall become effective by passing the "segger-toolchain.cmake" file to 
#     the --toolchain cmake commandline-option
#     (or alternatively using the -DCMAKE_TOOLCHAIN_FILE switch).
#   - Add the cmake_modules folder in order to let cmake pick up some 
#     platform/cpu/architecture-specific settings. Cmake does that in 
#     cmake-XXXX\Modules\CMake*Information.cmake with lines like these:
#        include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_C_COMPILER_ID}-C-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
#     NOTE:
#        1. It is the responsibility of the project maintainer to provide these files and extend CMAKE_MODULE_PATH accordingly!!!
#        2. The files under ./cmake_modules in this sample project are provided for reference and demonstration only and do not cover all possible use-cases.
# --------------------------------------------------------------------------------------------------
if(NOT "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" IN_LIST CMAKE_MODULE_PATH)
  list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
endif()
# --------------------------------------------------------------------------------------------------

project(SimpleAppProject LANGUAGES C CXX ASM)

list(JOIN CMAKE_CONFIGURATION_TYPES ", "  _cfg_list)
string(APPEND _msg "\n================================================================================================================\n")
if(DEFINED SEGGER_CMAKE_TOOLCHAIN_VERSION)
string(APPEND _msg "SEGGER_CMAKE_TOOLCHAIN_VERSION = ${SEGGER_CMAKE_TOOLCHAIN_VERSION}\n")
string(APPEND _msg "SEGGER_TOOLCHAIN_PKG_ROOT = ${SEGGER_TOOLCHAIN_PKG_ROOT}\n")
string(APPEND _msg "SEGGER_CMAKE_HAS_BUILTIN_COMPILER_ID = $CACHE{SEGGER_CMAKE_HAS_BUILTIN_COMPILER_ID}\n")
endif()
string(APPEND _msg "Available build configuration types = " "${_cfg_list}")
string(APPEND _msg "\n================================================================================================================\n")
message(STATUS ${_msg})
unset(_cfg_list)
unset(_msg)

#
# Generic Project Settings
#
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

#
# Sources
#
set(APP_SRC
  source/Main.c
  source/countervar.c
  source/demo_iostream.cpp
)
# Generated source code:
cmake_path(SET config_report_code ${CMAKE_CURRENT_BINARY_DIR}/source/report_config.c)
configure_file(./source/report_config.c.in ${config_report_code})

#
# Setup build
#
add_executable(SimpleApp
  ${APP_SRC}
  ${config_report_code}
)

target_compile_definitions(SimpleApp PRIVATE
  $<$<CONFIG:Debug>:DEBUG=1>  # Set define DEBUG=1 for debug build
  SimpleApp_BUILT_WITH_CMAKE
  SimpleApp_BUILD_CONFIG=$<CONFIG>
)

if(DEFINED SEGGER_USE_GCC AND SEGGER_USE_GCC GREATER 0)
  # We need at least CXX_STANDARD 11 if we want to use GCC-mode because seggers libc++ does not support using GCC with C++03. 
  set(_min_cxx_standard 11)
else()
  set(_min_cxx_standard 98)
endif()

set_target_properties(SimpleApp PROPERTIES
  C_STANDARD 99
  C_EXTENSIONS OFF
  C_STANDARD_REQUIRED ON
  CXX_STANDARD ${_min_cxx_standard}
  CXX_EXTENSIONS OFF
  CXX_STANDARD_REQUIRED ON
)
unset(_min_cxx_standard)

if(CMAKE_HOST_WIN32)
  set(_exec_suffix ".exe")
else()
  set(_exec_suffix "")
endif()

# ==========================================================================================================================================
#
# CPU specific code and linker scripts
#
if(CMAKE_SYSTEM_NAME STREQUAL "Generic")
# Cross-Compiling for embedded target detected.

  # Add .elf suffix to output file. Required for GNU/gcc mode, since by default 
  # CMake sets CMAKE_EXECUTABLE_SUFFIX to "" for GNU.
  set(CMAKE_EXECUTABLE_SUFFIX ".elf")

  if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm-.*")
    set(DEVICE_SRC_LIST
      bsp/cortex-m4-m7/System/Cortex_M_Startup.s
      bsp/cortex-m4-m7/System/SEGGER_THUMB_Startup.s
    )
    cmake_path(SET LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cortex-m4-m7/Setup/SEGGER_Flash.icf")

    # Used in Cortex_M_Startup for enabling J-Link halt-after-bootlaoder.
    target_compile_definitions(SimpleApp PRIVATE
      __SUPPORT_RESET_HALT_AFTER_BTL=1
    )
    set(_app_entry "Reset_Handler")
  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv32-.*")
    set(DEVICE_SRC_LIST
      bsp/riscv32/System/SEGGER_RV32_crt0.s
    )
    cmake_path(SET LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/riscv32/Setup/SEGGER_Flash_RV32.icf")
    set(_app_entry "_start")
  else()
    message(FATAL_ERROR "CMAKE_SYSTEM_PROCESSOR undefined or unsupported value. Please specify it on commandline using -DCMAKE_SYSTEM_PROCESSOR=<value> or in your CMakeLists.txt !")
  endif()

  # Add the additional device-specific files to the source-list for the application.
  target_sources(SimpleApp PRIVATE
    ${DEVICE_SRC_LIST}
  )

  # Make sure that any change in the linker-script induces a rebuild
  # and that the CROSSCOMPILING_EMULATOR property points to the SEGGER Simulator.
  set_target_properties(SimpleApp PROPERTIES
    LINK_DEPENDS ${LINKER_SCRIPT}
    CROSSCOMPILING_EMULATOR "${SEGGER_TOOLCHAIN_PKG_ROOT}/bin/emSim${_exec_suffix}"
  )

  # -----------------------------------------------------------------------------------------
  # Define linker options specific to the (embedded) application here and add reference to the linker script.
  # In contrary to the settings defined here, CPU/Architecture-specific toolchain flags
  # (for assembler, compiler, linker) flags etc. are better set in platform-specific 
  # files like (for example):
  #        <this_project_folder>/cmake_modules/Platform/Generic-SEGGERClang-<LANG>-arm-cortex-m4.cmake
  #        <this_project_folder>/cmake_modules/Platform/Generic-SEGGERClang-<LANG>-arm-cortex-m7.cmake
  #        <this_project_folder>/cmake_modules/Platform/Generic-GNU-<LANG>-arm-cortex-m7.cmake
  #        ... etc.
  # -----------------------------------------------------------------------------------------
  target_link_options(SimpleApp PRIVATE
    -T${LINKER_SCRIPT}
    # Set memory regions of device
    -Wl,--add-region:FLASH1=0x00100000@0x00000000
    -Wl,--add-region:RAM1=0x00010000@0x20000000
    # Application-specific configuration
    -Wl,--defsym=__STACKSIZE__=2048
    -Wl,--defsym=__HEAPSIZE__=2048
    # I/O Configuration
    -Wl,--defsym=__SEGGER_RTL_vfprintf=__SEGGER_RTL_vfprintf_int_nwp
    -Wl,--defsym=__SEGGER_RTL_vfscanf=__SEGGER_RTL_vfscanf_int
    -io=rtt
    # Entry Point
    -e${_app_entry}
    # Optional settings
    --full-section-headers
    --merge-sections
    --merge-strings
    --map-text
    --map-standard
    --no-outline
    --relax
    --no-springboard
    --no-tail-merge
    --tp-model=auto
    --list-all-undefineds
  )
endif()

# ==========================================================================================================================================
include(CTest) # Use CTest instead of enable_testing so that VSCode can show the status of the tests.

if(CMAKE_SYSTEM_NAME STREQUAL "Generic")
# Cross-Compiling for embedded target detected.
  set(_EXPECTED_SYS_PROC "${CMAKE_SYSTEM_PROCESSOR}")
  set(_TARGET_ARGS "-end;exit")  # These arguments are actually passed to the emulator and not to the applocation itself.

  add_test(NAME SimRunDirect COMMAND "$<SHELL_PATH:${SEGGER_TOOLCHAIN_PKG_ROOT}/bin/emSim${_exec_suffix}>" "$<TARGET_FILE:SimpleApp>" -end exit)
  set_tests_properties(SimRunDirect
    PROPERTIES PASS_REGULAR_EXPRESSION "Built with CMAKE_SYSTEM_PROCESSOR = ${_EXPECTED_SYS_PROC}"
  )
else()
  set(_EXPECTED_SYS_PROC "${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()

# We can make implicit use of the CROSSCOMPILING_EMULATOR property of the target as defined above.
# The arguments in ${_TARGET_ARGS} are actually consumed by the emSim simulator.
add_test(NAME RunImpl_ExpectedExit COMMAND SimpleApp ${_TARGET_ARGS})

add_test(NAME RunImpl_ExpectedSysProc COMMAND SimpleApp ${_TARGET_ARGS})
set_tests_properties(RunImpl_ExpectedSysProc
  PROPERTIES PASS_REGULAR_EXPRESSION "Built with CMAKE_SYSTEM_PROCESSOR = ${_EXPECTED_SYS_PROC}"
)

add_test(NAME RunImpl_ExpectedBuildConf COMMAND SimpleApp ${_TARGET_ARGS})
set_tests_properties(RunImpl_ExpectedBuildConf
  PROPERTIES PASS_REGULAR_EXPRESSION "Build Config = $<CONFIG>"
)
# ==========================================================================================================================================
# **************************** end of file *****************************
