/*
 * timeouts.c
 *
 *  Created on: May 29, 2025
 *      Author: herli
 */
#include <id.h>
#include "timeouts.h"
#include "tein_detection.h"
#include "pre_injection.h"
#include "can_port.h"
#include "toothed_wheel.h"

#if HAS_PREINJECTION
#include "pre_injection.h"
static uint16_t last_PI_tick = 0;
#else
static uint16_t last_CAN_msg_1_tick = 0;
#endif

#if defined(T06301)
#include "ford_immo.h"

#endif
//#include "sync_pulse.c"

uint32_t BitStatus = 0;

uint32_t HiddenTimers = 0;

static uint16_t last_CAN_msg_2_tick = 0;

static uint16_t last_Idle_event_tick = 0;

static uint16_t last_ICRPM_event_tick = 0;
static uint16_t last_CaptorCorrect_event_tick = 0;

static uint16_t last_BIP_event_tick = 0;

static uint16_t last_TurnOff_event_tick = 0;
static uint16_t last_CKPSignal_event_tick = 0;
static uint16_t last_CKPSensor_event_tick = 0;
static uint16_t last_SV_BIP_InsideTolerance_Timeout = 0;

static uint16_t last_NOTIMPLEMENTED_event_tick = 0;
static uint16_t last_BITZERO_event_tick = 0;

static uint16_t last_CAN_msg_empf_1_tick = 0;
static uint16_t last_CAN_msg_empf_2_tick = 0;
static uint16_t last_CAN_msg_empf_4_tick = 0;
static uint16_t last_CAN_msg_empf_3_boot_tick = 0;
static uint16_t last_sync_pulse_boot_tick = 0;

static uint8_t  boot_em3_remaining = 0;   // how many left to send after the first
static uint16_t last_boot_em3_tick = 0;   // last tick for this timeout

static uint16_t last_startup_tick = 0;   // last tick for this timeout

#if HAS_PREINJECTION
	void Handle_PI_Timeout(void) {
		// Custom action on CAN timeout
		// e.g., trigger a CAN fault routine

		//si no hay sigo reseteandolo
		if(!active_PI){
			Timeout_ResetByIndex(14, TIM16->CNT);  // Reset turnoff timeout

		}

		//Timeout_ResetByIndexNoStatus(14, TIM16->CNT); //resetea sin poner a 0 el status
	}
#else
void Handle_Can_Timeout_1(void) {
    // Custom action on CAN timeout
    // e.g., trigger a CAN fault routine
	ME = 0.0f;
}
#endif

void Handle_Can_Timeout_2(void) {
    // Custom action on CAN timeout
    // e.g., trigger a CAN fault routine
	ME = 0.0f;
}
void Handle_Idle_Timeout(void) {
    // Custom action on CAN timeout
    // e.g., trigger a CAN fault routine

}
uint8_t rpmoutCount = 0;
extern volatile uint32_t prev_Difference;
extern uint8_t hasCapturedTeeth;
void Handle_IcRPM_Timeout(void) {
    // Handle RPM missing
	/*rpmoutCount++; 	//500 / 20ms = 25
	if(rpmoutCount > 24){
		RPM = 0; //estas son rpm pal can, pa que no de errores de COM.

		PHI_AD = 0;
	}else{
		//Timeout_ResetByIndex(3, TIM16->CNT);  // Reset rpm timeout
		Timeout_ResetByIndexNoStatus(3, TIM16->CNT); //resetea sin poner a 0 el status
	}*/
	RPM = 0; //estas son rpm pal can, pa que no de errores de COM.

	PHI_AD = 0;
	hasCapturedTeeth = 0;
	prev_Difference = 0xFFFFFFFF;
	INJ_END();

    Timeout_StopByIndex(3);               // que sapague hasta que vuelva a turular

	Timeout_ResetByIndex(13, TIM16->CNT);  // Reset CKP timeout
    Timeout_StopByIndex(13);  // Reset CKP timeout

    Timeout_ResetByIndex(12, TIM16->CNT);  // Reset CKP timeout
    Timeout_StopByIndex(12);  // Reset CKP timeout

    Timeout_ResetByIndex(10, TIM16->CNT);  // Reset CKP timeout
    Timeout_StopByIndex(10);  // Reset CKP timeout
    FORCE_INJ_END();

}
void Handle_CaptorDefect_Timeout(void) {
	TW_EVAL_MAX_TEETH();
	Timeout_ResetByIndex(4, TIM16->CNT);  // Reset turnoff timeout
}

