/*
 * 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           : trax_hw_port.h
 * @brief          : Generic Platform Hardware Port Abstraction (Fallback)
 * @version        : 1.0.0
 ******************************************************************************
 * @attention
 * 
 * This is a generic fallback implementation for platforms that don't have
 * a specific port. Users should create a platform-specific port or configure
 * the macros below for their hardware.
 * 
 * This file provides minimal implementations that may need to be customized
 * for your specific platform.
 * 
 ******************************************************************************
 */

#ifndef TRAX_HW_PORT_H_
#define TRAX_HW_PORT_H_

#include "trax_config_default.h"
#include "trax_timebase.h"   /* trax_timebase.tick_cntr for TICK_TIMER packing */

#ifdef __cplusplus
extern "C" {
#endif

/*=============================================================================
 ====================ISR PRIORITY ORDERING CONVENTION==========================
 ============================================================================*/

/* Generic platform: no architectural assumption can be made. We default to
 * the most common embedded convention (lower number = higher priority, like
 * ARM NVIC) but the right thing to do on a real target is to add a proper
 * hardware port and define this there. */
#ifndef TRAX_CFG_ISR_PRIO_ASCENDING
    #define TRAX_CFG_ISR_PRIO_ASCENDING   0  /* assumed: lower number wins */
#endif

/*=============================================================================
 ====================CRITICAL SECTION MACROS===================================
 ============================================================================*/

/**
 * @brief Enter / exit critical section — block-style macro pair.
 *
 * Generic stub implementation. Override this in your platform-specific
 * port (or define directly in trax_config.h before including trax.h)
 * with a real interrupt-disable / restore sequence for your hardware.
 *
 * Usage:
 *   TRAX_PORT_ENTER_CRITICAL_SECTION { ... } TRAX_PORT_EXIT_CRITICAL_SECTION
 *
 * @note This is a minimal stub — it only opens an inner block, with no
 *       actual interrupt masking. NOT safe for production use without
 *       a platform-specific override.
 */
#ifndef TRAX_PORT_ENTER_CRITICAL_SECTION
/* Loud build-time signal: without a real interrupt-disable pair, every
 * TraxProbe frame write races every other producer. The failure mode at
 * -O2 is silent ring corruption (out-of-order trans_counter, torn frames)
 * that only surfaces as a FRAME_CORRUPT stream stop much later — do not
 * ship this stub. Override the pair in trax_config.h or add a real port. */
#if defined(_MSC_VER)
  #pragma message("WARNING: TraxProbe Generic port: TRAX_PORT_ENTER/EXIT_CRITICAL_SECTION are NO-OPs (no interrupt masking). Define a real pair for your platform before production use.")
#else
  #warning "TraxProbe Generic port: TRAX_PORT_ENTER/EXIT_CRITICAL_SECTION are NO-OPs (no interrupt masking). Define a real pair for your platform before production use."
#endif
#define TRAX_PORT_ENTER_CRITICAL_SECTION \
    { \
        /* Generic: Disable interrupts - customize for your platform */ \
        /* Example for ARM: uint32_t primask = __get_PRIMASK(); __disable_irq(); */ \
        {
#endif

#ifndef TRAX_PORT_EXIT_CRITICAL_SECTION
#define TRAX_PORT_EXIT_CRITICAL_SECTION \
        } \
        /* Generic: Restore interrupts - customize for your platform */ \
        /* Example for ARM: __set_PRIMASK(primask); */ \
    }
#endif

/*=============================================================================
 ====================CORE ID (SMP) ============================================
 ============================================================================*/

/**
 * @brief Return the index of the CPU core executing this call (0-based).
 *
 * Generic platform default is core 0 (compile-time constant — folds away
 * everywhere it is used).  Real multi-core targets MUST add a proper
 * hardware port and define this there as a hardware-register read so
 * each core's frames are tagged with the correct coreId byte that the
 * host extracts from the upper byte of the id wire word.
 *
 * See hw_port/ARM_Cortex_M/include/trax_hw_port.h for concrete
 * RP2040 and AMP examples.
 */
#ifndef TRAX_PORT_GET_CORE_ID
    #define TRAX_PORT_GET_CORE_ID()  ((uint8_t)0U)
#endif

/*=============================================================================
 ====================FREE-RUNNING COUNTER======================================
 ============================================================================*/

/**
 * @brief Free-running 32-bit counter register read
 *
 * Required when TRAX_CFG_TIMESTAMP_MODE == TRAX_TIMESTAMP_FREERUN.
 * Define this in your platform-specific port as a register read expression.
 *
 * Examples:
 *   ARM Cortex-M (DWT):   #define TRAX_HW_PORT_FREERUN_COUNTER  (DWT->CYCCNT)
 *   RISC-V (mcycle):      #define TRAX_HW_PORT_FREERUN_COUNTER  read_csr(mcycle)
 *   ESP32 (CCOUNT):       #define TRAX_HW_PORT_FREERUN_COUNTER  xthal_get_ccount()
 */
#ifndef TRAX_HW_PORT_FREERUN_COUNTER
#warning "TRAX_HW_PORT_FREERUN_COUNTER not defined! Required for FREERUN timestamp mode."
#define TRAX_HW_PORT_FREERUN_COUNTER  (0U)
#endif

/*=============================================================================
 ====================TIMETRACK MACROS==========================================
 ============================================================================*/

/* Part of the hw_port contract (see hw_port/README.md): every port must
 * provide TRAX_HW_PORT_TIMEPACKED_GET32/PUT32 for the active timestamp
 * mode. Implemented as standard C (static inline, no GNU statement
 * expressions) like the reference ports. */

#if (TRAX_CFG_TIMESTAMP_MODE == TRAX_TIMESTAMP_FREERUN)

#ifndef TRAX_HW_PORT_TIMEPACKED_GET32
#define TRAX_HW_PORT_TIMEPACKED_GET32() \
    (TRAX_HW_PORT_FREERUN_COUNTER)
#endif

#ifndef TRAX_HW_PORT_TIMEPACKED_PUT32
#define TRAX_HW_PORT_TIMEPACKED_PUT32(p_wr) \
    do { *p_wr++ = TRAX_HW_PORT_FREERUN_COUNTER; } while (0)
#endif

#else /* TRAX_TIMESTAMP_TICK_TIMER */

#if !defined(TRAX_CFG_TIMESTAMP_TIMER_VAL)
    #error "TRAX_CFG_TIMESTAMP_TIMER_VAL must be defined for TICK_TIMER mode (a fine-timer register read expression)"
#endif

#ifndef TRAX_HW_PORT_TIMEPACKED_GET32
/* No CPU barrier between the tick and fine-timer reads on the generic
 * port (there is no portable way to express one). tick_cntr is volatile
 * and TRAX_CFG_TIMESTAMP_TIMER_VAL should be a volatile register read, so
 * the compiler keeps them ordered; add a real port for weakly-ordered
 * multi-issue cores that need a hardware barrier here. */
static inline uint32_t trax_hw_port_timepacked_get32(void)
{
    uint32_t tick_cntr = trax_timebase.tick_cntr;
    uint32_t timer_val = TRAX_CFG_TIMESTAMP_TIMER_VAL;
    return (tick_cntr << TRAX_TIMESTAMP_TICK_SHIFT) |
           (timer_val & TRAX_TIMESTAMP_VAL_MASK);
}
#define TRAX_HW_PORT_TIMEPACKED_GET32()  trax_hw_port_timepacked_get32()
#endif

#ifndef TRAX_HW_PORT_TIMEPACKED_PUT32
#define TRAX_HW_PORT_TIMEPACKED_PUT32(p_wr) \
    do { *p_wr++ = TRAX_HW_PORT_TIMEPACKED_GET32(); } while (0)
#endif

#endif /* TRAX_CFG_TIMESTAMP_MODE */

#ifdef __cplusplus
}
#endif

#endif /* TRAX_HW_PORT_H_ */
