/******************************************************************************
*
* @file    ads1260.c
* @author  ECS, Joseph Zimmer
* @version V1.0.0
* @date    25-04-2019
* @brief
*            INITIALISIERUNG ADS1260:
*            0. Setze die ADC Zustandsvariable auf ADC_STATE_INITIALIZE
*    PIN CONFIG:
*            1. ADC_POWER_DOWN_Pin auf 1 setzen                     -> ADS power up
*            2. ADC_RESET_Pin auf 1 setzen                          -> ADS reset Zustand abschalten
*            3. ADC_START_CONV_Pin auf 0 setzen                     -> ADS in Konfigurationsmodus ADC läuft nicht
*
*    WARTEN AUF:
*            4. //  warten bis ADC_DATA_READY_Pin auf 1 ist             -> wenn auf 1 ist dann ist der Chip bereit für Kommunikation  //
*               wurde ersetzt durch einschalten des Data Ready Interrupts dieser löst bei fallender Flanke aus
*               die fallende Flanke wird generiert durch den ADS1260 wenn dieser mit der Data Conversion fertig ist.
*
*    REGISTER CONFIG:
*            5. interne Referenzspannung 2.500V wird eingeschaltet, lässt sich mit ADC vom STM32G0 messen
*            6. Samplerate auf 10 sps- setzen
*            7. Filter auf FIR setzen
*            8. Conversion Mode auf Mode Pulse setzen               -> nur eine Conversion wenn gestartet muss für jede neue Conversion neu aufgerufen werden
*            9. Schalte AIN0 und AIN1 auf dem ADC
*           10. Self Offset Calibration wird durchgeführt
*
*            x.  Setze die ADC Zustandsvariable auf ADC_STATE_CONVERSION_STOPPED
*
*
*
*
*            REGISTER SCHREIBEN:
*
*            1.Byte 0x40 + Register Adresse || 2.Byte 0xXX Daten
*            Bsp:
*               Code 0x40 + Register 0x06, Daten 0x10
*               => 1.Byte 0x46,            => 2.Byte 0x10
*
*
*
******************************************************************************/

//      --- INCLUDES -----------------------------------------------------------------
#include "ads1260.h"
#include "spi.h"
#include "math.h"
#include "main.h"
#include "eeprom.h"
#include <stdio.h>
//      --- EXTERNE VARIABLEN --------------------------------------------------------

//      --- LOKALE DEFINES - bitte hier dokumentieren --------------------------------

/*************************************************************************************************************/

/*************************************************************************************************************/
#define VOLTAGE                                     (0)
#define CURRENT                                     (1)
#define TEMPERATURE                                 (2)

#define DEFAULT_ADS1260_TRANSMIT_TIMEOUT            (10)
#define DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT    (10)
#define ADS1260_SELF_OFFSET_CALIBRATION_TIMEOUT     (2000)    // > 16 * sampletime muss eingestellt werden
#define ADS1260_SYSTEM_OFFSET_CALIBRATION_TIMEOUT   (2000)
#define ADS1260_GAIN_CALIBRATION_TIMEOUT            (2000)

#define COMMAND_POS                                 (0)
#define SEND_DATA_POS                               (1)
#define RECEIVE_DATA_POS                            (2)

#define SEND_DATA_NR_OF_BYTES                       (2)
#define RECEIVE_DATA_NR_OF_BYTES                    (3)
#define DATA_ARRAY_SIZE                             (3)

#define REGISTER_READ_COMMAND                     (1 << 5)
#define REGISTER_WRITE_COMMAND                    (1 << 6)

#define SYSTEM_OFFSET_CALIBRATION_COMMAND         (0x16)
#define GAIN_CALIBRATION_COMMAND                  (0x17)
#define SELF_OFFSET_CALIBRATION_COMMAND           (0x19)
                                                                  // Register Number:
#define DATA_RATE_REGISTER                                        (0x02)
#define DATA_RATE_2_5                             (0b00000 << 3)
#define DATA_RATE_5                               (0b00001 << 3)
#define DATA_RATE_10                              (0b00010 << 3)
#define DATA_RATE_16_6                            (0b00011 << 3)
#define DATA_RATE_20                              (0b00100 << 3)/*Default*/
#define DATA_RATE_50                              (0b00101 << 3)
#define DATA_RATE_60                              (0b00110 << 3)
#define DATA_RATE_100                             (0b00111 << 3)
#define DATA_RATE_400                             (0b01000 << 3)
#define DATA_RATE_1200                            (0b01001 << 3)
#define DATA_RATE_2400                            (0b01010 << 3)
#define DATA_RATE_4800                            (0b01011 << 3)
#define DATA_RATE_7200                            (0b01100 << 3)
#define DATA_RATE_14400                           (0b01101 << 3)
#define DATA_RATE_19200                           (0b01110 << 3)
#define DATA_RATE_25600                           (0b01111 << 3)
#define DATA_RATE_40000                           (0b10000 << 3)
#define DATA_RATE_RESET_MASK                     ~(0b11111 << 3)

#define DIGITAL_FILTER_REGISTER                                   (DATA_RATE_REGISTER)
#define FILTER_SINC1                              (0b000 << 0)
#define FILTER_SINC2                              (0b001 << 0)
#define FILTER_SINC3                              (0b010 << 0)
#define FILTER_SINC4                              (0b011 << 0)
#define FILTER_FIR                                (0b100 << 0)/*Default*/
#define FILTER_RESET_MASK                        ~(0b111 << 0)


#define CHOP_MODE_REGISTER                                        (0x03)
#define CHOP_MODE_NORMAL                          (0b00 << 5)/*Default*/
#define CHOP_MODE_CHOP_MODE                       (0b01 << 5)
#define CHOP_MODE_RESET_MASK                     ~(0b11 << 5)/*Default*/

#define CONVERSION_MODE_REGISTER                                  (CHOP_MODE_REGISTER)
#define CONVERSION_MODE_CONTINIOUS                (0 << 4)/*Default*/
#define CONVERSION_MODE_PULSE                     (1 << 4)
#define CONVERSION_MODE_RESET_MASK               ~(1 << 4)

