#include "xc.h"
#include "config.h"
#include "init.h"
#include "extern.h"
#include "CalibrationConstants.h"
#include "../CommonCode/conv.h"
#include "libq.h"
#include "../CommonCode/crc.h"
#include "../CommonCode/CRSAL.h"
#include "../CommonCode/pl_interp.h"

fractional abcCoefficient_Zoom[3] __attribute__((section(".xbss")));
fractional controlHistory_Zoom[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)


void InitIO()
{

    //Setup digital I/O
    //Setup digital outputs
    TRISA = 0x0000;  //Default to all outputs
    TRISAbits.TRISA9 = 1; //Don't make this an output, it's connected to ground as Vref-.
    TRISAbits.TRISA10 = 1; //Don't make this an output, it's connected to 3.3V as Vref+.

    TRISB = 0x0000;  //Default to all outputs
    TRISBbits.TRISB10 = 1; //Set Pin 34 as input, required for ADC AN10 to work correctly.
    TRISBbits.TRISB6 = 1; //Set as input for ICD, not sure if this is required, seems unlikely...
    TRISBbits.TRISB7 = 1; //Set as input for ICD, not sure if this is required, seems unlikely...
    TRISBbits.TRISB2 = 0; //SS1 set as output
       
    //TRISC = 0x0000   //Default to all outputs  Commented out because it's not clear what effect setting these to outputs has on the clocks, left for now at power up defaults...
    
    TRISD = 0x0000;  //Default to all outputs
    TRISDbits.TRISD1 = 0; //AUXIO_PIN 3 Set as Output
    TRISDbits.TRISD2 = 1; //TEMP_FLAG Set as Input
    TRISDbits.TRISD3 = 1; //AFT_H20_ALARM_ACTIVELOW as Input
    TRISDbits.TRISD4 = 0; //CAMERA_POWER as Output
    TRISDbits.TRISD5 = 0; //LASER_POWER_ACTIVELOW as Output
    TRISDbits.TRISD6 = 1; //OVERTEMP_ACTIVELOW as Input
    TRISDbits.TRISD8 = 0; //AUXIO_PIN2 Set as Output
    TRISDbits.TRISD9 = 0; //AUXIO_PIN5 Set as Output
    TRISDbits.TRISD10 = 0; //EEPRPROM_WP Set as Output
    TRISDbits.TRISD12 = 1; //FWD_H20_ALARM_ACTIVELOW as Input
    TRISDbits.TRISD13 = 0; //EXTENDER Set as Output
    TRISDbits.TRISD14 = 1; //U1CTS Set as input
    TRISDbits.TRISD15 = 0; //U1RTS Set as output
           
    TRISE = 0x0000;//Default to all outputs
    
    TRISF = 0x0000;
    TRISFbits.TRISF2 = 1; //U1 Rx
    TRISFbits.TRISF3 = 0; //U1 Tx  
    TRISFbits.TRISF4 = 1; //U2 Rx
    TRISFbits.TRISF5 = 0; //U2 Tx  
    TRISFbits.TRISF6 = 0; //SCK1
    TRISFbits.TRISF7 = 1; //SDI1
    TRISFbits.TRISF8 = 0; //SD01
    TRISFbits.TRISF12 = 1; //U2CTS Set as input
    TRISFbits.TRISF13 = 0; //U2RTS Set as output
    
    TRISG = 0x0000;
    TRISGbits.TRISG2 = 0; //I2C Clock
    TRISGbits.TRISG3 = 1; //I2C Data
    TRISGbits.TRISG6 = 1; //SCK2
    TRISGbits.TRISG7 = 1; //SDI2
    TRISGbits.TRISG8 = 0; //SDO2
    //TRISGbits.TRISG9 = 1; //SS2
    TRISGbits.TRISG9 = 0; //SS2  //BlueWire
    
    EXTENDER_ACTIVELOW = 1;  //Start without extender (ActiveLow, 0 = Extended)
    
}




void InitVariables()
{
    SerialDataIn = &SerialDataIn_A;  //Start by pointing at A buffer.
    
    SerialDataOut.preamble = 0x5555;
    SerialDataOut.CameraTemp = 0xdead;
    SerialDataOut.crc =  calcCRC((const char*) &SerialDataOut,sizeof(BottomToTopDataPacket)-2);
            
    
    ComputeScaling();
            
    TopStatus = 0;
    BottomStatus = 0;
    
    RateZeroAdjust = POWERUP_ZERORATEADJUST;
    
    int Focus_X[2] = {-32768, 32767};  // Data from topside is encoded as full range of fractional value.]
    int Focus_Y[2] = {FOCUS_CAMERA_MIN_CNTS, FOCUS_CAMERA_MAX_CNTS};  //Must be monotonically increasing unique values 
    pl_interp_init(&Focus_interp,2,Focus_X,Focus_Y);
}

void InitPIDGains()
{

    //Set up PID structures.
       
    Zoom_PID.abcCoefficients = &abcCoefficient_Zoom[0];
    Zoom_PID.controlHistory = &controlHistory_Zoom[0];
    PIDInit(&Zoom_PID);
    Zoom_GSAL.GainScaleFactor = 0;  //Used to Scale output of PID calculation, specified in bits to shift result, so powers of two..
    kCoeffs_Zoom[0] = Q15(.1); //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_Zoom[1] = Q15(0.0); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_Zoom[2] = Q15(0.0); //Der Gain    controller must be scaled up.
    Zoom_GSAL.LowerActuatorLimit = -32768;  //Can lower target bus voltage to limit battery current
    Zoom_GSAL.UpperActuatorLimit = 32767;      //Not allowed to raise target bus voltage
    PIDCoeffCalc((fractional *) & kCoeffs_Zoom[0], &Zoom_PID);
    
    
}

