/*
 * ford_immo.c
 *
 *  Created on: Nov 21, 2025
 *      Author: herli
 */
#include "ford_immo.h"
#include "timeouts.h"
#include "can_port.h"

uint16_t FIEONA_TRANS0 = 0x0507;
uint16_t FIEONA_TRANS1 = 0x381C;
uint16_t FIEONA_TRANS2 = 0xFC1C;
uint16_t FIEONA_TRANS3 = 0x71F5;//0x375B

uint8_t eps_fieona_override = 0;

#define FIEONA_UNLOCK_MS 600000
uint32_t fieona_unlock_end = 0;
uint8_t fieona_unlocked = 0;



uint16_t FIEONA_FIRSTWORD = 0x2001;
uint16_t FIEONA_SECONDWORD = 0x2000;

static uint16_t _immo_next2  = 0x4801;  // predicted next rx = f(0x2001)
static volatile uint16_t _rx_received = 0;
static volatile uint8_t  _rx_fresh    = 0;

// --- Core step function: f(x) = u16(u16(x*x) + (x >> 2)) ---

#define IMMO_FIXUP 0x2001

static uint16_t immo_f(uint16_t x)
{
	uint16_t sq = (uint16_t)(x * x);
	return (uint16_t)(sq + (x >> 2));
}

// --- Advance: compute next tx and prediction ---
uint8_t notreceived;
uint16_t FIEONA_advance()
{
    uint16_t rx = _rx_fresh ? _rx_received : _immo_next2;
    if(!_rx_fresh){
    	notreceived++;
    }
	_rx_fresh = 0;

	// Phase 1: tx = f(rx), fixup if < 2
	uint16_t tx = immo_f(rx);
	if (tx < 2) tx = IMMO_FIXUP;

	// Phase 2: next2 = f(tx), blacklist check
	uint16_t next2 = immo_f(tx);
	if (next2 < 2 || next2 == 0x054B || next2 == 0x4656 || next2 == 0x88FC)
		next2 = IMMO_FIXUP;

	FIEONA_FIRSTWORD  = tx;
	FIEONA_SECONDWORD = tx & 0xFF00;
	_immo_next2 = next2;
	return tx;
}

uint8_t isCar = 0;
volatile uint8_t isChecked = 0;
extern uint8_t startupiscar;

void FIEONA_Check_Car_Startup()
{
	if (isChecked) return;
	if(startupiscar){
		isCar = 1;
	}
	if (isCar){
		fieona_unlocked = 1;
		//FIEONA_TRANS3 = 0x71F5;//0x71F5
    	Timeout_ResetByIndex(1, TIM16->CNT);
	}
	isChecked = 1;

}
// --- RX Handler ---

static uint16_t last_send4_tick = 0;   // last tick for this timeout
extern uint8_t count;



void Fieona_SEND4_Handler(
    const struct CanMessageDef *msg,
    const uint8_t in_data[8],
    CanTxFn txfn
)
{
	if(count > 1){
		last_send4_tick = TIM16->CNT;
	}
    // Extract first word (little endian)
    uint16_t rx_word = (uint16_t)in_data[0] | ((uint16_t)in_data[1] << 8);

    // Desync check (firmware validate_rx_word_and_aux behavior)
	if (rx_word != _immo_next2) {
		if (rx_word != IMMO_FIXUP) {
			rx_word = 0;
		}
	}

	_rx_received = rx_word;
	_rx_fresh = 1;
}

//Podria hacer que siempre empieze bloqueado, PERO si recibe un 700 antes de haber enviado el primer 312, este bloqueada... no??



void Fieona_SEND3_Handler(const uint8_t in_data[8]){
    uint16_t rx_word = (uint16_t)in_data[0] | ((uint16_t)in_data[1] << 8);

    if(fieona_unlocked){ //si recibo un 700, despues de que este bloqueada, y no es 23 o 24, no contestamos
    	if(rx_word == 0x0023){
			FIEONA_TRANS0 = 0xAA63;
			FIEONA_TRANS2 = 0x0001;
			FIEONA_TRANS2 = 0x2100;
			eps_fieona_override = 1;
    	}else if(rx_word == 0x0024){
			FIEONA_TRANS0 = 0x0164;
			FIEONA_TRANS2 = 0x0001;
			FIEONA_TRANS2 = 0;
			eps_fieona_override = 1;
    	}else if(!isCar){ //si no es el coche no enviar
            Timeout_StopByIndex(18);
    	}
    	Timeout_ResetByIndex(1, TIM16->CNT);

    }else{	//si no esta bloqueado
    	if(rx_word == 0x0024){ //y es 24 -> envio como desinmovilizando pero sin 2100
			FIEONA_TRANS0 = 0x0164;
			FIEONA_TRANS1 = 0x0001;
			FIEONA_TRANS2 = 0;

			if(!fieona_unlocked){
				fieona_unlock_end = 0; //si estaba desbloqueando fuck you (creo que deberia ir a si...
			}
			eps_fieona_override = 1;

		}else if(rx_word == 0x00B2){ //y es b2 -> envio desinmovilizando con 2100
			FIEONA_TRANS0 = 0x0164;
			FIEONA_TRANS1 = 0x0001;
			FIEONA_TRANS2 = 0x2100;
			eps_fieona_override = 1;

			if(!fieona_unlock_end){ //si no habia empezado a desinmovilizar empiezo
		    	Timeout_StartIfStopped(1, TIM16->CNT);

				fieona_unlock_end = HAL_GetTick() + FIEONA_UNLOCK_MS; //roll over is 50 days with 32bit hal tick
			}else{	//si habia empezado, chekiamos si ya acabo.
				if(HAL_GetTick() > fieona_unlock_end){
					fieona_unlocked = 1;
					fieona_unlock_end = 0;
				}
			}
		}else{ //si envio cualquier otra cosa dejo de desinmovilizar y no overrideo na.
			//fieona_unlocked = 0; //aqui creo que deberia volver a bloquearla, pero no voy a tocar na por ahora.
			fieona_unlock_end = 0;
			eps_fieona_override = 0;
		}


    }


}
void Fieona_SEND3_set_init(uint8_t i){
	if(i){
    	FIEONA_TRANS0 = 0x0507;
	}else{
    	FIEONA_TRANS0 = 0x7F81;
	}
	FIEONA_TRANS1 = 0x381C;
	FIEONA_TRANS2 = 0xFC1C;
	FIEONA_TRANS3 = 0x71F5;
}

void FIEONA_Poll(){
	if(last_send4_tick){
		uint16_t newtick = last_send4_tick - 250;
		Timeout_ResetByIndex(20, newtick);  // deberia mejorarlo bastante esto, en vez de
		last_send4_tick = 0;
	}
}