#define CONVERSION_START_DELAY_REGISTER                           (CHOP_MODE_REGISTER)
#define CONVERSION_START_DELAY_0u                 (0b0000 << 0)
#define CONVERSION_START_DELAY_50u                (0b0001 << 0)/*Default*/
#define CONVERSION_START_DELAY_59u                (0b0010 << 0)
#define CONVERSION_START_DELAY_67u                (0b0011 << 0)
#define CONVERSION_START_DELAY_85u                (0b0100 << 0)
#define CONVERSION_START_DELAY_119u               (0b0101 << 0)
#define CONVERSION_START_DELAY_189u               (0b0110 << 0)
#define CONVERSION_START_DELAY_328u               (0b0111 << 0)
#define CONVERSION_START_DELAY_605u               (0b1000 << 0)
#define CONVERSION_START_DELAY_1_16m              (0b1001 << 0)
#define CONVERSION_START_DELAY_2_27m              (0b1010 << 0)
#define CONVERSION_START_DELAY_4_49m              (0b1011 << 0)
#define CONVERSION_START_DELAY_8_89m              (0b1100 << 0)
#define CONVERSION_START_DELAY_17_8m              (0b1101 << 0)
#define CONVERSION_START_RESET_MASK              ~(0b1111 << 0)



#define REFERENCE_CONFIG_REGISTER                                 (0x06)
#define INTERNAL_REFERENCE_ENABLE                 (1 << 4)
#define INTERNAL_REFERENCE_DISABLE                (0 << 4)/*Default*/
#define INTERNAL_REFERENCE_RESET_MASK            ~(1 << 4)

#define SELECT_POS_REFERENCE_INTERNAL             (0b00 << 2)
#define SELECT_POS_REFERENCE_AVDD                 (0b01 << 2)/*Default*/
#define SELECT_POS_REFERENCE_AIN0                 (0b10 << 2)
#define SELECT_POS_REFERENCE_AIN2                 (0b11 << 2)

#define SELECT_NEG_REFERENCE_INTERNAL             (0b00 << 0)
#define SELECT_NEG_REFERENCE_AVSS                 (0b01 << 0)/*Default*/
#define SELECT_NEG_REFERENCE_AIN1                 (0b10 << 0)
#define SELECT_NEG_REFERENCE_AIN3                 (0b11 << 0)

#define SELECT_REFERENCE_RESET_MASK              ~(0b1111 << 0)

#define OFFSET_CAL_LOW_BYTE_REG                                   (0x07)
#define OFFSET_CAL_MID_BYTE_REG                                   (0x08)
#define OFFSET_CAL_HIGH_BYTE_REG                                  (0x09)

#define FSCALE_CAL_LOW_BYTE_REG                                   (0x0A)
#define FSCALE_CAL_MID_BYTE_REG                                   (0x0B)
#define FSCALE_CAL_HIGH_BYTE_REG                                  (0x0C)

#define INPUT_MUX_REGISTER                                        (0x11)

#define POS_INPUT_MUX_SELECT_AINCOM               (0b0000 << 4)
#define POS_INPUT_MUX_SELECT_AIN0                 (0b0001 << 4)
#define POS_INPUT_MUX_SELECT_AIN1                 (0b0010 << 4)
#define POS_INPUT_MUX_SELECT_AIN2                 (0b0011 << 4)
#define POS_INPUT_MUX_SELECT_AIN3                 (0b0100 << 4)
#define POS_INPUT_MUX_SELECT_AIN4                 (0b0101 << 4)
#define POS_INPUT_MUX_SELECT_INT_TEMP_SENSOR_POS  (0b1011 << 4)
#define POS_INPUT_MUX_SELECT_INT_AVDD_DIV4_POS    (0b1100 << 4)
#define POS_INPUT_MUX_SELECT_INT_DVDD_DIV4_POS    (0b1101 << 4)
#define POS_INPUT_MUX_SELECT_INPUTS_OPEN          (0b1110 << 4)
#define POS_INPUT_MUX_SELECT_VCOM                 (0b1111 << 4)

#define NEG_INPUT_MUX_SELECT_AINCOM               (0b0000 << 4)
#define NEG_INPUT_MUX_SELECT_AIN0                 (0b0001 << 0)
#define NEG_INPUT_MUX_SELECT_AIN1                 (0b0010 << 0)
#define NEG_INPUT_MUX_SELECT_AIN2                 (0b0011 << 0)
#define NEG_INPUT_MUX_SELECT_AIN3                 (0b0100 << 0)
#define NEG_INPUT_MUX_SELECT_AIN4                 (0b0101 << 0)
#define NEG_INPUT_MUX_SELECT_INT_TEMP_SENSOR_NEG  (0b1011 << 0)
#define NEG_INPUT_MUX_SELECT_INT_AVDD_DIV4_NEG    (0b1100 << 0)
#define NEG_INPUT_MUX_SELECT_INT_DVDD_DIV4_NEG    (0b1101 << 0)
#define NEG_INPUT_MUX_SELECT_INPUTS_OPEN          (0b1110 << 0)
#define NEG_INPUT_MUX_SELECT_VCOM                 (0b1111 << 0)
#define INPUT_MUX_SELECT_RESET_MASK              ~(0b00000000 << 0)

//      --- LOKALE TYPE DEFS - bitte hier dokumentieren-------------------------------

//      --- DEFINITIONEN GLOBALER VARIABLEN - Bitte in Header dokumentieren ----------
uint32_t ahCounter[50];
int32_t nrOfValuesCurrent;
int32_t avgValWithOffsetCompensation;
int32_t avgValWithOffsetCommonModeOffsetCorrection;
int32_t avgValWithOffsetCommonModeOffsetTemperatureCorrection;
double current;
double currentWithGainCorrection;
double currentWithGainAndGainShuntTempCorrection;
//double currentWithGainAndGainShuntTempAndGainChipTempCorrection;
//      --- LOKALE VARIABLEN - bitte hier dokumentieren ------------------------------
static adc_state_enum_t ads1260DataCoversionState;

static const uint8_t RREG_BaseOpcode = 0x20;                                                 // Read Register CMD
static const uint8_t WREG_BaseOpcode = 0x40;                                                 // Write Register CMD
static const uint8_t LOCK_Opcode = 0xF2;                                                     // Lock registers modification CMD
static const uint8_t RDATA_Opcode = 0x12;                                                    // Read conversion DATA CMD

