// Tmc2209.h
#ifndef TMC2209_H
#define TMC2209_H

#include "pico/stdlib.h"
#include "Tmc_uart.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h> 
#include <math.h>
#include <string.h>

typedef struct {
    TMC_UART* serial_instance;
    int mtr_id; 
    uint8_t rFrame[4]; 
    uint8_t wFrame[8]; 
    uint64_t result[4];
} TMC2209;


//======================================================================================
// New def of reg, not use
//======================================================================================

typedef union {
    uint8_t data[8];
    struct {
        uint8_t adrress;
        uint8_t mtr_id;
        uint8_t reg;
        uint8_t payload;
        uint8_t crc;
    } msg;
} TMC_uart_write_datagram_t;

typedef union {
    uint8_t data[4];
    struct {
        uint8_t adrress;
        uint8_t mtr_id;
        uint8_t reg;
        uint8_t crc8;
    } msg;
} TMC_uart_read_datagram_t;


enum tmc2209_regaddr_t {
    GCONF        = 0x00,
    GSTAT        = 0x01,
    IFCNT        = 0x02,
    SLAVECONF    = 0x03,
    OTP_PROG     = 0x04,
    OTP_READ     = 0x05,
    IOIN         = 0x06,
    FACTORY_CONF = 0x07,

    IHOLD_IRUN   = 0x10,
    TPOWERDOWN   = 0x11,
    TSTEP        = 0x12,
    TPWMTHRS     = 0x13,
    VACTUAL      = 0x22,
    TCOOLTHRS    = 0x14,
    SGTHRS       = 0x40,
    SG_RESULT    = 0x41,
    COOLCONF     = 0x42,

    MSCNT        = 0x6A,
    MSCURACT     = 0x6B,
    CHOPCONF     = 0x6C,
    DRV_STATUS   = 0x6F,
    PWMCONF      = 0x70,
    PWM_SCALE    = 0x71,
    PWM_AUTO     = 0x72,
    LAST_ADDR    = PWM_AUTO
};





typedef union {
    uint8_t value;
    struct {
        uint8_t
        reset_flag   :1,
        driver_error :1,
        sg2          :1,
        standstill   :1,
        unused       :4;
    };
} TMC2209_status_t;

// --- register definitions ---

// GCONF : RW
typedef union {
    uint32_t value;
    struct {
        uint32_t
        I_scale_analog   :1,
        internal_Rsense  :1,
        en_spreadcycle   :1,
        shaft            :1,
        index_otpw       :1,
        index_step       :1,
        pdn_disable      :1,
        mstep_reg_select :1,
        multistep_filt   :1,
        test_mode        :1,
        reserved         :22;
    };
} TMC2209_gconf_reg_t;

// GSTAT : R+C
typedef union {
    uint32_t value;
    struct {
        uint32_t
        reset    :1,
        drv_err  :1,
        uv_cp    :1,
        reserved :29;
    };
} TMC2209_gstat_reg_t;

// IFCNT : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        count    :8,
        reserved :24;
    };
} TMC2209_ifcnt_reg_t;

// SLAVECONF : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        reserved0 :8,
        conf      :4,
        reserved1 :20;
    };
} TMC2209_slaveconf_reg_t;

// OTP_PROG : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        otpbit   :2,
        otpbyte  :2,
        otpmagic :28;
    };
} TMC2209_otp_prog_reg_t;

// OTP_READ : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        otp0_0_4 :5,
        otp0_5   :1,
        otp0_6   :1,
        otp0_7   :1,
        otp1_0_3 :4,
        otp1_4   :1,
        otp1_5_7 :3,
        otp2_0   :1,
        otp2_1   :1,
        otp2_2   :1,
        otp2_3_4 :2,
        otp2_5_6 :2,
        otp2_7   :1,
        reserved :8;
    };
} TMC2209_otp_read_reg_t;

// IOIN : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        enn       :1,
        unused0   :1,
        ms1       :1,
        ms2       :1,
        diag      :1,
        unused1   :1,
        pdn_uart  :1,
        step      :1,
        spread_en :1,
        dir       :1,
        reserved  :14,
        version   :8;
    };
} TMC2209_ioin_reg_t;