void Handle_TurnOff_Timeout(void) {
    // Handle engine off event
	  if(HAL_GPIO_ReadPin(SHUT_OFF_GPIO_Port, SHUT_OFF_Pin) != GPIO_PIN_RESET){  	//si esta en alto

		OnEnd();
		//SYNC_PULSE_TIM_STOP();
		//Timeout_StopByIndex(11);
		//para los de ford se para el can en este msmo momento...
	}else{
		Timeout_ResetByIndex(11, TIM16->CNT);  // Reset turnoff timeout
		safetySHUTOFF = 0;
		//forceDC = 0;
	}

}
void Handle_BIP_Timeout(void) {
    // Handle not captured BIP
	TEIN_STATUS_ONFAULT();
}
void Handle_CKP_NOSIGNAL_Timeout(void) {
	CKP_PULSE_AVAILABLE = 0;
}
void Handle_CKP_SENSOR_Timeout(void) {
	CKP_PULSE_AVAILABLE = 0;
}

void Handle_NOTIMPLEMENTED_Timeout(void) {
    // Handle not implemented
	//T_ein = 950;
}

void Handle_RPM_Low_Timeout(void) {
	if(RPM < CAN_RPM_SEND_ASYNC || safetySHUTOFF){
		can_port_send_msg_def(&MSG_ID_EMPF1);
	}
	Timeout_ResetByIndex(16, TIM16->CNT);  // Reset turnoff timeout
}
void Handle_EMPF2_TimeoutTick(void)
{
	if(s_empf2_pending){
	    can_port_send_msg_def(&MSG_ID_EMPF2);
	    s_empf2_pending = 0;
	}
	Timeout_ResetByIndex(17, TIM16->CNT);  // Reset turnoff timeout
}

extern uint8_t startup_finished;
extern uint8_t count;
extern uint8_t startup_count;
extern uint8_t startup_sent_count;
void Handle_Boot_EMPF3_Timeout(void)
{
#if defined(T06301)
    if(!startup_finished) {//startup &&
        Set_Timeout_Period_ByIndex(18, 400);

    	/* FOR THE FORD CAN IMMO*/
        can_port_send_msg_def(&MSG_ID_EMPF3);
    	/* END FORD IMMO*/
        if(startup_count){
            Timeout_ResetByIndex(18, TIM16->CNT);  // re-arm for another 40ms
            startup_count--;
        }else{
        	startup_finished = 1;
        }

    }else{
        can_port_send_msg_def(&MSG_ID_EMPF3_MOD);
        Timeout_StopByIndex(18);               // done
    }
#else
	can_port_send_msg_def(&MSG_ID_EMPF3);
    if(!startup_finished) {//startup &&
		Set_Timeout_Period_ByIndex(18, 150);

		startup_sent_count++;
		Timeout_ResetByIndex(18, TIM16->CNT);  // re-arm for another 40ms

    }else{
		Timeout_StopByIndex(18);  // re-arm for another 40ms
    }
#endif

}