static const uint8_t MODE3_regAdr = 0x05;                                                    // MODE3 register address
static const uint8_t MODE3_STATENB = 6U;                                                     // Status enable bit position in MODE3 register
static const uint8_t MODE3_CRCENB = 5U;                                                      // CRC enable bit position in MODE3 register

static const uint8_t STATUS_regAdr = 0x01;
static const uint8_t STATUS_LOCK = 7U;
static const uint8_t STATUS_CRCERR = 6U;
static const uint8_t STATUS_REFL_ALM = 3U;
static const uint8_t STATUS_DRDY = 2U;


static const uint8_t arbitraryByte = 0xEC;                                                   // Don't care byte
static const uint8_t replyHeader = 0xFF; 

//      --- LOKALE FUNKTIONS PROTOTYPEN ----------------------------------------------
static void ADS_1260_SetConversionMode(SPI_HandleTypeDef * hspi, uint8_t conversionMode);
static void ADS_1260_SetInternalReference(SPI_HandleTypeDef * hspi);
static void ADS_1260_SetExternalReference(SPI_HandleTypeDef * hspi);
static void ADS_1260_InputMuxSelect(SPI_HandleTypeDef * hspi, uint8_t muxSelect);
static void ADS_1260_SetChopMode(SPI_HandleTypeDef * hspi, uint8_t chopMode);
static void ADS_1260_ActivateStatusData(void);
static void ADS_1260_ActivateLock(void);

static uint32_t ADS1260_ProcessCurrent(int32_t current);
volatile uint32_t newCurrentValue=0;
//static uint32_t ADS1260_ProcessVoltage(int32_t voltage, sys_data_t * data);
//static uint32_t ADS1260_ProcessTemperature(int32_t temperature, sys_data_t * data);

// Funktionen werden extern

//      --- LOKALE FUNKTIONEN - bitte hier dokumentieren -----------------------------

