#include <dsp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xc.h"
#include "math.h"
#include "UART.h"
#include "config.h"
#include "extern.h"
#include "conv.h"
#include "isr.h"
#include "config.h"
#include "CalibrationConstants.h"
#include "libq.h"

extern unsigned int pos;


extern int step;
extern unsigned int halls;



fractional fooQ15;
float foo;
unsigned int *Buff; //Pointer to appropriate DMA Buffer, switched on PingPong


//This DMA interrupt occurs at the rate of the TMR3 interrupt divided by the number of
// analog channels that are scanned.  (i.e TMR3 at 80kHz, 20 conversions of 8 channels = 500kHz
// This interrupt include all dsp work takes about 200uS (measured 5/25/2015)
void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
//void __attribute__((__interrupt__(__save__(CORCON)))) _DMA0Interrupt(void)
{
    static int i = 0;
    int i_last;
//    int j;
    static unsigned long paddlewheel_cnt_history[PADDLEWHEEL_FILTERSAMPLES];
    static int first_time = 1;
//    static fractional Pressure_Offset;
//    static fractional I_Flow_Offset;

//    long Pressure;
//    long I_Flow;

    
    __asm__ volatile ("push CORCON");


    if (DMACS1 & 0x0001) //Point to one buffer or the other depending on which one caused interrupt
        Buff = BufferB;
    else
        Buff = BufferA;

//    if(first_time)  //Compute analog counts cooresponding to zero's of engineering units.
 //     {
 //     Pressure_Offset = ConvertEngUnitsToInt(0.0, Pressure_cnt, Pressure_eng);
 //     I_Flow_Offset = ConvertEngUnitsToInt(0.0, I_Flow_cnt, I_Flow_eng);
 //     }

#ifdef ALLOW_CALIBRATION
    if(raw) //Remove offset if in calibration mode
    {
      Pressure_Offset = 0;
      I_Flow_Offset = 0;
      first_time = 1;
    }
#endif

    // BuffferA/BufferB and Buff are unsigned integers, because the ADC is set up to represent data as unsigned fractionals (integers),
    // this is appropriate.  Below all variables that get set from the ADC values are signed integers, this doesn't introduce a lack
    // of precision for variables that are always positive (like VBus) because it's a 12-bit ADC, so representing it in 15 bits instead
    // of 16 doesn't change much.  The ADC FORMAT setting could be used to produce variables as signed integers, but this isn't used to
    // give some control over the zero-point, which may not fall exactly half-way between 0 and Vref in every case.

    //If the analog inputs used (or their ordering) are changed, the next lines must be changed to match
    //Additionally the analog input pin specification must be changed in init.c

//     for (j = 0; j < FILTERSAMPLES; j++)
//         {
//         Pressure_ADC[j] = _Q15sub(Buff[0 + NUMAIO * j] >> 1,Pressure_Offset); //AN0 - spare
//         I_Flow_ADC[j] = _Q15sub(Buff[1 + NUMAIO * j] >> 1,I_Flow_Offset); //AN1 -
//         }



    //Filter Analog Signals.
    //This uses the dsp library and changes the CORCON register.
    // Therefore interrupts that occur during this time must protect the CORCON and possibly other registers.
    
//    FIR(FILTERSAMPLES, &outSamples[0], &Pressure_ADC[0], &ADC_Filter);
//    Pressure_Buf[i] = outSamples[FILTERSAMPLES - 1]; //Store current value for use later.
       
//    FIR(FILTERSAMPLES, &outSamples[0], &I_Flow_ADC[0], &ADC_Filter);
//    I_Flow_Buf[i] = outSamples[FILTERSAMPLES - 1]; //Store current value for use later.

    paddlewheel_cnt_history[i] = paddlewheel_cnts;  //Store current count.
    
    FlowTotal_2 = ((float) paddlewheel_cnt_history[i])/K_FACTOR;  //Totalize in Liters

    time = time + 1.0/OUTPUT_RATE;
    time_relative = time_relative + 1.0/OUTPUT_RATE;

    AD1CON1bits.ASAM = 0;// Stop ADC, we have what we need.

    i_last = i+1;
    if(i_last >= PADDLEWHEEL_FILTERSAMPLES)
        i_last = 0;
    if(paddlewheel_cnt_history[i] > paddlewheel_cnt_history[i_last])  //Totalizer Reset hasn't happened
      FlowRate_2 = 60.0*(paddlewheel_cnt_history[i]-paddlewheel_cnt_history[i_last])/K_FACTOR;
    else
      FlowRate_2 = 0;


    if(i == PADDLEWHEEL_FILTERSAMPLES-1)  //Collected a series of samples, now process and send out the data, the code in this if statement runs at the T3 interrupt rate (25Hz)
    {
   
    //Form data for sending out over RS-232.
  //  Pressure = 0L;
  //  I_Flow = 0L;

  //  for (j = 0; j < REPORTINGSAMPLES; j++)
  //     {
  //      Pressure += Pressure_Buf[j]; //N-m
  //      I_Flow += I_Flow_Buf[j];
  //     }

  //  Pressure = Pressure/ REPORTINGSAMPLES;
  //  I_Flow = I_Flow / REPORTINGSAMPLES;
  

  //  DiffPressure = ConvertFractToEngUnits((int) Pressure, Pressure_cnt, Pressure_eng),
  //  FlowRate_1 = ConvertFractToEngUnits((int) I_Flow, I_Flow_cnt,  I_Flow_eng);
  //  FlowTotal_1 += FlowRate_1/OUTPUT_RATE;

    i = 0;

    IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit (otherwise it seems to come right back from sleep)

    //Idle();  //This shuts down the main clock, but TMR1 is using the clock from SOSC so will continue to count and cause an interrupt
              // This interrupt, or a wake on bus activity interrupt for the can module will bring the device back from sleep.
    //PORTE = 0;  //Turn both off;

    }
    else  //We haven't collected all the analog i/o needed for averaging, so keep going.
    {
       i++;
       IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
    }


    __asm__ volatile ("pop CORCON");
    

}


// TMR1 Interrupt  25Hz, Starts ADC sampling, after enough samples are collected (specified by FILTERSAMPLES and REPORTINGSAMPLES),
// the dma interrupt sends out the CAN packet and stops adc sampling until this isr starts it again.  If sleep mode is being used, it is this
// interrupt that wakes the processor from sleep generally, and the dma interrupt puts it back to sleep after the can packets have been sent.
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
//void __attribute__((__interrupt__(__save__(CORCON))))     _T1Interrupt(void)
{
    __asm__ volatile ("push CORCON");

AD1CON1bits.ASAM = 1; //Auto-sample start bit
  
    _T1IF = 0;
    __asm__ volatile ("pop CORCON");
   

}

void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void)
//void __attribute__((__interrupt__(__save__(CORCON)))) _CNInterrupt(void)
{
    if(_RD5 == 1)  //Only increment on transition to high
       paddlewheel_cnts++;
    _CNIF = 0; // Clear interrupt
}