#include "h/p33FJ64GP802.h"
#include "h/common.h"
#include "h/dac.h"
#include "h/adc.h"

unsigned int adcDataRecord;
unsigned int adcDataReady;
unsigned int adcDataReadyPtr;
unsigned int adcDataBufferSample;
unsigned int adcDropped;
unsigned int adcLoopBack;
unsigned int adcDataRecordReq;
unsigned int adcCh;
int adcIndex;
int adcPeriod;
int adcResult[8];
long adcTotal;

void initADC(void)
{
        AD1CON1bits.ADON 	= 0;		// Turn on the A/D converter	
		AD1CON1bits.FORM   	= 3;		// Data Output Format: Signed Fraction (Q15 format)
		AD1CON1bits.SSRC   	= 7;		// Sample Clock Source
		AD1CON1bits.ASAM   	= 1;		// ADC Sample Control: Sampling begins immediately after conversion
		AD1CON1bits.AD12B  	= 1;		// 10-bit ADC operation
		AD1CON2bits.CSCNA 	= 1;		// Scan Input Selections for CH0+ during Sample A bit
		AD1CON2bits.CHPS  	= 0;		// Converts CH0
		AD1CON3bits.ADRC 	= 0;		// ADC Clock is derived from Systems Clock
		AD1CON3bits.ADCS 	= 6;		// ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
		AD1CON2bits.SMPI 	= 0;		// 2 ADC Channel is scanned
		AD1CON1bits.ASAM	= 1;
		AD1CON3bits.SAMC	= 0b11111;
		//AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
		AD1CSSL = 0x0000;
		AD1CSSLbits.CSS0=1;			// Enable AN0 for channel scan
		AD1CSSLbits.CSS1=0;			// Enable AN1 for channel scan
		//AD1PCFGH/AD1PCFGL: Port Configuration Register
		AD1PCFGL=0xFFFF;
		AD1PCFGLbits.PCFG0 = 0;		// AN4 as Analog Input
		AD1PCFGLbits.PCFG1 = 0;		// AN4 as Analog Input
		adcCh=0;
		adcDataRecord=0;
		adcDataRecordReq=0;
		adcDataReady=0;
		adcDataReadyPtr=0;
		adcDataBufferSample=0;
		adcDropped=0;
		adcLoopBack=0;
		adcIndex=0;
		adcTotal=0;
		adcPeriod=8;          
        IFS0bits.AD1IF = 0;			// Clear the A/D interrupt flag bit
        IEC0bits.AD1IE = 1;			// Enable A/D interrupt 
        AD1CON1bits.ADON = 1;		// Turn on the A/D converter	
}

int readAN(unsigned char channel)
{
	int i;
	// reads AN0
	AD1CHS0=(0x001F & channel);
	AD1CON1bits.SAMP=1;
	for(i=0; i<200; i++)asm("nop");
	AD1CON1bits.SAMP=0;
	while(AD1CON1bits.DONE==0);
	return ADC1BUF0;
}

void selectChannel(int ch)
{
	AD1CON1bits.ADON=0;
	AD1CSSL=0;
	if(ch==0)
	{
	AD1CSSLbits.CSS0=1;
	AD1CSSLbits.CSS1=0;
	} else
	{
	AD1CSSLbits.CSS0=0;
	AD1CSSLbits.CSS1=1;
	}
	adcIndex=0;
	AD1CON1bits.ADON=1;
}

void startRecord(void)
{
	selectChannel(adcCh);
	adcDataReady=1;
	adcLoopBack=0;
	adcDataRecordReq=1;
	adcDataRecord=1;
}

void endRecord(void)
{
	adcDataRecordReq=0;
	adcDataRecord=1;
	while(adcDataRecord==1)asm("nop");
	adcDataReady=0;
	adcDataReadyPtr=0;
	adcDropped=0;
}

void continueRecord(void)
{
	adcDataRecordReq=1;
	adcDataRecord=1;
}

void __attribute__((interrupt, no_auto_psv))_ADC1Interrupt(void)
{
	int xx;

 	adcIndex++;
	if(adcIndex>=adcPeriod)adcIndex=0;
	if(adcIndex==0)
	{
	adcResult[0]=ADC1BUF0;
	adcTotal+=adcResult[0];
	if(adcDataRecord)
    {
			xx=__builtin_divsd(adcTotal, adcPeriod);
			adcTotal=0;
			dataBuffer[adcDataBufferSample]=(int)xx; 
	    	if(adcDataBufferSample<(ADC_BUFFER_SIZE-1))adcDataBufferSample++; else adcDataBufferSample=0;
            if((adcDataBufferSample==0)||(adcDataBufferSample==ADC_HALF_BUFFER_SIZE))
            {
               if(adcDataReady) 
                {
                    if(adcDataBufferSample==0)adcDataReadyPtr=ADC_HALF_BUFFER_SIZE; else adcDataReadyPtr=0;
                    adcDataReady=0;
                } else adcDropped++;   
				if(adcDataRecordReq==0)adcDataRecord=0;
            }    
    }
	} else
	{
	adcResult[adcIndex]=ADC1BUF0;
	adcTotal+=adcResult[adcIndex];
	}
    IFS0bits.AD1IF=0;
}

