#include "module/chassis.hpp"
#include "device/motor_rm.h"
#include "task/user_task.h"
#include "module/dr16.h"
#include "bsp/time.h"

#define CHASSIS_GAIN 100.0f

#define LIMIT(x, min, max) \
    do { if ((x) < (min)) (x) = (min); else if ((x) > (max)) (x) = (max); } while (0)

Chassis::Chassis() {
    motors_param[0] = {
        .can = BSP_CAN_2,
        .id = 0x201,
        .module = MOTOR_M3508,
        .reverse = false,
        .gear = true
    };
    motors_param[1] = {
        .can = BSP_CAN_2,
        .id = 0x202,
        .module = MOTOR_M3508,
        .reverse = false,
        .gear = true
    };
    motors_param[2] = {
        .can = BSP_CAN_2,
        .id = 0x203,
        .module = MOTOR_M3508,
        .reverse = false,
        .gear = true
    };
    motors_param[3] = {
        .can = BSP_CAN_2,
        .id = 0x204,
        .module = MOTOR_M3508,
        .reverse = false,
        .gear = true
    };
    pid_params[0] = KPID_Params_t{
        .k=0.1,
        .p=0.1,
        .i=0,
        .d=0,
        .i_limit=0.5,
        .out_limit=1,
        .d_cutoff_freq=100,
        .range = -1,
    };
    pid_params[1] = KPID_Params_t{
        .k=0.1,
        .p=0.1,
        .i=0,
        .d=0,
        .i_limit=0.5,
        .out_limit=1,
        .d_cutoff_freq=100,
        .range = -1,
    };
    pid_params[2] = KPID_Params_t{
        .k=0.1,
        .p=0.1,
        .i=0,
        .d=0,
        .i_limit=0.5,
        .out_limit=1,
        .d_cutoff_freq=100,
        .range = -1,
    };
    pid_params[3] = KPID_Params_t{
        .k=0.1,
        .p=0.1,
        .i=0,
        .d=0,
        .i_limit=0.5,
        .out_limit=1,
        .d_cutoff_freq=100,
        .range = -1,
    };
}

void Chassis::init() {
    for(int i = 0; i < 4; i++){
        PID_Init(&pid[i], KPID_MODE_NO_D, CTRL_CHASSIS_FREQ, &pid_params[i]);
        MOTOR_RM_Register(&motors_param[i]);
    }
    last_time = BSP_TIME_Get_us();
}

void Chassis::operator()() {
    last_time = time;
    time = BSP_TIME_Get_us();
    dt = time - last_time;
    //更新数据
    update_motors();
    //解算底盘数据
    calc_chassis();
    //计算pid
    calc_pid();
    if(dr16.data.sw_l == DR16_SW_DOWN){
        MOTOR_RM_Relax(&motors_param[0]);
        MOTOR_RM_Relax(&motors_param[1]);
        MOTOR_RM_Relax(&motors_param[2]);
        MOTOR_RM_Relax(&motors_param[3]);
    }else {
        for(int i = 0; i < 4; i++){
            MOTOR_RM_SetOutput(&motors_param[i], pid_output[i]);
        }
    }
    //发送控制
    send_control();
    // MOTOR_RM_SetOutput(&motors_param[0], 0.1f);
    // MOTOR_RM_Ctrl(&motors_param[0]);


}

void Chassis::update_motors(){
    MOTOR_RM_UpdateAll();

    MOTOR_RM_t *motor = NULL;
    motor = MOTOR_RM_GetMotor(&motors_param[0]);
    chassis_motors[0] = *motor;
    motor = MOTOR_RM_GetMotor(&motors_param[1]);
    chassis_motors[1] = *motor;
    motor = MOTOR_RM_GetMotor(&motors_param[2]);
    chassis_motors[2] = *motor;
    motor = MOTOR_RM_GetMotor(&motors_param[3]);
    chassis_motors[3] = *motor;
}

void Chassis::calc_chassis(){
    if(dr16.data.sw_r == DR16_SW_DOWN){
        target_speed.m1 = (dr16.data.ch_l_x - dr16.data.ch_l_y + dr16.data.ch_r_x) * CHASSIS_GAIN;  // 右前
        target_speed.m2 = (-dr16.data.ch_l_x - dr16.data.ch_l_y + dr16.data.ch_r_x) * CHASSIS_GAIN;  // 右后
        target_speed.m3 = (-dr16.data.ch_l_x + dr16.data.ch_l_y + dr16.data.ch_r_x) * CHASSIS_GAIN;  // 左后
        target_speed.m4 = (dr16.data.ch_l_x + dr16.data.ch_l_y + dr16.data.ch_r_x) * CHASSIS_GAIN;  // 左前

        /* 限幅，防止溢出 */
        LIMIT(target_speed.m1, -1000, 1000);
        LIMIT(target_speed.m2, -1000, 1000);
        LIMIT(target_speed.m3, -1000, 1000);
        LIMIT(target_speed.m4, -1000, 1000);
    }else {
        target_speed.m1 = 0;
        target_speed.m2 = 0;
        target_speed.m3 = 0;
        target_speed.m4 = 0;
    }
}

void Chassis::calc_pid(){
    pid_output[0] = PID_Calc(&pid[0], target_speed.m1, chassis_motors[0].feedback.rotor_speed, 0, dt/1000000.0f);
    pid_output[1] = PID_Calc(&pid[1], target_speed.m2, chassis_motors[1].feedback.rotor_speed, 0, dt/1000000.0f);
    pid_output[2] = PID_Calc(&pid[2], target_speed.m3, chassis_motors[2].feedback.rotor_speed, 0, dt/1000000.0f);
    pid_output[3] = PID_Calc(&pid[3], target_speed.m4, chassis_motors[3].feedback.rotor_speed, 0, dt/1000000.0f);

}

void Chassis::send_control(){
    MOTOR_RM_Ctrl(&motors_param[0]);
}