// FACTORY_CONF : RW
typedef union {
    uint32_t value;
    struct {
        uint32_t
        fclktrim  :4,
        reserved1 :3,
        ottrim    :2,
        reserved :23;
    };
} TMC2209_factory_conf_reg_t;

// IHOLD_IRUN : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        ihold      :5,
        reserved1  :3,
        irun       :5,
        reserved2  :3,
        iholddelay :4,
        reserved3  :12;
    };
} TMC2209_ihold_irun_reg_t;

// TPOWERDOWN : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        tpowerdown :8,
        reserved   :24;
    };
} TMC2209_tpowerdown_reg_t;

// TSTEP : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        tstep    :20,
        reserved :12;
    };
} TMC2209_tstep_reg_t;

// TPWMTHRS : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        tpwmthrs :20,
        reserved :12;
    };
} TMC2209_tpwmthrs_reg_t;

// TCOOLTHRS : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        tcoolthrs :20,
        reserved  :12;
    };
} TMC2209_tcoolthrs_reg_t;

// VACTUAL : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        actual   :24,
        reserved :8;
    };
} TMC2209_vactual_reg_t;

// SGTHRS : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        threshold :8,
        reserved  :24;
    };
} TMC2209_sgthrs_reg_t;

// SG_RESULT : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        result   :10,
        reserved :22;
    };
} TMC2209_sg_result_reg_t;

// MSCNT : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        mscnt    :10,
        reserved :22;
    };
} TMC2209_mscnt_reg_t;

// MSCURACT : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        cur_a     :9,
        reserved1 :7,
        cur_b     :9,
        reserved2 :7;
    };
} TMC2209_mscuract_reg_t;

// CHOPCONF : RW
typedef union {
    uint32_t value;
    struct {
        uint32_t
        toff      :4,
        hstrt     :3,
        hend      :4,
        reserved0 :4,
        tbl       :2,
        vsense    :1,
        reserved1 :6,
        mres      :4,
        intpol    :1,
        dedge     :1,
        diss2g    :1,
        diss2vs   :1;
    };
} TMC2209_chopconf_reg_t;

// DRV_STATUS : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        otpw       :1,
        ot         :1,
        s2ga       :1,
        s2gb       :1,
        s2vsa      :1,
        s2vsb      :1,
        ola        :1,
        olb        :1,
        t120       :1,
        t143       :1,
        t150       :1,
        t157       :1,
        reserved1  :4,
        cs_actual  :5,
        reserved2  :3,
        reserved3  :6,
        stealth    :1,
        stst       :1;
    };
} TMC2209_drv_status_reg_t;

// COOLCONF : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        semin     :4,
        reserved1 :1,
        seup      :2,
        reserved2 :1,
        semax     :4,
        reserved3 :1,
        sedn      :2,
        seimin    :1,
        reserved5 :16;
    };
} TMC2209_coolconf_reg_t;

// PWMCONF : W
typedef union {
    uint32_t value;
    struct {
        uint32_t
        pwm_ofs       :8,
        pwm_grad      :8,
        pwm_freq      :2,
        pwm_autoscale :1,
        pwm_autograd  :1,
        freewheel     :2,
        reserved      :2,
        pwm_reg       :4,
        pwm_lim       :4;
    };
} TMC2209_pwmconf_reg_t;

// PWM_SCALE : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        pwm_scale_sum  :8,
        reserved1      :8,
        pwm_scale_auto :9,
        reserved2      :7;
    };
} TMC2209_pwm_scale_reg_t;

// PWM_AUTO : R
typedef union {
    uint32_t value;
    struct {
        uint32_t
        pwm_ofs_auto  :8,
        unused0       :8,
        pwm_grad_auto :8,
        unused1       :8;
    };
} TMC2209_pwm_auto_ctrl_reg_t;

// --- end of register definitions ---

typedef union {
    // tmc2209_regaddr_t reg;
    uint8_t value;
    struct {
        uint8_t
        idx   :7,
        write :1;
    };
} TMC2209_addr_t;