void InitDma0()  //DMA channel 0 is used to transfer data at the end of the ADC conversion process
{
DMA0CONbits.AMODE = 0; // Configure DMA for Register indirect with post increment (used with conversion order mode)
DMA0CNT = NUMAIO*INNERFILTERSAMPLES-1;

DMA0CONbits.MODE = 2; // Configure DMA for Continuous mode with ping-pong
DMA0PAD = (int)&ADC1BUF0;
DMA0REQ = 13;  //Select ADC1 convert done
DMA0STA = __builtin_dmaoffset(BufferA);
DMA0STB = __builtin_dmaoffset(BufferB);
_DMA0IP = 5;
IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
IEC0bits.DMA0IE = 1; //Set the DMA interrupt enable bit
DMA0CONbits.CHEN = 1;

}




// This sets up the ADC sample and convert sequence.  This ADC is set up to run in scan mode,
// it cycles throught the specified channels.  After all are converted a DMA transfer
// occurs which transfers all values into memory locations.
// This conversions are started in the PWM interrupt, it cycles through the number of specified channels (NUMIO))
// and samples (INNERFILTERSAMPLES) and after a total of NUMAIO*INNERFILTERSAMPLES samples initiates a DMA interrupt 
// indicating that the conversion is done. 
// With this interrupt set to occur at xxkHz, and x channels to be scanned, new
// analog data is available at xkHz, although the samples were all taken x.xx microseconds apart.










void InitADC_WithIntrpt()
{
    AD1CON1bits.SSRC = 2;  //Clock source select -  010 causes Timer3 compare to end sampling and start conversion

    AD1CON1bits.ASAM = 1; //Auto-sample start bit, this is enabled in PWM interupt.
    AD1CON1bits.AD12B = 1; //12 bit mode, disables simultaneous sampling
    AD1CON1bits.FORM = 2; //Report Results as un-signed Integers.  i.e. dddd dddd dddd 0000 is the twelve bits

    AD1CON2bits.VCFG = 3; //Use VRef+/VRef- as reference, driven by precision reference in our board.
    AD1CON2bits.BUFM = 0;
    AD1CON2bits.CSCNA = 1;  //ScanINput Selections for CH0+ during Sample A bit
    AD1CON2bits.CHPS = 0;  //Converts CH0

    AD1CON3bits.ADCS = 4;  //Conversion clock select - Conversion time is 5*Tcy, see datasheet
    AD1CON3bits.SAMC = 0x1f;  //Auto-sample time bits.  This is only used in SSRC = 7...
    
    AD1PCFGH = AIOMASK_H; // select specified analog input pins
    AD1PCFGL = AIOMASK_L; // select specified analog input pins

    AD1CSSH = ~AIOMASK_H; // Scan specified inputs
    AD1CSSL = ~AIOMASK_L; // Scan specified inputs
//Use Conversion Order mode
    AD1CON1bits.ADDMABM = 1;  //DMA buffers are built in conversion order mode.
    AD1CON2bits.SMPI = NUMAIO-1;

# if INNERFILTERSAMPLES == 1
    AD1CON4bits.DMABL = 0;
# endif
# if INNERFILTERSAMPLES == 2
    AD1CON4bits.DMABL = 1;
# endif
# if INNERFILTERSAMPLES == 4
    AD1CON4bits.DMABL = 2;
# endif
# if INNERFILTERSAMPLES == 8
    AD1CON4bits.DMABL = 3;
# endif
# if INNERFILTERSAMPLES == 16
    AD1CON4bits.DMABL = 4;
# endif
# if INNERFILTERSAMPLES == 32
    AD1CON4bits.DMABL = 5;
# endif
# if INNERFILTERSAMPLES == 64
    AD1CON4bits.DMABL = 6;
# endif
# if INNERFILTERSAMPLES == 128
    AD1CON4bits.DMABL = 7;
# endif


    _AD1IF = 0;  //Clear Interrupt
    _AD1IE = 0;  //Do not Enable ADC Interrupt
    AD1CON1bits.ADON = 0;  //Don't enable ADC yet, wait until everything else is set up and enable in main

}




void InitSPI() {

    SPI1CON1bits.DISSCK = 0;
    SPI1CON1bits.DISSDO = 0;
    SPI1CON1bits.MODE16 = 1;
    SPI1CON1bits.SMP = 0;
    SPI1CON1bits.CKE = 0;
    SPI1CON1bits.SSEN = 0;
    SPI1CON1bits.CKP = 0;
    SPI1CON1bits.MSTEN = 1;
    SPI1CON1bits.SPRE = 4; //4;
    SPI1CON1bits.PPRE = 2;

    _SPI1IP = 6;
    _SPI1IF = 0;          // Clear the Interrupt flag
    _SPI1IE = 1;           // Enable the interrupt



    SPI1STATbits.SPIROV = 0;
    SPI1STATbits.SPIEN = 0;  //Keep Disabled for now

    SPI2CON1bits.DISSCK = 0;
    SPI2CON1bits.DISSDO = 0;
    SPI2CON1bits.MODE16 = 1;
    SPI2CON1bits.SMP = 0;
    SPI2CON1bits.CKE = 0;
    //SPI2CON1bits.SSEN = 1; 
    SPI2CON1bits.SSEN = 0;   //BlueWire
    SPI2CON1bits.CKP = 0;
    SPI2CON1bits.MSTEN = 0;


    _SPI2IP = 6;
    _SPI2IF = 0;           // Clear the Interrupt flag
    _SPI2IE = 1;           // Don't Enable the interrupt, not needed


    //SPI2STATbits.SPIEN = 0;  //Keep SPI2 disabled for now


}