void Handle_EMPF3_BootStart_Timeout(void){
#if defined(T06301)
    Timeout_ResetByIndex(18, TIM16->CNT);  // re-arm for another 40ms
#else
    Timeout_ResetByIndex(18, TIM16->CNT);  // re-arm for another 40ms
	can_port_send_msg_def(&MSG_ID_EMPF1);
    Timeout_ResetByIndex(16, TIM16->CNT);  // re-arm for another 40ms
#endif
    Timeout_StopByIndex(21);               // got to stop them because overflow

}
uint8_t s_empf4_due = 0;
int counter = 0;
#if defined(T06301)
void Handle_EMPF4_TimeoutTick(void)
{
	//s_empf4_due = 1;
	can_port_send_msg_def(&MSG_ID_EMPF4);
	uint16_t newtick = last_CAN_msg_empf_4_tick + 500;
	Timeout_ResetByIndex(20, newtick);  // deberia mejorarlo bastante esto, en vez de
	FIEONA_advance();
}
#endif

void Handle_startup_Timeout(void){
	startedEngine = 1;
	Timeout_ResetByIndex(0, TIM16->CNT);  // Reset turnoff timeout
	Timeout_StopByIndex(0);
	Timeout_ResetByIndex(2, TIM16->CNT);  // Reset turnoff timeout
	Timeout_StopByIndex(2);
}
void Handle_BITZERO_Timeout(void){
}
#if defined(T06301)
void Handle_SYNC_Pulse_BootStart_Timeout(void){
  if(FORD_SYNC_PULSE_OUT){
	  SYNC_PULSE_TIM_START();
  }
  Timeout_StartIfStopped(20, TIM16->CNT);  // deberia mejorarlo bastante esto, en vez de
  Timeout_ResetByIndex(16, TIM16->CNT - 50);  // Reset turnoff timeout
  Timeout_StopByIndex(22);               // got to stop them because overflow
}
#endif

void Handle_SV_BIP_OutOfTolerance_Timeout(void) {
    // Handle not implemented
	//T_ein = 950;
}
/*TimeoutEntry timeout_list[] = {
	{ &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 0), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
	{ &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 1), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ &last_Idle_event_tick, 1000, &BitStatus, (1 << 2), Handle_Idle_Timeout, 1 }, // 100ms
	{ &last_ICRPM_event_tick, 1200, &BitStatus, (1 << 3), Handle_IcRPM_Timeout, 1 }, // 20 ms //si en 20 no captura, abre can error, si en 500 sigue sin capturar, rpm = 0
    { &last_CaptorCorrect_event_tick, 30000, &BitStatus, (1 << 4), Handle_CaptorDefect_Timeout, 0 }, // 3000ms

    { &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 5), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 6), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 7), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 8), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 9), Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ &last_BIP_event_tick, 50000, &BitStatus, (1 << 10), Handle_BIP_Timeout, 0 }, // 5000 ms
    { &last_TurnOff_event_tick, 2500, &BitStatus, (1 << 11), Handle_TurnOff_Timeout, 0 }, // 250ms

    { &last_CKPSignal_event_tick, 5000, &BitStatus, (1 << 12), Handle_CKP_NOSIGNAL_Timeout, 0 }, // 10ms
    { &last_CKPSensor_event_tick, 3000, &BitStatus, (1 << 13), Handle_CKP_SENSOR_Timeout, 0 }, // 10ms, no tendrian que estar started...

#if HAS_PREINJECTION
    { &last_PI_tick, 100, &BitStatus, (1 << 14), Handle_PI_Timeout, 1 }, // 500 ms
#else
    { &last_CAN_msg_1_tick, 2500, &BitStatus, (1 << 14), Handle_Can_Timeout_1, 0 }, // 500 ms
#endif

    { &last_CAN_msg_2_tick, 2500, &BitStatus, (1 << 15), Handle_Can_Timeout_2, 0 }, // 500 ms

    { &last_CAN_msg_empf_1_tick, 600, &HiddenTimers, (1 << 0), Handle_RPM_Low_Timeout, 1}, // 500 ms
    { &last_CAN_msg_empf_2_tick, CAN_EMPF2_INSTANT ? 10 : 600, &HiddenTimers, (1 << 1), Handle_EMPF2_TimeoutTick, 0}, // 500 ms
	{ &last_boot_em3_tick, 400, &HiddenTimers, (1 << 2), Handle_Boot_EMPF3_Timeout, 0 },
	{ &last_startup_tick, 1000, &HiddenTimers, (1 << 3), Handle_startup_Timeout, 0 },
    { &last_CAN_msg_empf_4_tick, 500, &HiddenTimers, (1 << 4), Handle_EMPF4_TimeoutTick, 1}, // 500 ms
};*/
TimeoutEntry timeout_list[] = {
#if defined(T06301)
	{ 0, &last_BITZERO_event_tick, 10, &BitStatus, (1 << 0), 0, Handle_BITZERO_Timeout, 1 }, // 10ms
	{ 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 11), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ 0, &last_Idle_event_tick, 10, &BitStatus, (1 << 2), 0, Handle_Idle_Timeout, 1 }, // 100ms
	{ 1, &last_ICRPM_event_tick, 1200, &HiddenTimers, (1 << 3), 0, Handle_IcRPM_Timeout, 1 }, // 20 ms //si en 20 no captura, abre can error, si en 500 sigue sin capturar, rpm = 0
    { 1, &last_CaptorCorrect_event_tick, 30000, &HiddenTimers, (1 << 4), 0, Handle_CaptorDefect_Timeout, 0 }, // 3000ms

    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 5), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 6), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 7), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 8), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 9), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ 1, &last_BIP_event_tick, 50000, &HiddenTimers, (1 << 10), 0, Handle_BIP_Timeout, 0 }, // 5000 ms
    { 0, &last_TurnOff_event_tick, 2500, &BitStatus, (1 << 1), 0, Handle_TurnOff_Timeout, 1 }, // 250ms

    { 0, &last_CKPSignal_event_tick, 5000, &HiddenTimers, (1 << 12), 0, Handle_CKP_NOSIGNAL_Timeout, 0 }, // 10ms
    { 0, &last_CKPSensor_event_tick, 3000, &HiddenTimers, (1 << 13), 0, Handle_CKP_SENSOR_Timeout, 0 }, // 10ms, no tendrian que estar started...