// --- datagrams ---

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_gconf_reg_t reg;
} TMC2209_gconf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_gstat_reg_t reg;
} TMC2209_gstat_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_tpowerdown_reg_t reg;
} TMC2209_tpowerdown_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_ifcnt_reg_t reg;
} TMC2209_ifcnt_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_slaveconf_reg_t reg;
} TMC2209_slaveconf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_otp_prog_reg_t reg;
} TMC2209_otp_prog_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_otp_read_reg_t reg;
} TMC2209_otp_read_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_ioin_reg_t reg;
} TMC2209_ioin_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_factory_conf_reg_t reg;
} TMC2209_factory_conf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_ihold_irun_reg_t reg;
} TMC2209_ihold_irun_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_tstep_reg_t reg;
} TMC2209_tstep_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_tpwmthrs_reg_t reg;
} TMC2209_tpwmthrs_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_tcoolthrs_reg_t reg;
} TMC2209_tcoolthrs_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_vactual_reg_t reg;
} TMC2209_vactual_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_sgthrs_reg_t reg;
} TMC2209_sgthrs_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_sg_result_reg_t reg;
} TMC2209_sg_result_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_mscnt_reg_t reg;
} TMC2209_mscnt_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_mscuract_reg_t reg;
} TMC2209_mscuract_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_chopconf_reg_t reg;
} TMC2209_chopconf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_drv_status_reg_t reg;
} TMC2209_drv_status_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_coolconf_reg_t reg;
} TMC2209_coolconf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_pwmconf_reg_t reg;
} TMC2209_pwmconf_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_pwm_scale_reg_t reg;
} TMC2209_pwm_scale_dgr_t;

typedef struct {
    TMC2209_addr_t addr;
    TMC2209_pwm_auto_ctrl_reg_t reg;
} TMC2209_pwm_auto_ctrl_dgr_t;

// -- end of datagrams

typedef union {
    uint32_t value;
    uint8_t data[4];
    TMC2209_gconf_reg_t gconf;
    TMC2209_gstat_reg_t gstat;
    TMC2209_ifcnt_reg_t ifcnt;
    TMC2209_slaveconf_reg_t slaveconf;
    TMC2209_otp_prog_reg_t otp_prog;
    TMC2209_otp_read_reg_t otp_read;
    TMC2209_ioin_reg_t ioin;
    TMC2209_factory_conf_reg_t factory_conf;
    TMC2209_ihold_irun_reg_t ihold_irun;
    TMC2209_tpowerdown_reg_t tpowerdown;
    TMC2209_tstep_reg_t tstep;
    TMC2209_tpwmthrs_reg_t tpwmthrs;
    TMC2209_tcoolthrs_reg_t tcoolthrs;
    TMC2209_vactual_reg_t vactual;
    TMC2209_sgthrs_reg_t sgthrs;
    TMC2209_sg_result_reg_t sg_result;
    TMC2209_coolconf_reg_t coolconf;
    TMC2209_mscnt_reg_t mscnt;
    TMC2209_mscuract_reg_t mscuract;
    TMC2209_chopconf_reg_t chopconf;
    TMC2209_drv_status_reg_t drv_status;
    TMC2209_pwmconf_reg_t pwmconf;
    TMC2209_pwm_scale_reg_t pwm_scale;
    TMC2209_pwm_auto_ctrl_reg_t pwm_auto_ctrl;
} TMC2209_payload;

typedef struct {
     TMC2209_addr_t addr;
     TMC2209_payload payload;
} TMC2209_datagram_t;

typedef union {
    uint8_t data[8];
    struct {
        uint8_t sync;
        uint8_t slave;
        TMC2209_addr_t addr;
        TMC2209_payload payload;
        uint8_t crc;
    } msg;
} TMC2209_write_datagram_t;

typedef union {
    uint8_t data[4];
    struct {
        uint8_t sync;
        uint8_t slave;
        TMC2209_addr_t addr;
        uint8_t crc;
    } msg;
} TMC2209_read_datagram_t;

