#ifndef AD_MODBUS_H
#define AD_MODBUS_H

#include <stdint.h>

#include "main.h"

typedef enum
{
    AD_MODBUS_FUNCTION_READ_HOLDING_REGISTERS = 3,
    AD_MODBUS_FUNCTION_WRITE_SINGLE_REGISTER = 6,
    AD_MODBUS_FUNCTION_WRITE_MULTIPLE_REGISTERS = 16
} AD_ModbusFunction_t;

typedef enum
{
    AD_MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 1,
    AD_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2,
    AD_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 3,
    AD_MODBUS_EXCEPTION_SERVER_DEVICE_FAILURE = 4
} AD_ModbusException_t;

typedef enum
{
    AD_MODBUS_STATUS_INITIALIZED = (1UL << 0),
    AD_MODBUS_STATUS_FRAME_READY = (1UL << 1),
    AD_MODBUS_STATUS_LAST_FRAME_OK = (1UL << 2),
    AD_MODBUS_STATUS_LAST_FRAME_ERROR = (1UL << 3),
    AD_MODBUS_STATUS_UART_RX_ACTIVE = (1UL << 4),
    AD_MODBUS_STATUS_RX_OVERFLOW = (1UL << 5)
} AD_ModbusStatusFlag_t;

typedef enum
{
    AD_MODBUS_REG_DEVICE_ID = 0x0000,
    AD_MODBUS_REG_PROTOCOL_VERSION = 0x0001,
    AD_MODBUS_REG_CONTROL_ENABLE = 0x0002,
    AD_MODBUS_REG_CONTROL_MODE = 0x0003,
    AD_MODBUS_REG_CONTROL_RESET_FAULTS = 0x0004,
    AD_MODBUS_REG_CONTROL_STOP = 0x0005,
    AD_MODBUS_REG_CONTROL_LOCKED_ROTOR_ALLOWED = 0x0006,
    AD_MODBUS_REG_CONTROL_PWM_DUTY_0P0001 = 0x0007,
    AD_MODBUS_REG_LIMIT_CURRENT_0P01_A = 0x0008,
    AD_MODBUS_REG_LIMIT_OVERVOLTAGE_0P1_V = 0x0009,
    AD_MODBUS_REG_LIMIT_UNDERVOLTAGE_0P1_V = 0x000A,
    AD_MODBUS_REG_LIMIT_SPEED_RPM = 0x000B,
    AD_MODBUS_REG_LIMIT_TEMPERATURE_0P1_C = 0x000C,
    AD_MODBUS_REG_CONTROL_ROTATION_FREQ_0P1_HZ = 0x000D,
    AD_MODBUS_REG_CONTROL_ROTATION_MOD_0P0001 = 0x000E,
    AD_MODBUS_REG_CONTROL_PWM_POLARITY_FLAGS = 0x000F,

    AD_MODBUS_REG_STATUS_MODE = 0x0010,
    AD_MODBUS_REG_STATUS_FLAGS_LO = 0x0011,
    AD_MODBUS_REG_STATUS_FLAGS_HI = 0x0012,
    AD_MODBUS_REG_FAULT_FLAGS_LO = 0x0013,
    AD_MODBUS_REG_FAULT_FLAGS_HI = 0x0014,
    AD_MODBUS_REG_POWER_STAGE_ALLOWED = 0x0015,
    AD_MODBUS_REG_TEST_RUNNING = 0x0016,
    AD_MODBUS_REG_INVERTER_PWM_RUNNING = 0x0017,
    AD_MODBUS_REG_INVERTER_SERVICE_OUTPUT = 0x0018,
    AD_MODBUS_REG_INVERTER_ID_STAGE = 0x0019,
    AD_MODBUS_REG_CONTROL_PWM_TIMING_MODE = 0x001A,
    AD_MODBUS_REG_CONTROL_MOTOR_CONTROL_TYPE = 0x001B,
    AD_MODBUS_REG_CONTROL_HOST_PROTOCOL = 0x001C,
    AD_MODBUS_REG_CONTROL_BINARY_TRANSPORT = 0x001D,
    AD_MODBUS_REG_CONTROL_ROTATION_RAMP_TIME_MS = 0x001E,
    AD_MODBUS_REG_CONTROL_RESET_PHASE_CURRENT_PEAKS = 0x001F,

    AD_MODBUS_REG_MEAS_IA_0P001_A = 0x0020,
    AD_MODBUS_REG_MEAS_IB_0P001_A = 0x0021,
    AD_MODBUS_REG_MEAS_IC_0P001_A = 0x0022,
    AD_MODBUS_REG_MEAS_VDC_0P1_V = 0x0023,
    AD_MODBUS_REG_MEAS_TEMP_0P1_C = 0x0024,
    AD_MODBUS_REG_MEAS_STATUS_LO = 0x0025,
    AD_MODBUS_REG_MEAS_STATUS_HI = 0x0026,
    AD_MODBUS_REG_MEAS_SPEED_RPM = 0x0027,
    AD_MODBUS_REG_MEAS_IA_RMS_0P001_A = 0x0028,
    AD_MODBUS_REG_MEAS_IB_RMS_0P001_A = 0x0029,
    AD_MODBUS_REG_MEAS_IC_RMS_0P001_A = 0x002A,
    AD_MODBUS_REG_MEAS_TORQUE_0P001_NM = 0x002B,
    AD_MODBUS_REG_MEAS_IA_PEAK_0P001_A = 0x002C,
    AD_MODBUS_REG_MEAS_IB_PEAK_0P001_A = 0x002D,
    AD_MODBUS_REG_MEAS_IC_PEAK_0P001_A = 0x002E,
    AD_MODBUS_REG_MEAS_SLIP_0P01_PERCENT = 0x002F,

    AD_MODBUS_REG_PARAM_VALID_MASK_LO = 0x0030,
    AD_MODBUS_REG_PARAM_VALID_MASK_HI = 0x0031,
    AD_MODBUS_REG_PARAM_RS_MOHM = 0x0032,
    AD_MODBUS_REG_PARAM_LS_UH_LO = 0x0033,
    AD_MODBUS_REG_PARAM_LS_UH_HI = 0x0034,
    AD_MODBUS_REG_PARAM_LL_UH_LO = 0x0035,
    AD_MODBUS_REG_PARAM_LL_UH_HI = 0x0036,
    AD_MODBUS_REG_PARAM_RR_MOHM = 0x0037,
    AD_MODBUS_REG_PARAM_LR_UH_LO = 0x0038,
    AD_MODBUS_REG_PARAM_LR_UH_HI = 0x0039,
    AD_MODBUS_REG_PARAM_LM_UH_LO = 0x003A,
    AD_MODBUS_REG_PARAM_LM_UH_HI = 0x003B,
    AD_MODBUS_REG_PARAM_J_NKGM2_LO = 0x003C,
    AD_MODBUS_REG_PARAM_J_NKGM2_HI = 0x003D,
    AD_MODBUS_REG_PARAM_B_NNMS_LO = 0x003E,
    AD_MODBUS_REG_PARAM_B_NNMS_HI = 0x003F,
    AD_MODBUS_REG_PARAM_POLE_PAIRS = 0x0040,
    AD_MODBUS_REG_PARAM_PHASE_SHUNT_MOHM = 0x0041
} AD_ModbusRegister_t;