#if HAS_PREINJECTION
    { 1, &last_PI_tick, 100, &BitStatus, (1 << 14), 0, Handle_PI_Timeout, 1 }, // 500 ms
#else
    { 0, &last_CAN_msg_1_tick, 2500, &HiddenTimers, (1 << 14), 0, Handle_Can_Timeout_1, 0 }, // 500 ms
#endif

    { 1, &last_CAN_msg_2_tick, 50000, &HiddenTimers, (1 << 15), 0, Handle_Can_Timeout_2, 0 }, // 500 ms

    { 1, &last_CAN_msg_empf_1_tick, 600, &HiddenTimers, (1 << 0), 0, Handle_RPM_Low_Timeout, 0}, // 500 ms
    { 1, &last_CAN_msg_empf_2_tick, CAN_EMPF2_INSTANT ? 10 : 600, &HiddenTimers, (1 << 1), 0, Handle_EMPF2_TimeoutTick, 0}, // 500 ms
	{ 1, &last_boot_em3_tick, 100, &HiddenTimers, (1 << 2), 0, Handle_Boot_EMPF3_Timeout, 0 },
	{ 1, &last_startup_tick, 1000, &HiddenTimers, (1 << 3), 0, Handle_startup_Timeout, 0 },
    { 1, &last_CAN_msg_empf_4_tick, 500, &HiddenTimers, (1 << 4), 0, Handle_EMPF4_TimeoutTick, 0}, // 50 ms
    { 1, &last_CAN_msg_empf_3_boot_tick, 6200, &HiddenTimers, (1 << 5), 0, Handle_EMPF3_BootStart_Timeout, 1}, // 50 ms
    { 1, &last_sync_pulse_boot_tick, 950, &HiddenTimers, (1 << 6), 0, Handle_SYNC_Pulse_BootStart_Timeout, 1}, // 50 ms