/*
* @brief        Einstellung Conversion Mode
* @param        kein
* @retval       kein
*/
static void ADS_1260_SetConversionMode(SPI_HandleTypeDef * hspi, uint8_t conversionMode)
{
  uint8_t spiData[DATA_ARRAY_SIZE];
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + CONVERSION_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Modify
  spiData[SEND_DATA_POS] = ((spiData[RECEIVE_DATA_POS] & CONVERSION_MODE_RESET_MASK) | conversionMode); // so gefriemelt dass der Conversionsmodus gesetzt wird und der Rest des Registers unberührt beleibt
  // Write
  spiData[COMMAND_POS] = (REGISTER_WRITE_COMMAND + CONVERSION_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, SEND_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + CONVERSION_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verify
  if((spiData[RECEIVE_DATA_POS] & conversionMode) != conversionMode)
  {
    printf("ERROR ADS_1260_SetConversionMode\n");
    while(1);
  }

}

/*
* @brief        Einstellung Chop Mode
* @param        kein
* @retval       kein
*/
static void ADS_1260_SetChopMode(SPI_HandleTypeDef * hspi, uint8_t chopMode)
{
  uint8_t spiData[DATA_ARRAY_SIZE];
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + CHOP_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Modify
  spiData[SEND_DATA_POS] = ((spiData[RECEIVE_DATA_POS] & CHOP_MODE_RESET_MASK) | chopMode); // so gefriemelt dass der Conversionsmodus gesetzt wird und der Rest des Registers unberührt beleibt
  // Write
  spiData[COMMAND_POS] = (REGISTER_WRITE_COMMAND + CHOP_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, SEND_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + CHOP_MODE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verify
  if((spiData[RECEIVE_DATA_POS] & chopMode) != chopMode)
  {
    printf("ERROR ADS_1260_SetChopMode\n");
    while(1);
  }
}

/*
* @brief        Einstellung Datarate
* @param        kein
* @retval       kein
*/
void ADS_1260_SetDataRate(SPI_HandleTypeDef * hspi, uint8_t dataRate)
{
  uint8_t spiData[DATA_ARRAY_SIZE];
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + DATA_RATE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Modify
  spiData[SEND_DATA_POS] = ((spiData[RECEIVE_DATA_POS] & DATA_RATE_RESET_MASK) | dataRate); // so gefriemelt dass die Datarate gesetzt wird und der Rest des Registers unberührt beleibt
  // Write
  spiData[COMMAND_POS] = (REGISTER_WRITE_COMMAND + DATA_RATE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, SEND_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + DATA_RATE_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verify
  if((spiData[RECEIVE_DATA_POS] & dataRate) != dataRate)
  {
    printf("ERROR ADS_1260_SetDataRate\n");
    while(1);
  }

}

/*
* @brief        Einstellung Filtertyp
* @param        kein
* @retval       kein
*/
void ADS_1260_SetDigitalFilter(SPI_HandleTypeDef * hspi, uint8_t digitalFilter)
{
  uint8_t spiData[DATA_ARRAY_SIZE];
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + DIGITAL_FILTER_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Modify
  spiData[SEND_DATA_POS] = ((spiData[RECEIVE_DATA_POS] & FILTER_RESET_MASK) | digitalFilter); // so gefriemelt dass der Filter gesetzt wird und der Rest des Registers unberührt beleibt
  // Write
  spiData[COMMAND_POS] = (REGISTER_WRITE_COMMAND + DIGITAL_FILTER_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, SEND_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + DIGITAL_FILTER_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, RECEIVE_DATA_NR_OF_BYTES, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verify
  if((spiData[RECEIVE_DATA_POS] & digitalFilter) != digitalFilter)
  {
    printf("ERROR ADS_1260_SetDigitalFilter\n");
    while(1);
  }
}

/*
* @brief        schaltet über die Mux die Eingänge auf den ADC
* @param        kein
* @retval       kein
*/
static void ADS_1260_InputMuxSelect(SPI_HandleTypeDef * hspi, uint8_t muxSelect)
{
  // Write
  uint8_t spiData[3] = {(REGISTER_WRITE_COMMAND + INPUT_MUX_REGISTER), muxSelect, 0};
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 2, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + INPUT_MUX_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 3, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verifie
  if(spiData[RECEIVE_DATA_POS] != muxSelect)
  {
    printf("ERROR ADS_1260_InputMuxSelect\n");
//    while(1);
  }
}


/*
* @brief        schaltet die interne 2.500 Volt Referenzspannungsquelle ein
*               und wählt diese als Referenspannungsquelle aus
* @param        kein
* @retval       kein
*/
static void ADS_1260_SetInternalReference(SPI_HandleTypeDef * hspi)
{
  // Write
  uint8_t spiData[3] = {(REGISTER_WRITE_COMMAND + REFERENCE_CONFIG_REGISTER), (INTERNAL_REFERENCE_ENABLE + SELECT_POS_REFERENCE_INTERNAL + SELECT_NEG_REFERENCE_INTERNAL), 0};
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 2, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + REFERENCE_CONFIG_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 3, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verifie
  if(spiData[RECEIVE_DATA_POS] != (INTERNAL_REFERENCE_ENABLE + SELECT_POS_REFERENCE_INTERNAL + SELECT_NEG_REFERENCE_INTERNAL))
  {
    printf("ERROR ADS_1260_SetInternalReference\n");
    while(1);
  }

}


/*
* @brief        schaltet die interne 2.500 Volt Referenzspannungsquelle ein
*               und wählt diese als Referenspannungsquelle aus
* @param        kein
* @retval       kein
*/
static void ADS_1260_SetExternalReference(SPI_HandleTypeDef * hspi)
{
  // Write
  uint8_t spiData[3] = {(REGISTER_WRITE_COMMAND + REFERENCE_CONFIG_REGISTER), (INTERNAL_REFERENCE_DISABLE + SELECT_POS_REFERENCE_AIN0 + SELECT_NEG_REFERENCE_AIN1), 0};
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 2, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Read
  spiData[COMMAND_POS] = (REGISTER_READ_COMMAND + REFERENCE_CONFIG_REGISTER);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(hspi, spiData, spiData, 3, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
  HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);
  // Verifie
  if(spiData[RECEIVE_DATA_POS] != (INTERNAL_REFERENCE_DISABLE + SELECT_POS_REFERENCE_AIN0 + SELECT_NEG_REFERENCE_AIN1))
  {
    printf("ERROR ADS_1260_SetInternalReference\n");
    while(1);
  }

}





/************************************************** KAL *****************************************************************/
/*
* @brief        Software Offsetkalibrierung für die Strommessung.
*               Voraussetzungen: Es darf kein Strom über den Shunt fließen.
*                                Warten bis Mittelwertbildung abgeschlossen ist.
* @param        kein
* @retval       kein
*/
void ADS_1260_BatteryCurrentOffsetCalibrationStart(sys_data_t * data)
{
  data->s.parameter.batteryCurrentOffset = data->s.values.battryCurrentRaw;
  data->s.parameter.batteryCurrentOffsetRefTemperatureShunt = data->s.values.shuntTemperature;
  data->s.parameter.batteryCurrentOffsetRefTemperatureChip = data->s.values.chipTemperature;
  data->s.parameter.batteryCurrentOffsetRefshuntVoltage = data->s.values.shuntVoltage;
  EEPROM_storeConfig(&sys_data,0);
}

void ADS_1260_BatteryCurrentOffsetCommonModeErrorComepensationStart(sys_data_t * data)
{
  //speichere geänderte CommonMode Spannung
  data->s.parameter.batteryCurrentOffsetCommonModeCalibrationVoltage = data->s.values.shuntVoltage;

  //Delta berechnen
  //Kompensationswert speichern in ADC Steps *1000 pro mV Common Mode Voltage
  int32_t deltaU = data->s.parameter.batteryCurrentOffsetCommonModeCalibrationVoltage - data->s.parameter.batteryCurrentOffsetRefshuntVoltage;

  //Entstandene Abweichung durch Common Mode Fehler, ist aktueller Messwert mit vorherigen Kompensationen
  int32_t deltaADC =  avgValWithOffsetCompensation;
  int32_t compensationFactor = deltaADC * 1000 / deltaU;
  data->s.parameter.batteryCurrentOffsetCommonModeCompensationFactor = compensationFactor;
  EEPROM_storeConfig(&sys_data,0);
}

void ADS_1260_BatteryCurrentOffsetTemperatureErrorComepensationStart(void)
{
  //speichere geänderte Temperatur
  //Achtung die Offset Kompeensation machen wir hier absichtlich mit der Chip Temperatur und nicht mit der Shunt Temperatur
  //Die Chip spiegeelt genaueer die Temperatur der ADC und Strommessverstärker wieder. Der Offset driftt hängt von der Temp der ADC/VREF/Messverstrker zusammen
  //und nicht mit der Temp der Shunt Widerstände
  sys_data.s.parameter.batteryCurrentOffsetTemperatureCalibrationTemperature = sys_data.s.values.chipTemperature;


  //Delta berechnen
  int32_t deltaT = sys_data.s.parameter.batteryCurrentOffsetTemperatureCalibrationTemperature - sys_data.s.parameter.batteryCurrentOffsetRefTemperatureChip;
  int32_t deltaADC =  avgValWithOffsetCommonModeOffsetCorrection;
  int32_t compensationFactor = deltaADC * 1000 / deltaT;
  sys_data.s.parameter.batteryCurrentOffsetTemperatureCompensationFactor = compensationFactor;
  EEPROM_storeConfig(&sys_data,0);
}




void ADS_1260_BatteryCurrentGainCalibrationStart(sys_data_t * data)
{
  double helper;
  printf("--- Gain  CAL ---");
  if(data->s.parameter.batteryCurrentGainRefCurrent == 0) // Fehler
  {
    printf("ADS_1260_BatteryCurrentGainCalibrationStart: ERROR IN CALIBRATION, NO REFERENCE CURRENT!\n");
    return;
  }



  // Sollstrom durch Batteriestrom teilen
  // Sollstrom ist in mA also umrechen in A, da Batteriestrom ("current") auch in A
  // ACHTUNG Das Punkt 0 ist wichtig, muss mit Fließkomma Berechnung durchgeführt werden!!!!
  helper = (data->s.parameter.batteryCurrentGainRefCurrent / 1000.0 ) / current;
  // in den Batteriegain umrechnen
  data->s.parameter.batteryCurrentGainCorrectionFaktor = (helper * 1000000.0);
  // schreibe Temperatur bei der kalibriert wurde
  data->s.parameter.batteryCurrentGainRefTempShunt = data->s.values.shuntTemperature;
  data->s.parameter.batteryCurrentGainRefTempChip  = data->s.values.chipTemperature;

  printf("I (without compensation)=%f\n", current);
  printf("I Referenz=%f\n", data->s.parameter.batteryCurrentGainRefCurrent / 1000.0);
  printf("Tshunt=%f\n", data->s.parameter.batteryCurrentGainRefTempShunt/100.0);
  printf("Tship=%f\n", data->s.parameter.batteryCurrentGainRefTempChip/100.0);
  printf("Korrekturfaktor=%f\n", data->s.parameter.batteryCurrentGainCorrectionFaktor*1000000.0 );
  printf("--- Gain  CAL ENDE---");
  EEPROM_storeConfig(&sys_data,0);
}
//Self Heat Kompensation
void ADS_1260_BatteryCurrentGainTemperatureCalibrationShuntStart(void)
{
  double helper;
  printf("--- Gain Drift CAL ---");
  //speichere aktuelle Temperatur
  sys_data.s.parameter.batteryCurrentGainTemperatureCalibrationShuntTemperature = sys_data.s.values.shuntTemperature;
  printf("Actual T=%f C\n", sys_data.s.parameter.batteryCurrentGainTemperatureCalibrationShuntTemperature/100.0);
  //Temperaturänderung berechnen
  int32_t deltaTShunt = ( sys_data.s.values.shuntTemperature - sys_data.s.parameter.batteryCurrentGainRefTempShunt);
  printf("delta T=%f C\n", deltaTShunt/100.0);

  helper = currentWithGainCorrection;
  printf("Acutal I=%f A(without gain temp drift correction)\n", currentWithGainCorrection);
  printf("Ref I=%f\n", sys_data.s.parameter.batteryCurrentGainRefCurrent/1000.0);
  // Sollstrom durch Batteriestrom   teilen
  // wir erhalten den Korrektur Faktor für die aktuelle Temperatur
  helper = (sys_data.s.parameter.batteryCurrentGainRefCurrent/1000.0) / helper;

  // Speichere Korrekturfaktor pro Schritt Temperaturänderung
  helper = helper - 1.0;

  helper = helper / (deltaTShunt);

  //Speicher um Faktor 10000000 erhöht um Kommazahlen zu vermeiden
  sys_data.s.parameter.batteryCurrentGainTemperatureCompensationShuntFactor = helper*1000000000.0;

  printf("Korrekturfaktor=%f [ 1 / Celsius]\n", (sys_data.s.parameter.batteryCurrentGainTemperatureCompensationShuntFactor  / 1000000000.0 * 100) + 1.0 );
  printf("--- Gain Drift CAL ENDE ---");
  EEPROM_storeConfig(&sys_data,0);
}

////Ambient Temperature
//void ADS_1260_BatteryCurrentGainTemperatureCalibrationChipStart()
//{
//  double helper;
//  //speichere geänderte Temperatur
//  sys_data.s.parameter.batteryCurrentGainTemperatureCalibrationChipTemperature = sys_data.s.values.chipTemperature;
//  int32_t deltaT = sys_data.s.values.chipTemperature - sys_data.s.parameter.batteryCurrentGainRefTempChip;
//
//
//  helper = currentWithGainAndGainShuntTempCorrection;
//  // Sollstrom durch Batteriestrom   teilen
//  // wir erhalten den Korrektur Faktor für die aktuelle Temperatur
//  helper = (sys_data.s.parameter.batteryCurrentGainRefCurrent/1000.0) / helper;
//
//  // Speichere Korrekturfaktor pro Schritt Temperaturänderung
//  helper = helper - 1.0;
//
//  helper = helper / deltaT;
//
//  //Speicher um Faktor 10000000 erhöht um Kommazahlen zu vermeiden
//  sys_data.s.parameter.batteryCurrentGainTemperatureCompensationChipFactor = helper*1000000000.0;
//
//}


/*
* @brief        Rohwerte ADC in Strom umrechnen
* @param        kein
* @retval       kein
*/

#define BATTERY_CURRENT_FILTER 2

static uint32_t ADS1260_ProcessCurrent(int32_t newval)
{
   static signed long avgsum = 0;
   static int meas_counter;
   if (meas_counter < INT32_MAX) meas_counter++;
   int32_t avgval;

   // Filterlängen in 2er-Potenzen --> Compiler optimiert
   avgsum -= avgsum/ BATTERY_CURRENT_FILTER;
   avgsum += newval;
   avgval = avgsum / BATTERY_CURRENT_FILTER;
   sys_data.s.values.battryCurrentRaw = avgval;
  /**********************Offset Kompensation:*******************************/
  // Offset abziehen
  avgValWithOffsetCompensation = avgval - sys_data.s.parameter.batteryCurrentOffset;
  // Temperaturabhängiges Offset abziehen
  // in ADC Messwerten mal Abweichung von Referenttemperatur
  //current = current - ((sys_data.s.ads1260.s.offsetTemperatureFactorCurrent / 1000.0) * ((sys_data.s.device.parameter.shuntTemperature - sys_data.s.ads1260.s.refTempSoftwareOffsetCalibrationCurrent)/1000.0));
  /**********************Offset Kompensation:*******************************/


  /********************** START Common Mode Kompensation:*******************************/
  //Berechne Änderung der aktuellen Spannung am Shunt zu der Spannung am shunt bei Kalibrierung
  int32_t commonModeDeltaU = ((int32_t)sys_data.s.values.shuntVoltage - (int32_t)sys_data.s.parameter.batteryCurrentOffsetRefshuntVoltage) ;
  int32_t commonModeErrorAdcSteps = (commonModeDeltaU * sys_data.s.parameter.batteryCurrentOffsetCommonModeCompensationFactor) / 1000.0 ;
  sys_data.s.values.batteryCurrentOffsetCommonModeCorrectionADCSteps = commonModeErrorAdcSteps;
  avgValWithOffsetCommonModeOffsetCorrection = avgValWithOffsetCompensation - commonModeErrorAdcSteps;
  /********************** ENDE Common Mode Kompensation:*******************************/

  /********************** START Offset Temperature Kompensation*******************************/
  //Berechne Änderung der aktuellen Spannung am Shunt zu der Spannung am shunt bei Kalibrierung
  //Achtung wir arbeiten für die Offset Temperatur Kompenssation mit der Chip Temperatur, nicht mit der Shunt Temperatur, vgl Kal. Faunktion
  double temperatureDeltaT = ((int32_t)sys_data.s.values.chipTemperature - (int32_t) sys_data.s.parameter.batteryCurrentOffsetRefTemperatureChip);
  int32_t temperatureErrorAdcSteps = (temperatureDeltaT * sys_data.s.parameter.batteryCurrentOffsetTemperatureCompensationFactor) / 1000.0 ;
  avgValWithOffsetCommonModeOffsetTemperatureCorrection = avgValWithOffsetCommonModeOffsetCorrection - temperatureErrorAdcSteps;
  /********************** ENDE Offset Temperature Kompensation *******************************/




  // ADC Messwerte nach Mittwelwertbildung und Offset speichern
  //sys_data.s.ads1260.s.mwADCStepsWithOffsetCorrectionCurrent = current;

  // 250 resultiert aus 100µOhm Shunt + (Verstärkung Strommessverstärker = 20) * 2 -> Umrechnung in Strom
  // 200 resultiert aus 125µOhm Shunt + (Verstärkung Strommessverstärker = 20) * 2 -> Umrechnung in Strom
  // 2.5 = Vref, externe Referenz ist 3.0V
  // 0x800000 = ADC Auflösung
  #if (DEVICETYPE == 500)
  current = ((avgValWithOffsetCommonModeOffsetTemperatureCorrection * (double)3.0 * 200.0) / (double)0x800000);
  #elif (DEVICETYPE == 250)
  current = ((avgValWithOffsetCommonModeOffsetTemperatureCorrection * (double)3.0 * 100.0) / (double)0x800000);
  #elif (DEVICETYPE == 125)
  current = ((avgValWithOffsetCommonModeOffsetTemperatureCorrection * (double)3.0 * 50.0) / (double)0x800000);
  #else
  #error No valid device type
  #endif
  // Gain aus Sysdata
  currentWithGainCorrection = current * (sys_data.s.parameter.batteryCurrentGainCorrectionFaktor / 1000000.0);

  /**********************Gain Temperatur Kompensation:*******************************/
  // Wenn sich in Abhängigkeit von der Temperatur das Gain ändert wird der Messwert mit einem Wert 1 +/- einem kleinen Faktor
  // der abhängig von der Temperaturabweichung ist multipliziert
  //ausgabe = ausgabe * ( 1 + ((sys_data.s.ads1260.s.gainTemperatureFactorCurrent * ((sys_data.s.device.parameter.shuntTemperature - sys_data.s.ads1260.s.refTempSoftwareGainCalibrationCurrent) / 1000.0) / 1000000000.0)));
  /**********************Gain Temperatur Kompensation:*******************************/

  #ifdef PRINT_BATTERY_CURRENT
  // Ausgabe runden auf %f.3
  printf("battery current = %.4fA\n", current);
  #endif




  double temperatureDeltaTShunt;
  //double temperatureDeltaTChip;
  temperatureDeltaTShunt = ((int32_t)sys_data.s.values.shuntTemperature - (int32_t) sys_data.s.parameter.batteryCurrentGainRefTempShunt);
  //temperatureDeltaTChip = ((int32_t)sys_data.s.values.chipTemperature - (int32_t) sys_data.s.parameter.batteryCurrentGainRefTempChip);

  // Gain Temperaturkompensation anwenden - Shunt
  double f = (sys_data.s.parameter.batteryCurrentGainTemperatureCompensationShuntFactor / 1000000000.0);
  double k = 1.0 + (temperatureDeltaTShunt  * f);
  currentWithGainAndGainShuntTempCorrection = currentWithGainCorrection * k;


  // Gain Temperaturkompensation anwenden - Ambient
  //double f2 = (sys_data.s.parameter.batteryCurrentGainTemperatureCompensationChipFactor / 1000000000.0);
  //double k2 = 1.0 + (  temperatureDeltaTChip * f2);
  //k2=1; //Testabschaltung
  //currentWithGainAndGainShuntTempAndGainChipTempCorrection = currentWithGainAndGainShuntTempCorrection * k2;



 // printf("i=%f A. ist=%f, fs=%f, dTs=%f\n", currentWithGainCorrection, currentWithGainAndGainShuntTempCorrection, k,  temperatureDeltaTShunt );

  //Endergebniss in mA speichern
  #if (DEVICETYPE == 500)
  if ((currentWithGainAndGainShuntTempCorrection > 550.0) || (currentWithGainAndGainShuntTempCorrection < -550.0))
  {
	sys_data.s.values.batteryCurrent = sys_data.s.values.fast_current;
  }
  else
  {
	sys_data.s.values.batteryCurrent = currentWithGainAndGainShuntTempCorrection * 1000.0;
  }
  #elif (DEVICETYPE == 250)
  if ((currentWithGainAndGainShuntTempCorrection > 275.0) || (currentWithGainAndGainShuntTempCorrection < -275.0))
  {
	sys_data.s.values.batteryCurrent = sys_data.s.values.fast_current;
  }
  else
  {
	sys_data.s.values.batteryCurrent = currentWithGainAndGainShuntTempCorrection * 1000.0;
  }
  #elif (DEVICETYPE == 125)
  if ((currentWithGainAndGainShuntTempCorrection > 137.0) || (currentWithGainAndGainShuntTempCorrection < -137.0))
  {
	sys_data.s.values.batteryCurrent = sys_data.s.values.fast_current;
  }
  else
  {
	sys_data.s.values.batteryCurrent = currentWithGainAndGainShuntTempCorrection * 1000.0;
  }
  #else
  #error No valid device type
  #endif



  if (meas_counter > (BATTERY_CURRENT_FILTER *10)) // Nur aktualiseren, wenn es schon ausreichend Messwerte gab
  {
    // höchster und niedrigster Stromwert werden gespeichert
    if(sys_data.s.values.batteryCurrent > sys_data.s.values.batteryCurrentMax)
    {
      sys_data.s.values.batteryCurrentMax = sys_data.s.values.batteryCurrent;
    }
    if(sys_data.s.values.batteryCurrent < sys_data.s.values.batteryCurrentMin)
    {
      sys_data.s.values.batteryCurrentMin = sys_data.s.values.batteryCurrent;
    }
  }
  
  newCurrentValue=1;

  return 0;
}


//      --- GLOBALE FUNKTIONEN - bitte in Header dokumentieren------------------------

void ADS1260_init(void)
{
   uint8_t sdata[10] = {0x47,0x00,0x00,0x00,0x00,0x00};
  /* 0*/ ads1260DataCoversionState = ADC_STATE_INITIALIZE;
  /* 3*/ HAL_GPIO_WritePin(ADC_START_CONV_GPIO_Port, ADC_START_CONV_Pin, GPIO_PIN_SET);
         HAL_Delay(150); // Delay weil die Vref braucht zeit um sich zu stabilisieren (siehe Datenblatt Seite 9)
  /* 1*/ //HAL_GPIO_WritePin(ADC_POWER_DOWN_GPIO_Port, ADC_POWER_DOWN_Pin, GPIO_PIN_RESET);
         //HAL_Delay(150); // Delay weil die Vref braucht zeit um sich zu stabilisieren (siehe Datenblatt Seite 9)
  /* 1*/ //HAL_GPIO_WritePin(ADC_POWER_DOWN_GPIO_Port, ADC_POWER_DOWN_Pin, GPIO_PIN_SET);
         //HAL_Delay(150); // Delay weil die Vref braucht zeit um sich zu stabilisieren (siehe Datenblatt Seite 9)
  /* 2*/ HAL_GPIO_WritePin(ADC_RESET_GPIO_Port, ADC_RESET_Pin, GPIO_PIN_RESET);
         HAL_Delay(150); // Delay weil die Vref braucht zeit um sich zu stabilisieren (siehe Datenblatt Seite 9)
  /* 2*/ HAL_GPIO_WritePin(ADC_RESET_GPIO_Port, ADC_RESET_Pin, GPIO_PIN_SET);
         HAL_Delay(150); // Delay weil die Vref braucht zeit um sich zu stabilisieren (siehe Datenblatt Seite 9)
  /* 3*/ HAL_GPIO_WritePin(ADC_START_CONV_GPIO_Port, ADC_START_CONV_Pin, GPIO_PIN_RESET);

  /* 4*/ //while(HAL_GPIO_ReadPin(ADC_DATA_READY_GPIO_Port, ADC_DATA_READY_Pin) == GPIO_PIN_RESET);
         HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
         HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);

  /* 5*/ ADS_1260_SetExternalReference(&hspi1);
         HAL_Delay(150);
  /* 6*/ ADS_1260_SetDataRate(&hspi1, DATA_RATE_20);
  //  /* 7*/ ADS_1260_SetDigitalFilter(&hspi1, FILTER_SINC4);
  /* 8*/ ADS_1260_SetConversionMode(&hspi1, CONVERSION_MODE_CONTINIOUS);
         // langsamer
         ADS_1260_SetChopMode(&hspi1, CHOP_MODE_CHOP_MODE);
         ADS_1260_InputMuxSelect(&hspi1, POS_INPUT_MUX_SELECT_AIN2 + NEG_INPUT_MUX_SELECT_AIN3);

         ADS_1260_ActivateStatusData();
         ADS_1260_ActivateLock();

  /*10*/ //ADS_1260_SelfOffsetCalibration(&hspi1);
         HAL_Delay(150);
  /*x*/  ads1260DataCoversionState = ADC_STATE_READY_FOR_CONVERSION;
         ADS1260_StartConversion();
}


void ADS1260_StartConversion(void)
{
  HAL_GPIO_WritePin(ADC_START_CONV_GPIO_Port, ADC_START_CONV_Pin, GPIO_PIN_SET);
}

void ADS1260_ReadConversion(void)
{
    extern CRC_HandleTypeDef hcrc;
    convert_union_t convert;

    //                                                    CRC2
    uint8_t spiDataIn[9] = { RDATA_Opcode, arbitraryByte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    spiDataIn[2] = HAL_CRC_Calculate(&hcrc, (uint32_t*) spiDataIn, 2);
    uint8_t spiDataOut[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    int32_t value = 0;
    HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, spiDataIn, spiDataOut, 9, DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
    HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

    if (spiDataOut[0] == replyHeader && spiDataOut[1] == spiDataIn[0] && spiDataOut[2] == spiDataIn[1] && spiDataOut[3] == spiDataIn[2] && spiDataOut[8] == HAL_CRC_Calculate(&hcrc, (uint32_t*) &spiDataOut[4], 4))
    {
        uint8_t STATUS_reg = spiDataOut[4];

        if ((STATUS_reg & (1 << STATUS_LOCK)) && (STATUS_reg & (1 << STATUS_DRDY)) && !(STATUS_reg & (1 << STATUS_CRCERR)) && !(STATUS_reg & (1 << STATUS_REFL_ALM)))
        {
            // Rohwerte Byteswitch
            convert.s[3] = 0;
            convert.s[2] = spiDataOut[5];
            convert.s[1] = spiDataOut[6];
            convert.s[0] = spiDataOut[7];

            // Vorzeichen ausrechnen (24 bit MSB = Vorzeichenbit muss auf 32 bit umgesetzt werden)
            if(convert.w >= 0x800000)
            {
              convert.sw = -(0xFFFFFF - convert.w);
              value = convert.sw;
            }
            else if(convert.w < 0x800000)
            {
              //convert.sw = convert.w;
              value = convert.w;
            }
        }
        else
        {
            sys_data.s.values.adc_restarts++;
            ADS1260_init();
        }

    }
    else
    {
        sys_data.s.values.adc_restarts++;
        ADS1260_init();
    }

    ADS1260_ProcessCurrent(value);
}

//-----------------------------------------------------------------------------

static void ADS_1260_ActivateLock(void)
{
    extern CRC_HandleTypeDef hcrc;
    const int maxReTries = 5;
    int lockIsWritten = 0;

    for (int i = 0; i < maxReTries; i++)
    {
        // Sendin LOCK command                        CRC2
        uint8_t Din[] = { LOCK_Opcode, arbitraryByte, 0x00, 0x00 };
        Din[2] = HAL_CRC_Calculate(&hcrc, (uint32_t*) Din, 2);
        uint8_t Dout[] = { 0x00, 0x00, 0x00, 0x00 };

        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
        HAL_SPI_TransmitReceive(&hspi1, Din, Dout, sizeof(Din) / sizeof(Din[0]), DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

        if (Dout[0] == replyHeader && Dout[1] == Din[0] && Dout[2] == Din[1] && Dout[3] == Din[2])
        {
            lockIsWritten = 1;
            break;
        }
        else continue;    
    }

    if (!lockIsWritten)
        while (1)
        {   // Blink the RED LED forever
            HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
            HAL_Delay(350);
        }

    int lockIsWrittenCorrect = 0;
    // Reading STATUS register to make sure that LOCK is active  
    for (int i = 0; i < maxReTries; i++)
    {
        // Reading the content of the STATUS register                     CRC2
        uint8_t Din[] = { RREG_BaseOpcode | STATUS_regAdr, arbitraryByte, 0x00, 0x00, 0x00, 0x00 };
        Din[2] = HAL_CRC_Calculate(&hcrc, (uint32_t*) Din, 2);
        uint8_t Dout[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
        HAL_SPI_TransmitReceive(&hspi1, Din, Dout, sizeof(Din) / sizeof(Din[0]), DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

        if (Dout[0] == replyHeader && Dout[1] == Din[0] && Dout[2] == Din[1] && Dout[3] == Din[2] && Dout[5] == HAL_CRC_Calculate(&hcrc, (uint32_t*)&Dout[4], 1))
        {
            uint8_t STATUS_reg = Dout[4];
            if (STATUS_reg & (1U << STATUS_LOCK))
            {
                lockIsWrittenCorrect = 1;
                break;
            }
        }
        else continue;    
    }
    
    if (!lockIsWrittenCorrect)
        while (1)
        {   // Blink the RED LED forever
            HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
            HAL_Delay(400);
        }
    
}

//-----------------------------------------------------------------------------

static void ADS_1260_ActivateStatusData(void)
{
    extern CRC_HandleTypeDef hcrc;
    const int maxReTries = 5;
    int mode3IsRead = 0;
    uint8_t MODE3_Reg;

    for (int i = 0; i < maxReTries; i++)
    {
        // Reading the content of the MODE3 register
        uint8_t Din[] = { RREG_BaseOpcode | MODE3_regAdr, arbitraryByte, 0x00 };
        uint8_t Dout[] = { 0x00, 0x00, 0x00 };

        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
        HAL_SPI_TransmitReceive(&hspi1, Din, Dout, sizeof(Din) / sizeof(Din[0]), DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

        if (Dout[0] == replyHeader && Dout[1] == Din[0])
        {
            MODE3_Reg = Dout[2];    // Saving the content of the MODE3 register
            mode3IsRead = 1;
            break;
        }
        else continue;    
    }
    
    if (!mode3IsRead)
        while (1)
        {   // Blink the RED LED forever
            HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
            HAL_Delay(200);
        }

    // Setting STATENB and CRCENB bits in MODE3 register
    MODE3_Reg |= (1U << MODE3_STATENB) | (1U << MODE3_CRCENB);

    int mode3IsWritten = 0;

    for (int i = 0; i < maxReTries; i++)
    {
        // Writing back the content of the MODE3 register
        uint8_t Din[] = { WREG_BaseOpcode | MODE3_regAdr, MODE3_Reg };
        uint8_t Dout[] = { 0x00, 0x00 };

        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
        HAL_SPI_TransmitReceive(&hspi1, Din, Dout, sizeof(Din) / sizeof(Din[0]), DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

        if (Dout[0] == replyHeader && Dout[1] == Din[0])
        {
            mode3IsWritten = 1;
            break;
        }
        else continue;    
    }

    if (!mode3IsWritten)
        while (1)
        {   // Blink the RED LED forever
            HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
            HAL_Delay(250);
        }

    int mode3IsWrittenCorrect = 0;

    // We have activated CRC in every data packet, so we need take it into account
    for (int i = 0; i < maxReTries; i++)
    {
        // Reading one more time the content of the MODE3 register       CRC2
        uint8_t Din[] = { RREG_BaseOpcode | MODE3_regAdr, arbitraryByte, 0x00, 0x00, 0x00, 0x00 };
        Din[2] = HAL_CRC_Calculate(&hcrc, (uint32_t*) Din, 2);
        uint8_t Dout[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_RESET);
        HAL_SPI_TransmitReceive(&hspi1, Din, Dout, sizeof(Din) / sizeof(Din[0]), DEFAULT_ADS1260_TRANSMIT_RECEIVE_TIMEOUT);
        HAL_GPIO_WritePin(ADC_SPI1_NSS_GPIO_Port, ADC_SPI1_NSS_Pin, GPIO_PIN_SET);

        if (Dout[0] == replyHeader && Dout[1] == Din[0] && Dout[2] == Din[1] && Dout[3] == Din[2] && Dout[5] == HAL_CRC_Calculate(&hcrc, (uint32_t*)&Dout[4], 1))
        {
            if ((Dout[4] & (1U << MODE3_STATENB)) && (Dout[4] & (1U << MODE3_CRCENB)))
            {
                mode3IsWrittenCorrect = 1;
                break;
            }
        }
        else continue;    
    }
    
    if (!mode3IsWrittenCorrect)
        while (1)
        {   // Blink the RED LED forever
            HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
            HAL_Delay(300);
        }
}

//-----------------------------------------------------------------------------

void ADS1260_ConversionFinished(void)
{
  ADS1260_ReadConversion();
 // ADS1260_StartConversion();
}

//-----------------------------------------------------------------------------