/*
 * adcUtil.c
 *
 *  Created on: Oct 6, 2018
 *      Author: robert.applebee
 */

// includes
#include <stdint.h>
#include <stdbool.h>
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "inc/hw_memmap.h"
#include "adcUtil.h"

void ADCseq0Handler();
void ADCseq1Handler();

unsigned int adcResults[20];
int adcGroup = 0;

void ADC_init(void)
{
    //
    // Enable the ADC0 module.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //
    // Wait for the ADC0 module to be ready.
    //
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)) { }

    //
    // Set external VREF (+2.5V not 3V)
    //
    ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);

    //
    // Enable the ADC1 module.
    // ADC1 is programmed to capture +24V and +24I
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);

    //
    // Set external VREF (+2.5V not 3V)
    //
    ADCReferenceSet(ADC1_BASE, ADC_REF_EXT_3V);

    //
    // Wait for the ADC1 module to be ready.
    //
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC1)) { }

    //
    // Program the first sample sequencer to capture the value of channel 0 through 5 when
    // the process trigger occures.
    // Add additional capture to workaround bug.
    //
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH0);
    ADCIntRegister(ADC0_BASE, 0, &ADCseq0Handler);
    ADCIntEnable(ADC0_BASE, 0);
    ADCSequenceEnable(ADC0_BASE, 0);

    //
    // Enable the first sample sequencer to capture the value of channel 18 and 19 when
    // the processor trigger occurs.
    //
    ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH18);
    ADCSequenceStepConfigure(ADC1_BASE, 0, 1, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH19);
    ADCIntRegister(ADC1_BASE, 0, &ADCseq1Handler);
    ADCIntEnable(ADC1_BASE, 0);
    ADCSequenceEnable(ADC1_BASE, 0);

    //
    // Trigger the sample sequence.
    //
    ADCProcessorTrigger(ADC0_BASE, 0);

    //
    // Trigger the sample sequence.
    //
    ADCProcessorTrigger(ADC1_BASE, 0);

}

void ADC_get24v(double *voltage, double *current)
{

    *current = 0.4 * adcResults[18] / 4096.0 * 2.5;
    *voltage = 11.0 * adcResults[19] / 4096.0 * 2.5;
}

//
// This function is the interrupt handler for ADC0.  It captures the ADC results
// from AIN0 through AIN17 in groups of six.
//
// Sample data is stored in the "adcResults" array in positions 0 - 17.
//
// The interrupt is generated after six inputs are sampled and then programs the sample sequencer
// for the next group.
//
// A seventh sample was added to work around a bug that was causing AIN5 sample to be set in AIN11 and AIN17.
//
void ADCseq0Handler()
{
    unsigned int u32[8];
    int count;
    int i;

    ADCIntClear(ADC0_BASE, 0);

    // get the sample data
    count = ADCSequenceDataGet(ADC0_BASE, 0, u32);
    if (count == 7) {
        for (i = 0; i < 6; i++)
            adcResults[adcGroup * 6 + i] = u32[i];

        // update the group
        adcGroup = (adcGroup == 2)? 0: adcGroup + 1;

        // program next group of channels for capture
        switch (adcGroup) {
        case 0:
            //
            // Program the first sample sequencer to capture the value of channel 0 through 5 when
            // the process trigger occures.
            // Add additional capture to workaround bug.
            //
            ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH0);
            break;
        case 1:
            //
            // Program the first sample sequencer to capture the value of channel 6 through 11 when
            // the process trigger occures.
            // Add additional capture to workaround bug.
            //
            ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH6);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH7);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH8);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH9);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH10);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH11);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH0);
            break;
        case 2:
            //
            // Program the first sample sequencer to capture the value of channel 12 through 17 when
            // the process trigger occures.
            // Add additional capture to workaround bug.
            //
            ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH12);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH13);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH14);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH15);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH16);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH17);
            ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH0);
            break;
        default:
            break;
        }
    }

    //
    // Trigger the sample sequence.
    //
    ADCProcessorTrigger(ADC0_BASE, 0);

}

//
// This function is the interrupt handler for ADC1.  It captures the ADC results
// from AIN18 and AIN19.
//
// Sample data is stored in the "adcResults" array in positions 18 and 19.
//
// The interrupt is generated after both inputs are sampled.
//
void ADCseq1Handler()
{
    unsigned int u32[8];
    int count;

    ADCIntClear(ADC1_BASE, 0);

    count = ADCSequenceDataGet(ADC1_BASE, 0, u32);
    if (count == 2) {
        adcResults[18] = u32[0];
        adcResults[19] = u32[1];
    }

    //
    // Trigger the sample sequence.
    //
    ADCProcessorTrigger(ADC1_BASE, 0);
}

