/**
 * @file 	CatchRunner.cpp
 * @brief 	Source file to compile catch framework.
 * @details	All tests should be written in other files.
 * For eclipse console output, install ANSI Escape in Console
 * from the eclipse market place to get colored characters.
 */

#include "CatchRunner.h"

#define CATCH_CONFIG_COLOUR_WINDOWS

#include <fsfw/osal/osal.h>

#include <catch2/catch_session.hpp>

#ifdef FSFW_OSAL_FREERTOS
#include <FreeRTOS.h>

#include "task.h"
#endif

extern int customSetup();
extern int customTeardown();

#ifdef FSFW_OSAL_FREERTOS
struct Taskparameters {
  int argc;
  char** argv;
  TaskHandle_t catchTask;
} taskParameters;

void unittestTaskFunction(void* pvParameters) {
  Taskparameters* parameters = (Taskparameters*)pvParameters;

  int result = Catch::Session().run(parameters->argc, parameters->argv);

  vTaskDelay(pdMS_TO_TICKS(10));
  vTaskSuspendAll();
  vTaskDelete(parameters->catchTask);
  customTeardown();
  exit(result);
}
#endif

#ifdef FSFW_OSAL_RTEMS
#include <signal.h>

int sigaltstack(const stack_t* ss, stack_t* old_ss) { return 0; }
extern "C" {

void exit_qemu_failing(int error) {
  asm(/* 0x20026 == ADP_Stopped_ApplicationExit */
         "mov x1, #0x26\n\t"
        "movk x1, #2, lsl #16\n\t"
        "str x1, [sp,#0]\n\t");

    /* Exit status code. Host QEMU process exits with that status. */
    asm("mov x0, %[error]\n\t" : : [error] "r" (error));
    asm(
        "str x0, [sp,#8]\n\t"

    /* x1 contains the address of parameter block.
     * Any memory address could be used. */
        "mov x1, sp\n\t"

    /* SYS_EXIT */
        "mov w0, #0x18\n\t"

    /* Do the semihosting call on A64. */
        "hlt 0xf000\n\t"
);
}

#include "testcfg/rtems/rtemsConfig.h"

rtems_task Init(rtems_task_argument ignored) {
  rtems_time_of_day now;
  now.year = 2023;
  now.month = 1;
  now.day = 15;
  now.hour = 0;
  now.minute = 0;
  now.second = 0;
  now.ticks = 0;
  rtems_clock_set(&now);
  customSetup();
  const char* argv[] = {"fsfw-test", ""};
  int result = Catch::Session().run(1, argv);
  customTeardown();
  if (result != 0) {
    exit_qemu_failing(result);
  }
  exit(result);
}
}
#endif

int main(int argc, char* argv[]) {
  customSetup();

  int result = 0;

#ifdef FSFW_OSAL_FREERTOS
  xTaskCreate(
      unittestTaskFunction, /* The function that implements the task. */
      "Unittests", /* The text name assigned to the task - for debug only as it is not used by the
                      kernel. */
      configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */
      &taskParameters, /* The parameter passed to the task - not used in this simple case. */
      1,               /* The priority assigned to the task. */
      &taskParameters.catchTask); /* The task handle is not required, so NULL is passed. */
  taskParameters.argc = argc;
  taskParameters.argv = argv;
  vTaskStartScheduler();
#else
  // Catch internal function call
  result = Catch::Session().run(argc, argv);
#endif

  // global clean-up
  customTeardown();
  return result;
}