#else

	{ 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 0), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
	{ 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 1), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ 1, &last_Idle_event_tick, 1000, &BitStatus, (1 << 2), 0, Handle_Idle_Timeout, 1 }, // 100ms
	{ 1, &last_ICRPM_event_tick, 1200, &BitStatus, (1 << 3), 0, Handle_IcRPM_Timeout, 1 }, // 20 ms //si en 20 no captura, abre can error, si en 500 sigue sin capturar, rpm = 0
    { 1, &last_CaptorCorrect_event_tick, 30000, &BitStatus, (1 << 4), 0, Handle_CaptorDefect_Timeout, 0 }, // 3000ms

    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 5), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 6), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 7), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
    { 1, &last_SV_BIP_InsideTolerance_Timeout, 65534, &BitStatus, (1 << 8), 0, Handle_SV_BIP_OutOfTolerance_Timeout, 0 }, // 10ms
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 9), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms

	{ 1, &last_BIP_event_tick, 50000, &BitStatus, (1 << 10), 0, Handle_BIP_Timeout, 0 }, // 5000 ms
    { 1, &last_TurnOff_event_tick, 2500, &BitStatus, (1 << 11), 0, Handle_TurnOff_Timeout, 0 }, // 250ms

    { 1, &last_CKPSignal_event_tick, 5000, &BitStatus, (1 << 12), 0, Handle_CKP_NOSIGNAL_Timeout, 0 }, // 10ms
    { 1, &last_CKPSensor_event_tick, 3000, &BitStatus, (1 << 13), 0, Handle_CKP_SENSOR_Timeout, 0 }, // 10ms, no tendrian que estar started...

	#if HAS_PREINJECTION
    { 1, &last_PI_tick, 100, &BitStatus, (1 << 14), 0, Handle_PI_Timeout, 1 }, // 500 ms
	#else
    { 1, &last_CAN_msg_1_tick, 2500, &BitStatus, (1 << 14), 0, Handle_Can_Timeout_1, 0 }, // 500 ms
	#endif
    { 1, &last_CAN_msg_2_tick, 2500, &BitStatus, (1 << 15), 0, Handle_Can_Timeout_2, 0 }, // 500 ms
    { 1, &last_CAN_msg_empf_1_tick, 600, &HiddenTimers, (1 << 0), 0, Handle_RPM_Low_Timeout, 0}, // 500 ms
    { 1, &last_CAN_msg_empf_2_tick, CAN_EMPF2_INSTANT ? 10 : 600, &HiddenTimers, (1 << 1), 0, Handle_EMPF2_TimeoutTick, 0}, // 500 ms
	{ 1, &last_boot_em3_tick, 100, &HiddenTimers, (1 << 2), 0, Handle_Boot_EMPF3_Timeout, 0 },
	{ 1, &last_startup_tick, 1000, &HiddenTimers, (1 << 3), 0, Handle_startup_Timeout, 0 },
    { 0, &last_NOTIMPLEMENTED_event_tick, 100, &BitStatus, (1 << 4), 0, Handle_NOTIMPLEMENTED_Timeout, 0 }, // 10ms
#if defined(T06211)
    { 1, &last_CAN_msg_empf_3_boot_tick, 3500, &HiddenTimers, (1 << 5), 0, Handle_EMPF3_BootStart_Timeout, 1}, // 50 ms
#else
    { 1, &last_CAN_msg_empf_3_boot_tick, 75, &HiddenTimers, (1 << 5), 0, Handle_EMPF3_BootStart_Timeout, 1}, // 50 ms
#endif
#endif

};
const size_t timeout_list_size = sizeof(timeout_list) / sizeof(timeout_list[0]);

uint8_t has_timed_out(uint16_t start, uint16_t duration) {
	 uint16_t now = TIM16->CNT;
    return ((uint16_t)(now - start)) > duration;
}

