cmake_minimum_required(VERSION 3.13)

if(NOT PICO_SDK_PATH)
    if(DEFINED ENV{PICO_SDK_PATH})
        set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
    else()
        message(FATAL_ERROR "Set PICO_SDK_PATH to a Raspberry Pi Pico SDK checkout")
    endif()
endif()

include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(freertos_heap4_rp2350 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)

# The card and allocator are C-only.  Debian's compact RISC-V toolchain does
# not ship libstdc++ headers, so keep the SDK's optional new/delete source out
# while preserving the interface targets expected by pico_stdlib.
add_library(pico_cxx_options_headers INTERFACE)
target_include_directories(pico_cxx_options_headers SYSTEM INTERFACE
    ${PICO_SDK_PATH}/src/rp2_common/pico_cxx_options/include)
add_library(pico_cxx_options INTERFACE)
target_link_libraries(pico_cxx_options INTERFACE pico_cxx_options_headers)

pico_sdk_init()

if(NOT PICO_PLATFORM STREQUAL "rp2350-riscv")
    message(FATAL_ERROR "This card targets the RP2350 RISC-V cores")
endif()
if(NOT HEAP4_UPSTREAM_ROOT)
    if(DEFINED ENV{HEAP4_UPSTREAM_ROOT})
        set(HEAP4_UPSTREAM_ROOT $ENV{HEAP4_UPSTREAM_ROOT})
    else()
        set(HEAP4_UPSTREAM_ROOT /opt/FreeRTOS-Kernel)
    endif()
endif()
if(NOT EXISTS ${HEAP4_UPSTREAM_ROOT}/portable/MemMang/heap_4.c)
    message(FATAL_ERROR "Pinned FreeRTOS heap_4.c not found at ${HEAP4_UPSTREAM_ROOT}")
endif()
if(NOT FREERTOS_RP2350_PATH)
    if(DEFINED ENV{FREERTOS_RP2350_PATH})
        set(FREERTOS_RP2350_PATH $ENV{FREERTOS_RP2350_PATH})
    else()
        set(FREERTOS_RP2350_PATH /opt/FreeRTOS-RP2350)
    endif()
endif()
if(NOT EXISTS ${FREERTOS_RP2350_PATH}/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S)
    message(FATAL_ERROR "Compatible RP2350 FreeRTOS core/port not found at ${FREERTOS_RP2350_PATH}")
endif()

set(FREERTOS_CONFIG_FILE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include)
# Raspberry Pi's port CMake uses FREERTOS_KERNEL_PATH for its matching core.
# Keep the stable allocator root separate and add its heap_4.c explicitly.
set(FREERTOS_KERNEL_PATH ${FREERTOS_RP2350_PATH})
add_subdirectory(
    ${FREERTOS_RP2350_PATH}/portable/ThirdParty/GCC/RP2350_RISC-V
    ${CMAKE_BINARY_DIR}/freertos-kernel)

set(HEAP4_PROFILE "observe" CACHE STRING "observe, debug or release")
set_property(CACHE HEAP4_PROFILE PROPERTY STRINGS observe debug release)
set(HEAP4_BINARY_TYPE "no_flash" CACHE STRING "Pico SDK binary type")
set_property(CACHE HEAP4_BINARY_TYPE PROPERTY STRINGS no_flash default)

if(HEAP4_PROFILE STREQUAL "observe")
    set(HEAP4_COMPILE_OPTIONS
        -O0 -g3 -fno-omit-frame-pointer -fno-inline
        -fno-optimize-sibling-calls)
elseif(HEAP4_PROFILE STREQUAL "debug")
    set(HEAP4_COMPILE_OPTIONS
        -Og -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls)
elseif(HEAP4_PROFILE STREQUAL "release")
    set(HEAP4_COMPILE_OPTIONS -O2)
else()
    message(FATAL_ERROR "HEAP4_PROFILE must be observe, debug or release")
endif()

set(MODEL_TASKS
    task01_first_fit_split
    task02_address_order_coalesce)

foreach(task IN LISTS MODEL_TASKS)
    set(task_source src/tasks/${task}.c)
    add_executable(${task} ${task_source})
    target_include_directories(${task} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/tasks)
    set_property(SOURCE ${task_source} APPEND PROPERTY COMPILE_OPTIONS
        ${HEAP4_COMPILE_OPTIONS} -Wall -Wextra -Wpedantic)
    target_link_libraries(${task} pico_stdlib)
    pico_enable_stdio_usb(${task} 0)
    pico_enable_stdio_uart(${task} 0)
    if(NOT HEAP4_BINARY_TYPE STREQUAL "default")
        pico_set_binary_type(${task} ${HEAP4_BINARY_TYPE})
    endif()
    pico_add_extra_outputs(${task})
endforeach()

set(heap4_task task03_freertos_heap4)
set(heap4_source src/tasks/${heap4_task}.c)
add_executable(${heap4_task} ${heap4_source})
target_sources(${heap4_task} PRIVATE
    ${HEAP4_UPSTREAM_ROOT}/portable/MemMang/heap_4.c)
target_include_directories(${heap4_task} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/include
    ${CMAKE_CURRENT_LIST_DIR}/src/tasks)
set_property(SOURCE ${heap4_source} APPEND PROPERTY COMPILE_OPTIONS
    ${HEAP4_COMPILE_OPTIONS} -Wall -Wextra -Wpedantic)
target_link_libraries(${heap4_task} pico_stdlib FreeRTOS-Kernel)
pico_enable_stdio_usb(${heap4_task} 0)
pico_enable_stdio_uart(${heap4_task} 0)
if(NOT HEAP4_BINARY_TYPE STREQUAL "default")
    pico_set_binary_type(${heap4_task} ${HEAP4_BINARY_TYPE})
endif()
pico_add_extra_outputs(${heap4_task})