enum
{
    AD_MODBUS_HOLDING_REGISTER_COUNT = 0x0042
};

typedef struct
{
    uint16_t H000_device_id;
    uint16_t H001_protocol_version;
    uint16_t H002_control_enable;
    uint16_t H003_control_mode;
    uint16_t H004_control_reset_faults;
    uint16_t H005_control_stop;
    uint16_t H006_control_locked_rotor_allowed;
    uint16_t H007_control_pwm_duty_0p0001;
    uint16_t H008_limit_current_0p01_a;
    uint16_t H009_limit_overvoltage_0p1_v;
    uint16_t H010_limit_undervoltage_0p1_v;
    uint16_t H011_limit_speed_rpm;
    uint16_t H012_limit_temperature_0p1_c;
    uint16_t H013_control_rotation_freq_0p1_hz;
    uint16_t H014_control_rotation_mod_0p0001;
    uint16_t H015_control_pwm_polarity_flags;
    uint16_t H016_status_mode;
    uint16_t H017_status_flags_lo;
    uint16_t H018_status_flags_hi;
    uint16_t H019_fault_flags_lo;
    uint16_t H020_fault_flags_hi;
    uint16_t H021_power_stage_allowed;
    uint16_t H022_test_running;
    uint16_t H023_inverter_pwm_running;
    uint16_t H024_inverter_service_output;
    uint16_t H025_inverter_id_stage;
    uint16_t H026_control_pwm_timing_mode;
    uint16_t H027_control_motor_control_type;
    uint16_t H028_control_host_protocol;
    uint16_t H029_control_binary_transport;
    uint16_t H030_control_rotation_ramp_time_ms;
    uint16_t H031_control_reset_phase_current_peaks;
    uint16_t H032_meas_ia_0p001_a;
    uint16_t H033_meas_ib_0p001_a;
    uint16_t H034_meas_ic_0p001_a;
    uint16_t H035_input_volt_0p1_v;
    uint16_t H036_meas_temp_0p1_c;
    uint16_t H037_meas_status_lo;
    uint16_t H038_meas_status_hi;
    uint16_t H039_meas_speed_rpm;
    uint16_t H040_meas_ia_rms_0p001_a;
    uint16_t H041_meas_ib_rms_0p001_a;
    uint16_t H042_meas_ic_rms_0p001_a;
    uint16_t H043_meas_torque_0p001_nm;
    uint16_t H044_meas_ia_peak_0p001_a;
    uint16_t H045_meas_ib_peak_0p001_a;
    uint16_t H046_meas_ic_peak_0p001_a;
    uint16_t H047_meas_slip_0p01_percent;
    uint16_t H048_param_valid_mask_lo;
    uint16_t H049_param_valid_mask_hi;
    uint16_t H050_param_rs_mohm;
    uint16_t H051_param_ls_uh_lo;
    uint16_t H052_param_ls_uh_hi;
    uint16_t H053_param_ll_uh_lo;
    uint16_t H054_param_ll_uh_hi;
    uint16_t H055_param_rr_mohm;
    uint16_t H056_param_lr_uh_lo;
    uint16_t H057_param_lr_uh_hi;
    uint16_t H058_param_lm_uh_lo;
    uint16_t H059_param_lm_uh_hi;
    uint16_t H060_param_j_nkgm2_lo;
    uint16_t H061_param_j_nkgm2_hi;
    uint16_t H062_param_b_nnms_lo;
    uint16_t H063_param_b_nnms_hi;
    uint16_t H064_param_pole_pairs;
    uint16_t H065_param_phase_shunt_mohm;
} AD_ModbusHoldingRegisters_t;

typedef union
{
    AD_ModbusHoldingRegisters_t holding;
    uint16_t holding_raw[AD_MODBUS_HOLDING_REGISTER_COUNT];
} AD_ModbusRegisters_t;

typedef struct
{
    uint8_t initialized;
    uint8_t slave_address;
    uint32_t baudrate;
    uint32_t status_flags;
    uint32_t rx_frames;
    uint32_t tx_frames;
    uint32_t crc_errors;
    uint32_t exception_errors;
    uint32_t uart_errors;
    uint32_t rx_overflows;
    uint32_t write_count;
    uint8_t last_function;
    uint16_t last_address;
    uint16_t last_quantity;
    uint16_t rx_count;
} AD_ModbusState_t;

extern volatile AD_ModbusRegisters_t g_ad_modbus_regs;
extern volatile AD_ModbusRegisters_t * const MB_REGS;

void AD_Modbus_Init(UART_HandleTypeDef *uart);
void AD_Modbus_Loop(void);
const AD_ModbusState_t* AD_Modbus_GetState(void);
void AD_Modbus_RefreshRegisters(void);
const volatile AD_ModbusRegisters_t* AD_Modbus_GetRegisters(void);

#endif
