/*
 * SPDX-License-Identifier: LicenseRef-TraxProbe-Commercial
 * Copyright (c) 2026 Embedya. All rights reserved.
 *
 * TraxProbe core engine. CONFIDENTIAL and proprietary to Embedya.
 * Licensed under the TraxProbe Commercial License (see LICENSE-COMMERCIAL.txt).
 * No use, copying, modification, redistribution, decompilation, or reverse
 * engineering is permitted except as expressly authorized by that agreement.
 */

/**
******************************************************************************
* @file           : trax_frame_validate.h
* @brief          : TraxProbe Frame Validation Module
* @version        : 3.0.0
*
* @attention
*   Validates frame integrity before transmission to host.
*
*   Check (single):
*     - Transaction counter — must increment by 1 (with 16-bit wrap).
*
*   Timestamps are intentionally NOT checked here. The on-target timer
*   wraps (and is supposed to wrap), and Traxcope reconstructs an
*   absolute timeline on the host side using the wrap-aware decoder, so
*   any "timestamp went backwards" rule on the producer would either
*   mis-fire on legitimate wraps or have to duplicate the wrap accounting
*   that the host already does correctly. Sequence integrity is fully
*   covered by the transaction-counter check.
*
*   Stream restart:
*     TID_SESSION_START is the sync/restart marker. When the validator
*     sees it, state resets automatically — the START_TRACE frame is
*     accepted unconditionally and the next frame re-seeds expected
*     values (also accepted). This mirrors host-side sync behavior.
*
*   Error counters are volatile so they can be inspected in a debugger
*   at any time, including from a breakpoint in an ISR.
*
*   MANDATORY MODULE:
*     This module is part of the probe self-diagnostic family and is
*     always compiled in (the TRAX_CFG_ENABLE_DIAG toggle was removed in
*     v3.0.0).  The host (Traxcope) runs its own sequence/integrity
*     check on every received frame, but on-target validation gives a
*     debugger break-here facility for catching producer-side corruption
*     at the moment it happens — before it leaves RAM.
******************************************************************************
* @code {.c}
*   trax_frame_validate_init();
*
*   if (!trax_frame_validate(p_frame_data, frame_size32)) {
*       // set breakpoint here — inspect trax_validate_last_* in debugger
*   }
*
*   // On trace restart:
*   trax_frame_validate_reset();
* @endcode
*/

#ifndef TRAX_FRAME_VALIDATE_H_
#define TRAX_FRAME_VALIDATE_H_

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/*=============================================================================
 ====================GLOBAL VARIABLES==========================================
 ============================================================================*/

/** Per-check error counters — inspect in debugger at any breakpoint */
extern volatile uint32_t trax_validate_err_trans_counter;
extern volatile uint32_t trax_validate_err_total;

/** Last validated frame fields — compare with failing frame for post-mortem */
extern volatile uint16_t trax_validate_last_trans_counter;

/** Failure context, latched on every reject (watch these at the
 *  return-false breakpoint):
 *    - expected transaction counter (prev_trans + 1)
 *    - actual transaction counter read from the rejected frame
 *    - address of the rejected frame inside the ring buffer */
extern volatile uint16_t trax_validate_fail_expected;
extern volatile uint16_t trax_validate_fail_actual;
extern const uint32_t *volatile trax_validate_fail_addr;

/*=============================================================================
 ====================GLOBAL FUNCTION DECLERATION===============================
 ============================================================================*/

/**
 * @brief Initialize / reset validation state and error counters
 */
void trax_frame_validate_init(void);

/**
 * @brief Validate a frame before transmission
 *
 * @param p_frame_data  Pointer to frame payload (header + timestamp + id + params)
 * @param frame_size32  Total frame size in 32-bit words
 *
 * @return true  Frame is valid — safe to transmit
 * @return false Frame failed validation — error counter incremented.
 *               Set a breakpoint on the return-false path to inspect state.
 */
bool trax_frame_validate(const uint32_t *p_frame_data, uint16_t frame_size32);

/**
 * @brief Reset validation state without clearing error counters
 *
 * Call on trace restart so the first frame of the new session is accepted.
 */
void trax_frame_validate_reset(void);

/*=============================================================================
 ====================VALIDATE-ONCE WATERMARK===================================
 ============================================================================*/
/*
 * The validator is STATEFUL (prev_trans advances with every accepted
 * frame) while the ring walk in trax_send_frames() is RE-RUNNABLE: on
 * transport backpressure the read pointer stays put and the same frames
 * are walked again on the next pass.
 *
 * Instead of rolling the sequence state back and re-validating the whole
 * batch on every retry (O(batch) per pass — quadratic over a backpressure
 * episode, and the dominant trax_process() cost on small cores), the
 * validator keeps a WATERMARK: the number of frames beyond the ring read
 * pointer that have already been validated. Retry walks skip those
 * frames, so every frame is validated exactly once in its lifetime.
 *
 * Invariant relied upon: committed frames between the read pointer and
 * the watermark are immutable — producers only append past p_alloc32 and
 * the reader only advances p_rd32 after a successful transport write.
 */

/**
 * @brief Frames beyond the ring read pointer that are already validated.
 *
 * The collector skips trax_frame_validate() for the first N frames of
 * its walk, where N is this value.
 */
uint32_t trax_frame_validate_prevalidated(void);

/**
 * @brief Raise the watermark after a ring walk.
 *
 * @param frames_walked  Number of frames (from the read pointer, in walk
 *                       order) that have passed validation this pass —
 *                       including frames skipped as already validated.
 *                       Monotonic max; smaller values are ignored.
 */
void trax_frame_validate_mark_walked(uint32_t frames_walked);

/**
 * @brief Lower the watermark when the read pointer advances.
 *
 * @param frames_consumed  Frames removed from the front of the ring
 *                         (batch committed to the transport).
 */
void trax_frame_validate_consume(uint32_t frames_consumed);

#ifdef __cplusplus
}
#endif

#endif /* TRAX_FRAME_VALIDATE_H_ */
