#include "foc.h"
#include "arm_math.h"
#include "math/fix_math.h"
#include "math/fast_math.h"
#include "foc/core/svpwm.h"
#include "libs/logger.h"
#include "bsp/bsp_driver.h"
#include "foc/mc_config.h"
#include "foc/foc_config.h"
#include "foc/motor/current.h"


void foc_init(foc_t *foc) {
	PI_Controller_Reset(&foc->daxis, 0);
	PI_Controller_Reset(&foc->qaxis, 0);

	foc->daxis.kp = mc_conf()->c.pid[PID_ID_ID].kp;
	foc->daxis.ki = mc_conf()->c.pid[PID_ID_ID].ki;
	foc->daxis.kd = mc_conf()->c.pid[PID_ID_ID].kd;
	foc->daxis.ts = foc->ts;
	foc->qaxis.kp = mc_conf()->c.pid[PID_IQ_ID].kp;
	foc->qaxis.ki = mc_conf()->c.pid[PID_IQ_ID].ki;
	foc->qaxis.kd = mc_conf()->c.pid[PID_IQ_ID].kd;
	foc->qaxis.ts = foc->ts;
	line_ramp_init(&foc->in.target_id, CONFIG_CURRENT_LOOP_RAMP_COUNT);
	line_ramp_set_minstep(&foc->in.target_id, CONFIG_CURRENT_LOOP_RAMP_STEP_MIN);
	line_ramp_init(&foc->in.target_iq, CONFIG_CURRENT_LOOP_RAMP_COUNT);
	line_ramp_set_minstep(&foc->in.target_iq, CONFIG_CURRENT_LOOP_RAMP_STEP_MIN);
	foc->mot_velocity_filterd = 0;
	foc->mot_vel_radusPers = 0;
	memset(&foc->in, 0, sizeof(foc_in_t));
	memset(&foc->out, 0, sizeof(foc_out_t));
}

void foc_abc_2_dq(float a, float b, float c, float *d, float *q) {
	float alpha = a;
	float beta  = ONE_BY_SQRT3 * (b - c);
	float cos,sin;
	arm_sin_cos(0, &sin, &cos);
	*d = alpha * cos + beta * sin;
	*q = -alpha * sin + beta * cos;
}


static __INLINE float id_feedforward(foc_t *foc) {
#ifdef CONFIG_CURRENT_LOOP_DECOUPE
	return -(mc_conf()->m.lq * foc->out.curr_dq.q * foc->mot_vel_radusPers);
#else
	return 0;
#endif
}

static __INLINE float iq_feedforward(foc_t *foc) {
#ifdef CONFIG_CURRENT_LOOP_DECOUPE
	return (mc_conf()->m.ld * foc->out.curr_dq.d + mc_conf()->m.flux) * foc->mot_vel_radusPers;
#else
	return 0;
#endif
}

void foc_update(foc_t *foc) {
	float max_Vdc = foc->in.dc_vol * CONFIG_SVM_MODULATION;
	
	LowPass_Filter(foc->mot_velocity_filterd, foc->in.mot_velocity, 0.01f);
	foc->mot_vel_radusPers = foc->mot_velocity_filterd / 30.0f * PI * mc_conf()->m.poles;
	arm_sin_cos(foc->in.mot_angle, &foc->sin, &foc->cos);
	park(foc, &foc->in.curr_ab, &foc->out.curr_dq);
	if (!foc->in.b_openloop) {
		/* limiter Vd output for PI controller */
		float max_vd = max_Vdc * SQRT3_BY_2;
		foc->daxis.max = max_vd;
		foc->daxis.min = -max_vd;
		float err = line_ramp_step(&foc->in.target_id) - foc->out.curr_dq.d;
		float id_ff = id_feedforward(foc);
		foc->in.target_vol_dq.d = PI_Controller_Serial(&foc->daxis, err, id_ff);

		/* limiter Vq output for PI controller */
		float max_vq = sqrtsub2_f(max_vd, foc->in.target_vol_dq.d);
		foc->qaxis.max = max_vq;
		foc->qaxis.min = -max_vq;
		err = line_ramp_step(&foc->in.target_iq) - foc->out.curr_dq.q;
		float iq_ff = iq_feedforward(foc);
		foc->in.target_vol_dq.q = PI_Controller_Serial(&foc->qaxis, err, iq_ff);
	}else {
		float max_vd = max_Vdc * SQRT3_BY_2;
		foc->in.target_vol_dq.d = fclamp(foc->in.target_vol_dq.d, -max_vd, max_vd);
		float max_vq = sqrtsub2_f(max_vd, foc->in.target_vol_dq.d);
		foc->in.target_vol_dq.q = fclamp(foc->in.target_vol_dq.q, -max_vq, max_vq);
	}

	foc->out.vol_dq.d = foc->in.target_vol_dq.d;
	foc->out.vol_dq.q = foc->in.target_vol_dq.q;
#ifdef CONFIG_Volvec_Delay_Comp
	float sin_old = foc->sin;
	float cos_old = foc->cos;
	if (foc->mot_velocity_filterd >= CONFIG_Volvec_Delay_Comp_Start_Vel) {
		float vol_dq_angle = foc->in.mot_angle + foc->mot_vel_radusPers / PI * 180.0f * (foc->ts * 0.8f);
		norm_angle_deg(vol_dq_angle);
		arm_sin_cos(vol_dq_angle, &foc->sin, &foc->cos);
	}
#endif
	rev_park(foc, &foc->out.vol_dq, &foc->out.vol_albeta);
	
	SVM_Duty_Fix(&foc->out.vol_albeta, foc->in.dc_vol, foc->half_period, &foc->out);

	phase_current_point(&foc->out);
	
	pwm_update_duty(foc->out.duty[0], foc->out.duty[1], foc->out.duty[2]);
	pwm_update_sample(foc->out.sample1, foc->out.sample2, foc->out.sample_phase);
#ifdef CONFIG_Volvec_Delay_Comp
	foc->sin = sin_old;
	foc->cos = cos_old;
#endif
}