typedef struct {
    // driver registers
    TMC2209_gconf_dgr_t gconf;
    TMC2209_gstat_dgr_t gstat;
    TMC2209_ifcnt_dgr_t ifcnt;
    TMC2209_slaveconf_dgr_t slaveconf;
    TMC2209_otp_prog_dgr_t otp_prog;
    TMC2209_otp_read_dgr_t otp_read;
    TMC2209_ioin_dgr_t ioin;
    TMC2209_factory_conf_dgr_t factory_conf;
    TMC2209_ihold_irun_dgr_t ihold_irun;
    TMC2209_tpowerdown_dgr_t tpowerdown;
    TMC2209_tstep_dgr_t tstep;
    TMC2209_tpwmthrs_dgr_t tpwmthrs;
    TMC2209_tcoolthrs_dgr_t tcoolthrs;
    TMC2209_vactual_dgr_t vactual;
    TMC2209_sgthrs_dgr_t sgthrs;
    TMC2209_sg_result_dgr_t sg_result;
    TMC2209_coolconf_dgr_t coolconf;
    TMC2209_mscnt_dgr_t mscnt;
    TMC2209_mscuract_dgr_t mscuract;
    TMC2209_chopconf_dgr_t chopconf;
    TMC2209_drv_status_dgr_t drv_status;
    TMC2209_pwmconf_dgr_t pwmconf;
    TMC2209_pwm_scale_dgr_t pwm_scale;
    TMC2209_pwm_auto_ctrl_dgr_t pwm_auto;

    TMC2209_status_t driver_status;

    // trinamic_config_t config;
} TMC2209_t;

//======================================================================================



void TMC2209_Init(TMC2209* tmc2209, TMC_UART* serial_instance);                                                       //ok
void TMC2209_destroy(TMC2209* tmc2209);                                                       //TODO
uint8_t compute_crc8_atm(const uint8_t *datagram, size_t length, uint8_t initial_value);            //ok
uint64_t* read_reg(TMC2209* tmc2209, int reg) ;                                                     //ok
uint32_t read_int(TMC2209* tmc2209, int reg);                                                       //ok
bool write_reg(TMC2209* tmc2209, int reg, int val);                                                 //ok
bool write_reg_check(TMC2209* tmc2209, int reg, int val) ;                                          //ok

void driver_status(TMC2209* tmc2209);                                                               //NotWork
void general_config(TMC2209* tmc2209);                                                               //NotWork
void general_stat(TMC2209* tmc2209);                                                               //NotWork

bool set_vactual(TMC2209* tmc2209, int value);                                      //ok
void set_voltage_sense(TMC2209* tmc2209, bool enabled);                                      //ok
bool get_voltage_sense(TMC2209* tmc2209);                                      //ok
void set_current_flow(TMC2209* tmc2209, double run_current, double hold_current_multiplier, int hold_current_delay, double Vref);//averif NotWork

int get_iscale_analog(TMC2209* tmc2209);                                                      //ok
void set_iscale_analog(TMC2209* tmc2209, bool enabled);                                       //ok
int get_interpolation(TMC2209* tmc2209);                                                      //ok
void set_interpolation(TMC2209* tmc2209, bool enabled);                                       //ok
int get_internal_resistor_sense(TMC2209* tmc2209);                                       //ok
void set_internal_resistor_sense(TMC2209* tmc2209, bool enabled);                                       //ok
int get_spread_cycle(TMC2209* tmc2209);                                       //NotWork
void set_spread_cycle(TMC2209* tmc2209, bool enabled);                                       //NotWork

void set_microstepping_resolution(TMC2209* tmc2209, int msres);                                       //ok
int get_microstepping_resolution(TMC2209* tmc2209);                                       //ok
void set_microstep_resolution_regselect(TMC2209* tmc2209, bool enabled);                                       //ok
void set_irun_ihold(TMC2209* tmc2209, double IHold, double IRun, int IHoldDelay);                                       //ok

int get_direction_shart(TMC2209* tmc2209);                                       //ok
void ioin(TMC2209* tmc2209);
void clear_general_stat(TMC2209* tmc2209);                                                    //ok
void set_direction_shart(TMC2209* tmc2209, int direction);                                       //ok

int get_stallguard(TMC2209* tmc2209);
void set_stallguard_threshold(TMC2209* tmc2209, int threshold);
void set_coolstep_threshold(TMC2209* tmc2209, int threshold);
void set_stallguard_callback(TMC2209* tmc2209, int stallguard_pin, int threshold, int callback, int min_speed);
int get_tstep(TMC2209* tmc2209);
int get_microstep_counter(TMC2209* tmc2209, bool in_steps, int offset);

#endif
