#ifndef AD_PARAMETER_IDENTIFICATION_H
#define AD_PARAMETER_IDENTIFICATION_H

#include <stdint.h>

#ifndef AD_PARAM_ID_ENABLE_POWER_TESTS
#define AD_PARAM_ID_ENABLE_POWER_TESTS 0
#endif

#define AD_PARAM_ID_TIMEOUT_US_DEFAULT (5000000UL)

#define AD_MOTOR_PARAM_VALID_RS              (1UL << 0)
#define AD_MOTOR_PARAM_VALID_RR              (1UL << 1)
#define AD_MOTOR_PARAM_VALID_LS              (1UL << 2)
#define AD_MOTOR_PARAM_VALID_LR              (1UL << 3)
#define AD_MOTOR_PARAM_VALID_LM              (1UL << 4)
#define AD_MOTOR_PARAM_VALID_LL              (1UL << 5)
#define AD_MOTOR_PARAM_VALID_J               (1UL << 6)
#define AD_MOTOR_PARAM_VALID_B               (1UL << 7)
#define AD_MOTOR_PARAM_VALID_NOMINALS        (1UL << 8)

#define AD_MEAS_STATUS_OVERCURRENT           (1UL << 0)
#define AD_MEAS_STATUS_OVERVOLTAGE           (1UL << 1)
#define AD_MEAS_STATUS_UNDERVOLTAGE          (1UL << 2)
#define AD_MEAS_STATUS_OVERTEMPERATURE       (1UL << 3)
#define AD_MEAS_STATUS_DRIVER_FAULT          (1UL << 4)
#define AD_MEAS_STATUS_EMERGENCY_STOP        (1UL << 5)

#define AD_PARAM_ID_STATUS_ACTIVE            (1UL << 0)
#define AD_PARAM_ID_STATUS_POWER_TEST_BLOCKED (1UL << 1)
#define AD_PARAM_ID_STATUS_POWER_STAGE_ARMED (1UL << 2)
#define AD_PARAM_ID_STATUS_FAULT_LATCHED     (1UL << 3)
#define AD_PARAM_ID_STATUS_TIMEOUT           (1UL << 4)
#define AD_PARAM_ID_STATUS_LOCKED_ROTOR_BLOCKED (1UL << 5)
#define AD_PARAM_ID_STATUS_SAFETY_LIMITS_UNKNOWN (1UL << 6)
#define AD_PARAM_ID_STATUS_DATA_VALID        (1UL << 7)

#define AD_PARAM_ID_FAULT_OVERCURRENT        (1UL << 0)
#define AD_PARAM_ID_FAULT_OVERVOLTAGE        (1UL << 1)
#define AD_PARAM_ID_FAULT_UNDERVOLTAGE       (1UL << 2)
#define AD_PARAM_ID_FAULT_OVERTEMPERATURE    (1UL << 3)
#define AD_PARAM_ID_FAULT_DRIVER             (1UL << 4)
#define AD_PARAM_ID_FAULT_EMERGENCY_STOP     (1UL << 5)
#define AD_PARAM_ID_FAULT_TIMEOUT            (1UL << 6)
#define AD_PARAM_ID_FAULT_NULL_INPUT         (1UL << 7)

typedef enum
{
    AD_PARAM_ID_MODE_IDLE = 0,
    AD_PARAM_ID_MODE_STATOR_RESISTANCE = 1,
    AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING = 2,
    AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE = 3,
    AD_PARAM_ID_MODE_INERTIA_FRICTION = 4,
    AD_PARAM_ID_MODE_DATA_LOGGING = 5
} AD_ParamID_Mode_t;

typedef struct
{
    float Rs_ohm;
    float Rr_ohm;
    float Ls_H;
    float Lr_H;
    float Lm_H;
    float Ll_H;
    float J_kg_m2;
    float B_Nm_s;
    float pole_pairs;
    float nominal_voltage_V;
    float nominal_current_A;
    float nominal_frequency_Hz;
    float nominal_power_W;
    float nominal_speed_rpm;
    uint32_t valid_mask;
} AD_MotorParameters_t;

typedef struct
{
    float ia_A;
    float ib_A;
    float ic_A;
    float vdc_V;
    float va_V;
    float vb_V;
    float vc_V;
    float speed_rpm;
    float temperature_C;
    uint32_t timestamp_us;
    uint32_t status_flags;
} AD_Measurements_t;

typedef struct
{
    uint8_t enable;
    uint8_t test_mode;
    uint8_t reset_faults;
    float pwm_duty_limit;
    float current_limit_A;
    float voltage_limit_V;
    float speed_limit_rpm;
} AD_Command_t;

typedef struct
{
    float overcurrent_A;
    float overvoltage_V;
    float undervoltage_V;
    float overtemperature_C;
    float speed_limit_rpm;
    uint32_t timeout_us;
} AD_ParamID_SafetyLimits_t;

void AD_ParamID_Init(void);
void AD_ParamID_Reset(void);
void AD_ParamID_Start(uint8_t mode);
void AD_ParamID_Stop(void);
void AD_ParamID_StepFast(const AD_Measurements_t *meas);
void AD_ParamID_StepSlow(void);
const AD_MotorParameters_t* AD_ParamID_GetParameters(void);
uint32_t AD_ParamID_GetStatus(void);

uint8_t AD_ParamID_GetMode(void);
uint32_t AD_ParamID_GetFaults(void);
void AD_ParamID_SetSafetyLimits(const AD_ParamID_SafetyLimits_t *limits);
void AD_ParamID_SetSoftwareEnable(uint8_t enable);
void AD_ParamID_SetLockedRotorAllowed(uint8_t enable);
uint8_t AD_ParamID_IsPowerStageAllowed(void);
void AD_ParamID_EmergencyStop(uint32_t fault_flags);

#endif
