/**
 ******************************************************************************
 * @file           : demo.c
 * @date           : 21 Aug 2026
 * @author         : bemre
 * @version        : 1.0.0
 *
 * @brief          : Simulated 24 V ARG load dump + overclamp MOSFET
 ******************************************************************************
 * @attention
 *   TEDAŞ-MLZ/2018-065.A analogy (no rectifier hardware).
 *   Load 40 A / 1 Ω. Dump: 40 A into Cout → fast Vbus rise.
 *   Overclamp is 10 Ω; bus energy bleeds slowly (~200 ms 36 V→26 V).
 *   One dump per second; Overclamp fires once then holds idle.
 *   FAIL dumps: ClampGate 20 ms after Vbus crosses 33 V (10–30 ms window).
 *
 *   Trigger Studio (host):
 *     v_bus rising edge 33 V, Pre ~80 ms, Post 300 ms.
 *   Marker: Overclamp process (detect → recover). Deadline 300 ms.
 *   Logs:   CLAMP on/off/late (Overclamp lane) + VBUS critical 33 V
 *           (Regulator lane). Same rows in Log View and Trace View.
 ******************************************************************************
 */

/*=============================================================================
 ====================INCLUDES==================================================
 ============================================================================*/

#include <demo.h>
#include <stdint.h>

#include "FreeRTOS.h"
#include "task.h"
#include "trax.h"
#include "trax_var_tid.h"
#include "trax_marker_tid.h"
#include "trax_log_tid.h"

/*=============================================================================
 ====================LOCAL MACRO FUNCTIONS=====================================
 ============================================================================*/

/*=============================================================================
 ====================LOCAL MACRO DEFINITIONS===================================
 ============================================================================*/

#define V_IDLE_V              25.5f
#define V_BAND_HI_V           26.0f
#define V_CLAMP_ENTER_V       28.0f
#define V_SPEC_V              33.0f
#define V_OPEN_V              36.0f

#define R_LOAD_OHM            1.0f
#define R_CLAMP_OHM           10.0f
#define I_SRC_A               40.0f
#define C_RISE_F              0.008f
#define C_FALL_F              0.090f
#define DT_S                  0.001f
#define A_IDLE                0.20f

#define TICK_MS               1U
#define DUMP_PERIOD_MS        1000U
#define DUMP_HOLD_MS          500U
#define LATE_AFTER_33_MS      20U
#define FAIL_EVERY_N          4U

#define PRIO_REGULATOR        4U
#define PRIO_LOADSIM          3U
#define STACK_WORDS           192U

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

/*=============================================================================
 ====================LOCAL STUCTURES===========================================
 ============================================================================*/

/*=============================================================================
 ====================LOCAL VARIABLES===========================================
 ============================================================================*/

static volatile float   v_bus;
static volatile float   i_load;
static volatile uint8_t clamp_gate;
static volatile uint8_t late_clamp;
static volatile uint8_t hold_idle;
static volatile uint8_t vbus_crit_latched;

/*=============================================================================
 ====================LOCAL FUNCTION DECLARATION================================
 ============================================================================*/

static void plant_step(void);
static void clamp_gate_set(uint8_t on);
static void task_regulator(void *p_arg);
static void task_loadsim(void *p_arg);

/*=============================================================================
 ====================GLOBAL FUNCTION IMPLEMANTATION============================
 ============================================================================*/

void demo_start(void)
{
	v_bus = V_IDLE_V;
	i_load = I_SRC_A;
	clamp_gate = 0U;
	late_clamp = 0U;
	hold_idle = 0U;
	vbus_crit_latched = 0U;

	/* Overclamp is the CubeMX defaultTask — see demo_overclamp(). */
	(void)xTaskCreate(task_regulator, "Regulator", STACK_WORDS, NULL,
			  PRIO_REGULATOR, NULL);
	(void)xTaskCreate(task_loadsim, "LoadSim", STACK_WORDS, NULL,
			  PRIO_LOADSIM, NULL);
}

/*=============================================================================
 ====================LOCAL FUNCTION IMPLEMANTATION=============================
 ============================================================================*/

