/*
 * FBKW.c
 *
 *  Created on: Nov 20, 2024
 *      Author: herli
 */
#include <id.h>
#include "FBKW.h"
#include <stdint.h>
#include <math.h>
#include "injection.h"
#include "toothed_wheel.h"
#include "pre_injection.h"
#include "temperature.h"
/*
float errorFBKW = 0;
float error_sum = 0;
float prev_errorFBKW = 0;
float targetFBKW = 0;
float Kp = 7;		//Kp = 5, and Ki = 0.5
float Ki = 0.0005;
float Kd = 0.005;
float Ku = 1;
float Offset = 50.0;
float intFBKWerror = 0; 		//add += error * tstep
float Proportional = 0;
double Integrator = 0;
float derivative = 0;

float maxOutput = 45;
*/
float FBKW_DEMAND = 0.0;
float FBKW_DC = 5;
float FBKW_FEEDBACK = 0.0;

float B_FB_KW = 0.0;

float DEMAND_filtered = 0.0;

uint8_t CKP_PULSE_AVAILABLE = 0;
uint8_t FBKW_PID_OPEN = 1; //estaba en 0 antes, igual asi no se peta el pid si no recibe avance


uint8_t forceDC2 = 0;
void FBKW_PIDInterrupt(){
	UpdateFBKW_DEMAND(B_FB_KW);

	if(!TW_RPM_SENSOR_STATE){
		FBKW_DC = 5; //audi like this
	}
	else if(!CKP_PULSE_AVAILABLE || !timer1started){ 	//Hay timeout o aun no se hizo la primera inyección -> modo open loop
		UpdateFBKW_OpenDutyCycle(RPM);
		FBKW_PID_OPEN = 1;
	}else{
		UpdatePID(&myPID);
		FBKW_PID_OPEN = 0;
	}
	if(forceDC){
		FBKW_DC = forceDC; //onstart should be 21,8%.
	}
	/*if(forceDC2 > 0){
		FBKW_DC = forceDC2;
	}*/
	UpdateFBKW_MODULATION(&htim4, TIM_CHANNEL_2, FBKW_DC);//FBKW_DC
}

float F_clamp(float value, float min, float max) {
    if (value < min) {
        return min;
    } else if (value > max) {
        return max;
    } else {
        return value;
    }
}

float FBKW_DEMAND_OFFSET = -2.5;
float UpdateFBKW_DEMAND(float FBKW){
	if(FBKW < FBKW_MAX && FBKW > -FBKW_MAX){ //cuando envia 760, se tiene que quedar en el ultimo valor

		/*FBKW_DEMAND = FBKW > 90 ? 0 : FBKW * FBKW_DEM_M + FBKW_DEM_N; 	//el limite superior de 90 se respeta
		float variabledemand = fclamp(1.82+ 0.0024724*RPM - 0.2626, 0, 10);
		FBKW_DEMAND += variabledemand;*/

		float FBKW_DEM_0 = FBKW * FBKW_DEM_M;
		float FBKW_TEMP = FBKW_DEM_TEMP_N + FBKW_DEM_TEMP_M * Temp;

		float rpm_cor = RPM > 1 ? RPM / 1000 : 0;
		float FBKW_DEM_RPM = FBKW_DEM_A1*rpm_cor + FBKW_DEM_A2*rpm_cor*rpm_cor + FBKW_DEM_A3*rpm_cor*rpm_cor*rpm_cor;

		FBKW_DEMAND = FBKW_DEM_0 + FBKW_TEMP + FBKW_DEM_RPM;


#if HAS_PREINJECTION
		FBKW_DEMAND += FBKW_DEMAND_OFFSET * active_PI; //this is nasty
#endif

		FBKW_DEMAND = FBKW_DEMAND < FBKW_DEM_MIN ? FBKW_DEM_MIN : FBKW_DEMAND;
		DEMAND_filtered = FBKW_DEMAND;

		forceDC = 0;
		if(FBKW_DEMAND < FBKW_FEEDBACK + 1.66){
			Timeout_ResetByIndex(8, TIM16->CNT);  // Reset CKP timeout
		}
		return DEMAND_filtered;
	}/*else if(B_FB_NW == 0){ //esto siempre 0 porque no esta implementado
		FBKW_DC = FBKW_PWM_MIN;
		forceDC = FBKW_PWM_MIN;
		FBKW_DEMAND = 0;
		DEMAND_filtered = FBKW_DEMAND;
		return 0;
	}else{
		forceDC = 0;
		return FBKW_DEMAND;
	}*/
	else{
		forceDC = 0;
		//FBKW_DEMAND = 0;
		//DEMAND_filtered = FBKW_DEMAND;
		return FBKW_DEMAND;
	}

}
float UpdateFBKW_OpenDutyCycle(float RPM){
	if(RPM > 0){
		if(RPM > 200 && DEMAND_filtered <= 0){
			FBKW_DC = FBKW_PWM_MAX;
		}else{
			float a = 3.33*DEMAND_filtered-97.4;
			float b = -0.894*DEMAND_filtered+24.6;
			FBKW_DC = a+b*log(RPM);

			FBKW_DC = F_clamp(FBKW_DC, FBKW_PWM_MIN, FBKW_PWM_MAX);
		}
	}else{
		//FBKW_DC = 0;
	}
	return FBKW_DC;
}

