#include "bsp/bsp_driver.h"
#include "foc/core/foc_observer.h"
#include "foc/core/ladrc_observer.h"
#include "foc/core/smo_observer.h"
#include "foc/motor/motor.h"

static foc_observer_t foc_obser = {
	.enc_err_cnt = 0,
	.b_force_sensorless = false,
};
void foc_observer_init(void) {
	foc_obser.is_sensorless_enable = false;
	foc_obser.is_sensorless_running = false;
	foc_obser.enc_angle = INVALID_ANGLE;
	foc_obser.enc_est_angle = INVALID_ANGLE;
	foc_obser.enc_speed = 0;
	foc_obser.sensorless_angle = INVALID_ANGLE;
	foc_obser.sensorless_est_angle = INVALID_ANGLE;
	foc_obser.sensorless_speed = 0;
	foc_obser.is_sensorless_stable = false;
	foc_obser.sensorless_stable_cnt = 0;
	foc_obser.sensorless_unstable_cnt = 0;
#ifdef CONFIG_SMO_OBSERVER
	smo_observer_init(CONFIG_SMO_PLL_BANDWITH, CONFIG_SMO_LFP_WC, CONFIG_SMO_GAIN_K, CONFIG_SMO_SIGMOID_MAX);
	foc_obser.is_sensorless_enable = true;
#endif
#ifdef CONFIG_LADRC_OBSERVER
	ladrc_observer_init(CONFIG_LADRC_OBSERVER_MIN_Wo, CONFIG_LADRC_OBSERVER_MIN_eVEL, CONFIG_LADRC_OBSERVER_LPF_FREQ);
	foc_obser.is_sensorless_enable = true;
#endif
}

#define RPM_2_degree(rpm)  ((rpm) * 6.0f * nv_get_motor_params()->poles * FOC_CTRL_US)

float foc_observer_update(float uAlp, float uBeta, float iAlp, float iBeta){
	foc_obser.sensorless_est_angle = foc_obser.sensorless_angle + RPM_2_degree(foc_obser.sensorless_speed);
#ifdef CONFIG_SMO_OBSERVER
	foc_obser.sensorless_angle = smo_observer_update(uAlp, uBeta, iAlp, iBeta);
	foc_obser.sensorless_speed = smo_observer_vel();
#elif defined CONFIG_LADRC_OBSERVER
	foc_obser.sensorless_angle = ladrc_observer_update(uAlp, uBeta, iAlp, iBeta);
	foc_obser.sensorless_speed = ladrc_observer_vel();
#endif
	return foc_obser.sensorless_angle;
}

bool foc_observer_diagnostic(float enc_angle, float enc_vel) {
	if (foc_obser.b_force_sensorless) {
		if (foc_obser.is_sensorless_stable) {
			if (foc_obser.sensorless_speed <= foc_observer_sensorless_working_speed()/2.0f) {
				foc_obser.is_sensorless_stable = false;
			}
		}
		return false;
	}
	if (enc_vel <= (foc_observer_sensorless_working_speed() - 100.0f)) {
		if (!foc_obser.is_sensorless_running) {
			if (motor_encoder_may_error()) {
				foc_obser.enc_err_cnt++;
				foc_obser.is_sensorless_running = true;
			}
		}
		foc_obser.enc_angle = enc_angle;
		foc_obser.enc_speed = ABS(enc_vel);
		if (!foc_obser.is_sensorless_running) {
			return true;
		}
		if (foc_obser.is_sensorless_stable) {
			if (foc_obser.sensorless_speed <= foc_observer_sensorless_working_speed()/2.0f) {
				foc_obser.is_sensorless_stable = false;
			}
		}
		return false;
	}
	if (!foc_obser.is_sensorless_running) {
		/* 判断无感算法是否已经稳定跟踪速度 */
		if (!foc_obser.is_sensorless_stable) {
			float vel_diff_abs = ABS(enc_vel - foc_obser.sensorless_speed);
			if (vel_diff_abs < 50) {
				foc_obser.sensorless_stable_cnt++;
			}else {
				foc_obser.sensorless_stable_cnt = 0;
			}
			if (foc_obser.sensorless_stable_cnt >= 1000) {
				foc_obser.is_sensorless_stable = true;
			}
		}
		if (motor_encoder_may_error()) {
			foc_obser.enc_err_cnt++;
			foc_obser.is_sensorless_running = true;
		}
	}
	foc_obser.enc_angle = enc_angle;
	foc_obser.enc_speed = ABS(enc_vel);
	return !foc_obser.is_sensorless_running;
}

float foc_observer_speed(void) {
	return foc_obser.sensorless_speed;
}

bool  foc_observer_is_encoder(void) {
	if (foc_obser.b_force_sensorless) {
		return false;
	}
	return !foc_obser.is_sensorless_running;
}

void  foc_observer_use_sensorless(bool use_smo) {
	if (foc_obser.is_sensorless_enable && use_smo) {
		foc_obser.b_force_sensorless = true;
	}else {
		foc_obser.b_force_sensorless = false;
	}
}
void  foc_observer_enable_sensorless(bool enable) {
	foc_obser.is_sensorless_enable = enable;
}

float foc_observer_sensorless_angle(void) {
	return foc_obser.sensorless_angle;
}

float foc_observer_sensorless_speed(void) {
	return foc_obser.sensorless_speed;
}

u16 foc_observer_enc_errcount(void) {
	return foc_obser.enc_err_cnt;
}

float foc_observer_sensorless_diff(void) {
	return foc_obser.real_est_diff;
}

float foc_observer_sensorless_ration(void) {
	return foc_obser.real_est_ration;
}

bool foc_observer_sensorless_stable(void) {
	return foc_obser.is_sensorless_stable;
}

bool foc_observer_is_force_sensorless(void) {
	return foc_obser.b_force_sensorless;
}

float foc_observer_sensorless_working_speed(void) {
#ifdef CONFIG_SMO_OBSERVER
	return CONFIG_SMO_MIN_SPEED;
#elif defined CONFIG_LADRC_OBSERVER
	return CONFIG_LADRC_OBSERVER_MIN_SPEED;
#else
	return 20000.0f;
#endif
}