static void plant_step(void)
{
	float i_c;

	if ((i_load > 0.5f) || (hold_idle != 0U)) {
		v_bus += (V_IDLE_V - v_bus) * A_IDLE;
	} else if (clamp_gate != 0U) {
		/* 10 Ω bleed of bus + battery energy (larger C than the dump
		 * charge path), so the tail is slow vs the 40 A front. */
		i_c = -(v_bus / R_CLAMP_OHM);
		v_bus += (i_c * DT_S) / C_FALL_F;
	} else {
		/* Load open, 40 A still into Cout. */
		i_c = I_SRC_A;
		v_bus += (i_c * DT_S) / C_RISE_F;
		if (v_bus > V_OPEN_V) {
			v_bus = V_OPEN_V;
		}
	}

	if (v_bus < 20.0f) {
		v_bus = 20.0f;
	}
	if (v_bus > 40.0f) {
		v_bus = 40.0f;
	}
}

static void clamp_gate_set(uint8_t on)
{
	clamp_gate = (on != 0U) ? 1U : 0U;
}

static void task_regulator(void *p_arg)
{
	TickType_t last;

	(void)p_arg;
	last = xTaskGetTickCount();

	for (;;) {
		plant_step();
		TRAX_VAR_SET_FLOAT(TID_VAR_V_BUS, v_bus);
		TRAX_VAR_SET_FLOAT(TID_VAR_I_LOAD, i_load);
		TRAX_VAR_SET(TID_VAR_CLAMP_GATE, clamp_gate);

		/* Rising-edge latch: one CRITICAL log per dump that actually
		 * hits the 33 V spec. TRAX_32F ships the float bit-pattern so
		 * Traxcope prints "%.2f V". The log is attached to whichever
		 * task is running here (Regulator) — enable the Log chip in
		 * Trace View to see it on that slice. */
		if ((v_bus >= V_SPEC_V) && (vbus_crit_latched == 0U)) {
			vbus_crit_latched = 1U;
			TRAX_LOG_CRITICAL(TID_LOG_VBUS_CRIT, "VBUS",
					  "Vbus critical %.2f V (limit %.2f V)",
					  TRAX_32F(v_bus), TRAX_32F(V_SPEC_V));
		} else if (v_bus < V_BAND_HI_V) {
			vbus_crit_latched = 0U;
		}

		vTaskDelayUntil(&last, pdMS_TO_TICKS(TICK_MS));
	}
}

void demo_overclamp(void)
{
	for (;;) {
		while (v_bus < V_CLAMP_ENTER_V) {
			vTaskDelay(pdMS_TO_TICKS(TICK_MS));
		}

		/* Marker + log share this timestamp: Marker Stats duration
		 * and the Log View / Trace View Log-chip row line up. */
		TRAX_MARKER_START(TID_MARK_OVERCLAMP);
		TRAX_LOG_WARNING(TID_LOG_CLAMP_ON, "CLAMP",
				 "Overclamp ON, Vbus=%.2f V",
				 TRAX_32F(v_bus));

		if (late_clamp != 0U) {
			late_clamp = 0U;
			TRAX_LOG_ERROR(TID_LOG_CLAMP_LATE, "CLAMP",
				       "Overclamp LATE %u ms after 33 V",
				       (unsigned)LATE_AFTER_33_MS);
			while (v_bus < V_SPEC_V) {
				vTaskDelay(pdMS_TO_TICKS(TICK_MS));
			}
			vTaskDelay(pdMS_TO_TICKS(LATE_AFTER_33_MS));
		}

		clamp_gate_set(1U);
		while (v_bus > V_BAND_HI_V) {
			vTaskDelay(pdMS_TO_TICKS(TICK_MS));
		}
		clamp_gate_set(0U);
		hold_idle = 1U;

		TRAX_LOG_INFO(TID_LOG_CLAMP_OFF, "CLAMP",
			      "Overclamp OFF, Vbus=%.2f V",
			      TRAX_32F(v_bus));
		TRAX_MARKER_STOP(TID_MARK_OVERCLAMP);
	}
}

static void task_loadsim(void *p_arg)
{
	TickType_t last;
	uint32_t dump_n;

	(void)p_arg;
	dump_n = 0U;
	last = xTaskGetTickCount();

	for (;;) {
		vTaskDelayUntil(&last, pdMS_TO_TICKS(DUMP_PERIOD_MS));

		hold_idle = 0U;
		late_clamp = (((dump_n % FAIL_EVERY_N) == (FAIL_EVERY_N - 1U))
				? 1U : 0U);
		dump_n++;

		i_load = 0.0f;
		vTaskDelay(pdMS_TO_TICKS(DUMP_HOLD_MS));
		i_load = I_SRC_A;
		late_clamp = 0U;
	}
}
