/*
 * SPDX-License-Identifier: Apache-2.0
 * Copyright (c) 2026 Embedya.
 *
 * TraxProbe porting layer (reference port). Licensed under the Apache License,
 * Version 2.0 (see LICENSE-Apache-2.0.txt). You may copy and modify this file
 * to support additional hardware or RTOS targets.
 *
 * This file depends on TraxProbe core headers, which remain licensed under the
 * TraxProbe Commercial License and are NOT relicensed by this notice.
 */

/**
 ******************************************************************************
 * @file           : esp_trace_freertos_impl.h
 * @brief          : ESP-IDF FreeRTOS trace-hook entry point for TraxProbe
 ******************************************************************************
 * @attention
 *
 * ESP-IDF's FreeRTOS forbids editing FreeRTOSConfig.h directly. Instead, the
 * config header pulls in this file via esp_trace_freertos.h when
 * `CONFIG_ESP_TRACE_ENABLE` + `CONFIG_ESP_TRACE_LIB_EXTERNAL` are set -- the
 * supported external trace-library hook (the same one SEGGER SystemView uses).
 * It is processed BEFORE FreeRTOS.h installs its empty default traceXXX()
 * macros, so the definitions below win.
 *
 * This shim adapts the kernel-agnostic reference FreeRTOS port
 * (os/FreeRTOS/trax_rtos_port.h) to ESP-IDF's SMP kernel:
 *
 *   1. pxCurrentTCB  -- the reference port references the classic single-core
 *      global `pxCurrentTCB`. ESP-IDF keeps the running task per-core in
 *      pxCurrentTCBs[] and exposes it via xTaskGetCurrentTaskHandle(); we map
 *      the name so every kernel TU (tasks.c, queue.c, ...) resolves it.
 *
 *   2. traceISR_ENTER -- the reference port's tick hook is SysTick-shaped and
 *      takes no argument; ESP-IDF calls traceISR_ENTER(intr_id) from
 *      xPortSysTickHandler(). We re-wrap to absorb the argument.
 *
 * Pre-init safety: FreeRTOS is already running when app_main() (hence
 * trax_init()) executes, so these hooks fire during early boot. That is safe:
 * frame emission is gated by TRAX_IS_STREAMING() (false until the host starts a
 * session) and the task/object tables refuse allocations until trax_os_init()
 * marks their free-lists ready, so pre-init hook calls are no-ops.
 *
 * Kernel version: declare the UPSTREAM BASE of the IDF fork in trax_config.h,
 * e.g. ESP-IDF v5.x (kernel base V10.5.1):
 *   #define TRAX_CFG_FREERTOS_VERSION  TRAX_FREERTOS_VERSION(10, 5, 1)
 * The reference port's version gates track upstream hook signatures, which
 * the IDF fork inherits from its base kernel.
 ******************************************************************************
 */

#ifndef TRAX_ESP_TRACE_FREERTOS_IMPL_H_
#define TRAX_ESP_TRACE_FREERTOS_IMPL_H_

/* Core API + the user-owned trax_config.h (selects TRAX_CFG_RTOS_TYPE).
 *
 * This header is pulled in *while FreeRTOSConfig.h is still being processed*,
 * before FreeRTOS's base types / port macros exist. TRAX_FROM_FREERTOS_CONFIG
 * tells the Xtensa hardware port (trax_hw_port.h) not to pull in
 * <freertos/FreeRTOS.h> during this window — doing so would recurse into a
 * half-initialised kernel and install FreeRTOS's empty default traceXXX()
 * macros ahead of TraxProbe's. The trace macros only *expand* later, inside the
 * kernel translation units, where the full FreeRTOS API is already in scope. */
#define TRAX_FROM_FREERTOS_CONFIG 1
#include "trax.h"
#undef TRAX_FROM_FREERTOS_CONFIG

#if TRAX_ENABLE && (TRAX_CFG_RTOS_TYPE == TRAX_RTOS_FREERTOS)

/* On the dual-core ESP32-S3 (configNUMBER_OF_CORES == 2, set in ESP-IDF's
 * FreeRTOSConfig.h before this header is pulled in) the reference port skips
 * its own single-core `extern pxCurrentTCB` declaration, so mapping the name
 * to the public accessor here cannot clash. */
#if (configNUMBER_OF_CORES > 1)
#ifndef pxCurrentTCB
#define pxCurrentTCB  xTaskGetCurrentTaskHandle()
#endif
#endif

/* Dispatcher -> os/FreeRTOS/trax_rtos_port.h (defines the traceXXX() hooks). */
#include "trax_rtos_port.h"

/* Override the SysTick-shaped tick-enter hook with an ESP-IDF-shaped one that
 * accepts (and ignores) the systimer interrupt id passed by
 * xPortSysTickHandler(). Body mirrors the reference port: advance the trax
 * timebase, raise the per-core in-tick guard, open the ISR-tick slice. */
#ifdef traceISR_ENTER
#undef traceISR_ENTER
#endif
#define traceISR_ENTER(_intr_id_)                                              \
  do {                                                                         \
    (void)(_intr_id_);                                                         \
    trax_timestamp_tick();                                                     \
    trax_in_tick_isr[TRAX_PORT_GET_CORE_ID()] = 1U;                            \
    TRAX_ISR_ENTER(TRAX_TID_ISR_TICK);                                         \
  } while (0)

#endif /* TRAX_ENABLE && (TRAX_CFG_RTOS_TYPE == TRAX_RTOS_FREERTOS) */

#endif /* TRAX_ESP_TRACE_FREERTOS_IMPL_H_ */