void UpdateFBKW_MODULATION(TIM_HandleTypeDef* pwmHandle, uint32_t pwmChannel, float dutyCycle){
	//dutyCycle = F_clamp(dutyCycle, 5.0, 95.0);
	uint32_t newRegVal = (uint32_t)roundf((float)(pwmHandle->Instance->ARR) * (dutyCycle * 0.01f));

	/*In case of the dutyCycle being calculated as higher than the reload register, cap it to the reload register*/
	if(newRegVal > pwmHandle->Instance->ARR)
	{
		newRegVal = pwmHandle->Instance->ARR;
	}
	/*Assign the new dutyCycle count to the capture compare register.*/
	__HAL_TIM_SET_COMPARE(pwmHandle, pwmChannel, (uint32_t)(roundf(newRegVal)));
}

void definePID(struct PID *pid, float Kp, float Ki, float Kd, float Kaw, float Bias, float T_C, float T, float max, float min, float max_rate, float integral, float err_prev, float deriv_prev, float command_sat_prev, float command_prev){
	myPID.Kp = Kp;
	myPID.Ki = Ki;
	myPID.Kd = Kd;
	myPID.Kaw = Kaw;
	myPID.Bias = Bias;
	myPID.T_C = T_C;			// Time constant for derivative filtering
	myPID.T = T;				// Time step
	myPID.max = max;
	myPID.min = min;
	myPID.max_rate = max_rate;
	myPID.integral = integral;
	myPID.err_prev = err_prev;
	myPID.deriv_prev = deriv_prev;
	myPID.command_sat_prev = command_sat_prev;
	myPID.command_prev = command_prev;
}
void initPID(struct PID *pid, float T_C, float T){
	myPID.Kp = FBKW_PID_KP;
	myPID.Ki = FBKW_PID_KI;
	myPID.Kd = FBKW_PID_KD;
	myPID.Kaw = FBKW_PID_KAW;
	myPID.Bias = FBKW_PID_BIAS;
	myPID.T_C = T_C;			// Time constant for derivative filtering
	myPID.T = T;				// Time step
	myPID.max = FBKW_PWM_MAX;
	myPID.min = FBKW_PWM_MIN;
	myPID.max_rate = FBKW_PID_MAXRATE;
	myPID.integral = FBKW_PID_INTEGRAL;
	myPID.err_prev = 0;
	myPID.deriv_prev = 0;
	myPID.command_sat_prev = 0;
	myPID.command_prev = 0;
}

void updatePIDfreq(struct PID *pid, uint8_t millisPID){
	TIM6->ARR = millisPID * 1000;
	myPID.T = 1.0*millisPID/1000;				// Time step
	//derivative filtering time constant update not available
}

void UpdatePID(struct PID *pid)
{
    /* This function implements a PID controller.
     *
     * Inputs:
     *   measurement: current measurement of the process variable
     *   setpoint: desired value of the process variable
     *   pid: a pointer to a PID struct containing the controller parameters
     *
     * Returns:
     *   command_sat: the control output of the PID controller (saturated based on max. min, max_rate)
     */

    float err;
    float command;
    float command_sat;
    float deriv_filt;

    /* Error calculation */
    //err = FBKW_FEEDBACK - DEMAND_filtered;
    err = FBKW_FEEDBACK - FBKW_DEMAND;

    //err = FBKW_DEMAND - FBKW_FEEDBACK;

    /* Integral term calculation - including anti-windup */
    pid->integral += pid->Ki*err*pid->T + pid->Kaw*(pid->command_sat_prev - pid->command_prev)*pid->T;

    /* Derivative term calculation using filtered derivative method */
    deriv_filt = (err - pid->err_prev + pid->T_C*pid->deriv_prev)/(pid->T + pid->T_C);
    pid->err_prev = err;
    pid->deriv_prev = deriv_filt;

    /* Summing the 3 terms */
    command = pid->Kp*err + pid->integral + pid->Kd*deriv_filt + pid->Bias;

    /* Remember command at previous step */
    pid->command_prev = command;

    /* Saturate command */
    if (command > pid->max)
    {
        command_sat = pid->max;
    }
    else if (command < pid->min)
    {
        command_sat = pid->min;
    }
    else
    {
        command_sat = command;
    }

    /* Apply rate limiter */
    if (command_sat > pid->command_sat_prev + pid->max_rate*pid->T)
    {
        command_sat = pid->command_sat_prev + pid->max_rate*pid->T;
    }
    else if (command_sat < pid->command_sat_prev - pid->max_rate*pid->T)
    {
        command_sat = pid->command_sat_prev - pid->max_rate*pid->T;
    }
    else
    {
        /* No action */
    }

    /* Remember saturated command at previous step */
    pid->command_sat_prev = command_sat;
    FBKW_DC = command_sat;
    //return command_sat;
}