void CheckTimeouts(uint16_t current_time, TimeoutEntry* timeouts) {
    for (size_t i = 0; i < timeout_list_size; ++i) {
    	if(!timeouts[i].enabled){continue;}
        if (timeouts[i].started && has_timed_out(*(timeouts[i].last_tick_ptr), timeouts[i].timeout_duration)) {
            *(timeouts[i].status_bit_ptr) |= timeouts[i].bit_mask;

            // Call the timeout handler if one is defined
            if (timeouts[i].on_timeout != NULL) {
                timeouts[i].on_timeout();
            }

        } else {
            //*(timeouts[i].status_bit_ptr) &= ~(timeouts[i].bit_mask);
        }
    }
}
void Timeout_Reset(uint16_t* tick_ptr, uint16_t new_tick, uint16_t* status_ptr, uint16_t bit_mask) {
    if (tick_ptr) {
        *tick_ptr = new_tick;
    }
    if (status_ptr) {
        *status_ptr &= ~bit_mask;  // Clear the sticky timeout bit
        //status |= BIT(n); for inverted
    }
}

void Timeout_ResetByIndex(uint8_t index, uint16_t new_tick) {
    if (index < timeout_list_size) {
        *timeout_list[index].last_tick_ptr = new_tick;
        *timeout_list[index].status_bit_ptr &= ~(timeout_list[index].bit_mask);
        if (!timeout_list[index].started){
        	timeout_list[index].started = 1;
        }
    }
}
/*void Timeout_ResetByIndex_Compliant(uint8_t index) {
    if (index < timeout_list_size) {
    	uint16_t new_tick = timeout_list[index].last_tick_ptr + timeout_list[index].timeout_duration;
        *timeout_list[index].last_tick_ptr = new_tick;
        *timeout_list[index].status_bit_ptr &= ~(timeout_list[index].bit_mask);
        if (!timeout_list[index].started){
        	timeout_list[index].started = 1;
        }
    }
}*/
void Timeout_ResetByIndexNoStatus(uint8_t index, uint16_t new_tick) {
    if (index < timeout_list_size) {
        *timeout_list[index].last_tick_ptr = new_tick;
        if (!timeout_list[index].started){
        	timeout_list[index].started = 1;
        }
    }
}

void Timeout_StopByIndex(uint8_t index){
	if (index < timeout_list_size){
    	timeout_list[index].started = 0;
	}
}
void Set_Timeout_Period_ByIndex(uint8_t index, uint16_t period){
	if (index < timeout_list_size){
    	timeout_list[index].timeout_duration = period;
	}
}
uint16_t* Timeout_GetCanTickPtr(void) {
    return &last_CAN_msg_2_tick;
}
uint16_t* Timeout_GetIcRPMTickPtr(void) {
    return &last_ICRPM_event_tick;
}
uint16_t* Timeout_GetTurnOffTickPtr(void) {
    return &last_TurnOff_event_tick;
}

void Timeout_CheckAll(uint16_t now) {
    CheckTimeouts(now, timeout_list);
}

bool Timeout_IsStarted(uint8_t index) {
    if (index >= timeout_list_size) return false;
    return timeout_list[index].started != 0;
}
void Timeout_StartIfStopped(uint8_t index, uint16_t now) {
    if (index >= timeout_list_size) return;
    if (!timeout_list[index].started) {
        *timeout_list[index].last_tick_ptr = now;
        timeout_list[index].started = 1;
        // do NOT touch status bit here
    }
}

bool Timeout_HasElapsed(uint8_t index, uint16_t now) {
    if (index >= timeout_list_size) return false;
    return has_timed_out(*timeout_list[index].last_tick_ptr,
                         timeout_list[index].timeout_duration);
}
void Timeout_PollActions(void)
{
    /*if (s_empf4_due) {
        s_empf4_due = 0;

        // Now safe: called from "normal" context
        can_port_send_msg_def(&MSG_ID_EMPF4);
        FIEONA_advance();
    }*/
}

/*void Timeout_Stop(uint8_t idx, uint16_t now) {
    if (idx >= timeout_list_size) return;
    timeout_list[idx].started = 0;
    *timeout_list[idx].last_tick_ptr = now; // optional, keeps a reference point
}*/
