#include "AD_DA.h"

/*---------------------Global variables for ADC----------------------------------*/
static const Pin pinsSPI[]  = {PINS_SPI, PIN_SPI_NPCS1_PA31, PIN_SPI_NPCS0_PA11};
static const Pin LDAC = PIN_LDAC;
static const Pin BUSY_ADC = PIN_BUSY_ADC;
static const Pin CNVST = PIN_CNVST;

/*------------Functions fo DAC--------------*/
extern void DAC_SendCommand(uint16_t prvni8, uint16_t druhy8, uint16_t treti8)
{
    uint32_t dump;

    SPI_Write(SPI, 1, prvni8);
    dump = SPI_Read(SPI);
    SPI_Write(SPI, 1, druhy8 );
    dump = SPI_Read(SPI);
    SPI_Write(SPI, 1, treti8 | SPI_TDR_LASTXFER );
    SPI->SPI_CR ^= SPI_CR_LASTXFER;
    dump = SPI_Read(SPI);
}

void DAC_Init(void)
{
    /*pins inicialization used for communication */
    PIO_Configure(pinsSPI, PIO_LISTSIZE(pinsSPI));
    PIO_Configure(&LDAC, PIO_LISTSIZE(LDAC));
    PIO_Configure(&CNVST, PIO_LISTSIZE(CNVST));
    PIO_Configure(&BUSY_ADC, PIO_LISTSIZE(BUSY_ADC));
    
    PIO_Set(&CNVST);

    DAC_SendCommand(12, 0, 4); /* first dump transmition, why?? but without that it doesnt work */
    DAC_SendCommand(12, 0, 4); /* set range to +-10V for both channels */
    DAC_SendCommand(16, 0, 5); /* turn ON choosen channels, than 10us delay is needed */
}

/* Set voltage on choosen DA channel, when success returns 1 otherwise 0 */
extern uint8_t DAC_Set_Voltage(uint8_t channel, float Uout)
{
    uint8_t data1, data2;
    float D;
    uint32_t dump;

    if ((Uout <= 10) || (Uout >= -10))
    {
        D = (Uout + 10)*819.2; /* (Uout+10)*819.2 */
        if (D == 16384)
            D--;
        data1 = (uint32_t)D >> 6;
        data2 =((uint32_t)D & 0x3F) << 2; 
        PIO_Set(&LDAC);
        SPI_Write(SPI, 1, channel);
        dump = SPI_Read(SPI);
        SPI_Write(SPI, 1, data1);
        dump = SPI_Read(SPI);
        SPI_Write(SPI, 1, data2 | SPI_TDR_LASTXFER);
        SPI->SPI_CR ^= SPI_CR_LASTXFER;
        dump = SPI_Read(SPI);
        PIO_Clear(&LDAC);
        return 1;
    }
    else
        return 0;
}

/*--------------------- ADC functions -----------------------------------------*/
extern void ADC_ReadVoltage (float *in_array)
{
    float *ReadVoltage = in_array;
    uint16_t firstV = 0, secondV = 0;

    PIO_Clear(&CNVST); /*conversion start */
    PIO_Set(&CNVST);
    while (PIO_Get(&BUSY_ADC));  /* wait for conversion */

    SPI_Write(SPI, 0, 0); /* dump TX */
    firstV = SPI_Read(SPI);  /* read Recieved voltage A */


    SPI_Write(SPI, 0, 0 | SPI_TDR_LASTXFER); /* dump TX with rise of CS at the end of TX/RX */
    SPI->SPI_CR ^= SPI_CR_LASTXFER;
    secondV = SPI_Read(SPI);  /* read Recieved voltage B */

    if (firstV & (1 << 13))
    {
        firstV = (~firstV) & 0x3FFF - 1;
        ReadVoltage[0] = firstV*(-1.22e-3);
    }
    else
        ReadVoltage[0] = firstV*(1.22e-3);

    if (secondV & (1 << 13))
    {
        secondV = (~secondV) & 0x3FFF - 1;
        ReadVoltage[1] = secondV*(-1.22e-3);
    }
    else
        ReadVoltage[1] = secondV*(1.22e-3);
}
