#include "hal/hal.h"
#include "hal/pwm.h"
#include "libs/task.h"
#include "foc_task.h"
#include "foc.h"
#include "phase_current.h"
#include "park_clark.h"
#include "hall_sensor.h"
#include "svpwm.h"

#if 1
static void __inline foc_update_theta(motor_foc_t *foc) {
	float angle = 0.0f;
	if (foc->override.is_theta) {
		angle = foc->override.theta;
	}else {
		angle = hall_sensor_get_theta();
	}
	foc->motor_s.angle = angle;
	foc->motor_s.theta = degree_2_pi(angle);
}

#else
static void __inline foc_update_theta(motor_foc_t *foc) {
	static float angle = 0.0f;
	static bool first_s = false;
	if (!first_s) {
		first_s = true;
		angle = hall_sensor_get_theta();
	}else {
		angle += 1;
	}
	fast_norm_angle(&angle);
	foc->motor_s.angle = angle;
	foc->motor_s.theta = degree_2_pi(angle);
}
#endif

/* 输出dq电压给反park,最后给svpwm */
static void __inline Foc_Dq_PI_Contrl(motor_foc_t *foc, dq_t *sampled, dq_t *ref_out) {
	if (foc->mode == FOC_MODE_PI_DQ || foc->mode == FOC_MODE_PI_FULL) {
		ref_out->d = pi_control(&foc->PI_id, foc->dq_ref.d - sampled->d);
		ref_out->q = pi_control(&foc->PI_iq, foc->dq_ref.q - sampled->q);
	}else {
		ref_out->d = foc->dq_ref.d;
		ref_out->q = foc->dq_ref.q;
	}
	if (foc->override.is_vdq) {
		ref_out->d = foc->override.vdq.d;
		ref_out->q = foc->override.vdq.q;
	}
}

static void __inline DeadTime_Compensation(current_samp_t *c_sample, phase_time_t *time) {
#if 0	
    /* Dead time compensation */
    if ( c_sample->Ia > 0)
    {
      time->A += TDead;
    }
    else
    {
      time->A -= TDead;
    }

    if ( c_sample->Ib > 0 )
    {
      time->B += TDead;
    }
    else
    {
      time->B -= TDead;
    }

    if ( c_sample->Ic > 0 )
    {
      time->C += TDead;
    }
    else
    {
      time->C -= TDead;
    }
#endif
}

static void __inline Debug_Log(motor_foc_t *foc){
#if 1
	static int count;
	if (count++ % 5== 0) {
		//printf("$%d %d %d %d;", foc->motor_s.angle, (int)(foc->current_samp.Ia * 1000.0f), (int)(foc->current_samp.Ib * 1000.0f),
		//	(int)(foc->current_samp.Ic * 1000.0f));
		printf("$%d;", (int)hall_sensor_get_speed());
	}
#endif	
}

/* FOC 主控制逻辑 */
void FOC_Fast_Task(motor_foc_t *foc){
	current_samp_t *c_sample = &foc->current_samp;
	alpha_beta_t sample_ab, pwm_ab;
	dq_t         sample_dq, v_dq;
	phase_time_t         phase_time;
	u32 sample_point;

	/* 更新电角度 */
	foc_update_theta(foc);
	/* 采集3相电流 */
	phase_current_sample(c_sample);
	/* ABC坐标转alpha-beta坐标 */
	Clark(c_sample->Ia, c_sample->Ib, c_sample->Ic, &sample_ab);
	/* alpha-beta坐标转旋转坐标系D-Q */
	Park(&sample_ab, foc->motor_s.theta, &sample_dq);
	/* 处理D,Q电流环，速度环低频运行，不在此处处理*/
	Foc_Dq_PI_Contrl(foc, &sample_dq, &v_dq);
	/* d-q坐标转 alpha-beta坐标，输入给pwm */
	Rev_Park(&v_dq, foc->motor_s.theta, &pwm_ab);
	/* 生成 pwm，模拟正弦波,此处vbus需要动态采集 */
	SVPWM_7(&pwm_ab, foc->vbus, FOC_PWM_Half_Period, &phase_time, &foc->sector);
	/* 通过扇区和pwm duty 选择合适的3相电流采样点 */
	sample_point = get_phase_sample_point(c_sample, &phase_time, foc->sector);
	/* 死区补偿 */
	DeadTime_Compensation(c_sample, &phase_time);
	/* 更新duty和采样点到硬件TIM1中 */
	PWM_UpdateDuty(phase_time.A, phase_time.B, phase_time.C, sample_point);

	Debug_Log(foc);
}

//输出dq电流，给电流环
static void __inline Foc_Speed_PI_Control(motor_foc_t *foc) {
	if (foc->mode == FOC_MODE_PI_SPEED || foc->mode == FOC_MODE_PI_FULL){
		float speed_ref = ramp_get_target(&foc->speed_ramp);
		float vq_out = pi_control(&foc->PI_speed, speed_ref - foc->motor_s.rpm);
		foc->dq_ref.q = vq_out;
	}
}

void FOC_Normal_Task(motor_foc_t *foc) {
	switch (foc->state) {
		case START:
			PWM_TurnOnLowSides();
			FOC_STM_NextState(CURRENT_CALIBRATE);
			break;
		case CURRENT_CALIBRATE:
			foc_current_calibrate();
			FOC_STM_NextState(READY_TO_RUN);
			break;
		case READY_TO_RUN:
			foc_pwm_start(true);
			FOC_STM_NextState(RAMPING_START);
			ramp_exc(&foc->start_ramp);
			foc_overide_vdq(true);
			break;
		case RAMPING_START:
			foc_overide_set_vdq(0.0f, ramp_get_target(&foc->start_ramp));
			if (ramp_complete(&foc->start_ramp)) {
				FOC_STM_NextState(RUNNING);
			}
			break;
		case RUNNING:
			Foc_Speed_PI_Control(foc);
			break;
		case ANY_STOP:
			ramp_clear(&foc->start_ramp);
			foc_clear();
			FOC_STM_NextState(IDLE);
			break;
		default:
			break;
	}

}
