#ifndef PLX_AIN_IMPL_H_
#define PLX_AIN_IMPL_H_

#include "hwbf_adc.h"

#define PLX_AIN_NUM_CHANNELS 32

// Definitions for specifying reference mode
#define ADC_INTERNAL    0x0
#define ADC_EXTERNAL    0x1
#define ADC_VDDA        0x3

// Definitions for specifying reference voltage
#define ADC_VREF3P3     1
#define ADC_VREF2P5     0

//
// Definitions for specifying an ADC
#define ADC_ADCA        0
#define ADC_ADCB        1
#define ADC_ADCC        2
#define ADC_ADCD        3
#define ADC_ADCE        4


typedef enum PLX_AIN_UNIT {
  PLX_AIN_ADC_A = 0,
  PLX_AIN_ADC_B,
  PLX_AIN_ADC_C,
  PLX_AIN_ADC_D,
  PLX_AIN_ADC_E,
} PLX_AIN_Unit_t;


typedef struct PLX_AIN_ADC_PARAMS {
  union ADC_ADCINTSEL1N2_REG ADCINTSEL1N2;
  union ADC_ADCCTL1_REG ADCCTL1;
  union ADC_ADCCTL2_REG ADCCTL2;
  union ADC_ADCSOCPRICTL_REG ADCSOCPRICTL;
  bool sigmodeDifferential;
  float vref;
} PLX_AIN_AdcParams_t;

typedef struct PLX_AIN_CHANNEL_PARAMS {
  union ADC_ADCSOC0CTL_REG ADCSOCxCTL;
  float scale;
  float offset;
} PLX_AIN_ChannelParams_t;

typedef struct PLX_AIN_OBJ {
  volatile struct ADC_REGS *adc;
  union ADC_ADCSOC0CTL_REG *socCtrl;
  volatile uint16_t *results;
  float scale[PLX_AIN_NUM_CHANNELS];
  float offset[PLX_AIN_NUM_CHANNELS];
  float voltsPerAdcBit;
  float voltsOffsetAdcDiff;
  bool sigmodeDifferential;
} PLX_AIN_Obj_t;

#include "ain_type5.h"

static inline void PLX_AIN_setDefaultAdcParams(PLX_AIN_AdcParams_t *aParams, float aVref, bool sigmodeDifferential)
{
  // maximal clock rate is 60 Mhz, minimum is 5 MHz
  if (PLX_AIN_SysClkHz <= 60000000L) {
    aParams->ADCCTL2.bit.PRESCALE = 0;  // set ADCCLK divider to /1.0
  } else if (PLX_AIN_SysClkHz <= 120000000L) {
    aParams->ADCCTL2.bit.PRESCALE = 2;  // set ADCCLK divider to /2.0
  } else if (PLX_AIN_SysClkHz <= 150000000L) {
    aParams->ADCCTL2.bit.PRESCALE = 3;  // set ADCCLK divider to /2.5
  } else if (PLX_AIN_SysClkHz <= 180000000L) {
    aParams->ADCCTL2.bit.PRESCALE = 4;  // set ADCCLK divider to /3.0
  } else {
    aParams->ADCCTL2.bit.PRESCALE = 5;  // set ADCCLK divider to /3.5
  }

  aParams->ADCCTL1.bit.INTPULSEPOS = 1; // set pulse positions to late
  aParams->ADCSOCPRICTL.bit.SOCPRIORITY = 0;  // round-robin - no high priority channels
  aParams->ADCINTSEL1N2.bit.INT1SEL = 0;

  aParams->vref = aVref;
  aParams->sigmodeDifferential = sigmodeDifferential;
}

#endif /* PLX_AIN_IMPL_H_ */
