#include "xc.h"
#include "config.h"
#include "init.h"
#include "extern.h"
#include "CalibrationConstants.h"
#include "conv.h"
#include "libq.h"
#include "CRSAL.h"


fractional abcCoefficient_Id[3] __attribute__((section(".xbss")));
fractional controlHistory_Id[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_Iq[3] __attribute__((section(".xbss")));
fractional controlHistory_Iq[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_Vel[3] __attribute__((section(".xbss")));
fractional controlHistory_Vel[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_ShuntReg[3] __attribute__((section(".xbss")));
fractional controlHistory_ShuntReg[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_BattChargeILim[3] __attribute__((section(".xbss")));
fractional controlHistory_BattChargeILim[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_BattDrawILim[3] __attribute__((section(".xbss")));
fractional controlHistory_BattDrawILim[3] __attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)

fractional abcCoefficient_VqVdLim[3]__attribute__((section(".xbss")));
fractional controlHistory_VqVdLim[3]__attribute__((section(".ybss"), far)); //Use this with small data memory model (the default)




void InitIO()
{

    //Setup digital I/O
    //Setup digital outputs
    TRISA = 0xffff;
    TRISAbits.TRISA6 = 0; //CAN_SILENT
    TRISAbits.TRISA7 = 0; //CAN_ENABLE
    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 = 0xffff;
    TRISBbits.TRISB1 = 0; //Bridge Enable
    TRISBbits.TRISB2 = 0; //SS1
//SCOTT
    TRISBbits.TRISB13 = 0; //VREF Enable
       

    //TRISD = 0x6ff2;
   // TRISD = 0xffff;
    
   // TRISDbits.TRISD1 = 0; //AUXIO_PIN2 Set as Output
    TRISDbits.TRISD2 = 0; //AUXIO_PIN3 Set as Output
    TRISDbits.TRISD8 = 0; //AUXIO_PIN4 Set as Output
    TRISDbits.TRISD9 = 0; //AUXIO_PIN5 Set as Output
    TRISDbits.TRISD10 = 0; //EEPROM_WP Set as Output

            
            
    TRISE = 0xffff;
    TRISEbits.TRISE0 = 0; //PWM1L
    TRISEbits.TRISE1 = 0; //PWM1H
    TRISEbits.TRISE2 = 0; //PWM2L
    TRISEbits.TRISE3 = 0; //PWM2H
    TRISEbits.TRISE4 = 0; //PWM3L
    TRISEbits.TRISE5 = 0; //PWM3H
    TRISEbits.TRISE6 = 0; //PWM4L

    TRISF = 0xffff;
    TRISFbits.TRISF6 = 0; //SCK1
    TRISFbits.TRISF7 = 1; //SDI1
    TRISFbits.TRISF8 = 0; //SD01

    TRISG = 0xffff;
    TRISGbits.TRISG6 = 1; //SCK2
    TRISGbits.TRISG7 = 1; //SDI2
    TRISGbits.TRISG8 = 0; //SDO2
    TRISGbits.TRISG9 = 1; //SS2
    TRISGbits.TRISG13 = 0; //Battery Switch GatePS Enable.
    TRISGbits.TRISG14 = 0; //Battery_Slow
    TRISGbits.TRISG15 = 0; //Battery_Switch

    BRIDGE_ENABLE = 0; //Keep Bridge Power Supplies off until MCPWM is set up later.
    BATTSWITCH_ENABLE = 0; //Keep BattSwitch FET Power Supply off until MCPWM is set up later.

}


void InitIIC()
{
    I2C1BRG = 0x00c4; //0x07ff;          
    I2C1CONbits.I2CSIDL = 0;
    I2C1CONbits.SCLREL = 0;
    I2C1CONbits.IPMIEN = 0;
    I2C1CONbits.A10M = 0;
    I2C1CONbits.DISSLW = 0;
    I2C1CONbits.SMEN = 0;
    I2C1CONbits.GCEN = 0;
    I2C1CONbits.STREN = 0;
    I2C1CONbits.ACKDT = 0;
    
    I2C1CONbits.RCEN = 0;
    I2C1CONbits.PEN = 0;
    I2C1CONbits.RSEN = 0;
    I2C1CONbits.SEN = 0;
    //_MI2C1IP = 3;
    I2C1CONbits.I2CEN = 1;

    TRISAbits.TRISA2 = 0;  //EEPROM Write Protect 
    EEPROM_WRITE_PROTECT = 1;  //Protected
    
    _MI2C1IF = 0;  //Clear Interrupt
    _MI2C1IE = 1;  //Enable Master Interrupt

}


void InitVariables()
{
    ComputeScaling();
    MaxWindCurrent = ConvertEngUnitsToFract(MAX_WINDCURRENTLIMIT, Cal.IWind_cnt, Cal.IWind_eng); 
    DisableCurrent = ConvertEngUnitsToFract(DISABLECURRENT, Cal.IWind_cnt, Cal.IWind_eng);
    TorqueCmdTimeout = (unsigned int) TORQUE_CMD_TIMEOUT*ISR_UPDATE_RATE;
    BiasCmdTimeout = (unsigned int) BIAS_CMD_TIMEOUT*ISR_UPDATE_RATE;
    SlowRotateCurrent = ConvertEngUnitsToFract(SLOWROTATECURRENT, Cal.IWind_cnt, Cal.IWind_eng);
    
    MaxBattDrawCurrent.LowerLimit = ConvertEngUnitsToFract(-MAX_BATTDRAWCURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng);
    MaxBattDrawCurrent.UpperLimit = ConvertEngUnitsToFract(-MIN_BATTDRAWCURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng);
    Set_CRSALValue(ConvertEngUnitsToFract(-DEFAULT_BATTDRAWCURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng),&MaxBattDrawCurrent);

    MaxBattChargeCurrent.LowerLimit = ConvertEngUnitsToFract(MIN_BATTCHARGECURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng);
    MaxBattChargeCurrent.UpperLimit = ConvertEngUnitsToFract(MAX_BATTCHARGECURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng);
    Set_CRSALValue(ConvertEngUnitsToFract(DEFAULT_BATTCHARGECURRENTLIMIT, Cal.IBatt_cnt, Cal.IBatt_eng),&MaxBattChargeCurrent);

    
    TargetVoltage.UpperLimit = ConvertEngUnitsToFract(MAX_TARGETVOLTAGE, Cal.VBus_cnt, Cal.VBus_eng);
    TargetVoltage.LowerLimit = ConvertEngUnitsToFract(MIN_TARGETVOLTAGE, Cal.VBus_cnt, Cal.VBus_eng);
    Set_CRSALValue(ConvertEngUnitsToFract(DEFAULT_TARGETVOLTAGE, Cal.VBus_cnt, Cal.VBus_eng),&TargetVoltage);
    
    AbsoluteMaxTargetVoltage = ConvertEngUnitsToFract(ABSOLUTEMAX_TARGETVOLTAGE, Cal.VBus_cnt, Cal.VBus_eng);
    ShutdownVoltage = ConvertEngUnitsToFract(SHUTDOWN_VOLTAGE, Cal.VBus_cnt, Cal.VBus_eng);
    
    UserCommandedCurrent.UpperLimit = ConvertEngUnitsToFract(MAX_USERCOMMANDEDCURRENT, Cal.IWind_cnt, Cal.IWind_eng);
    UserCommandedCurrent.LowerLimit = _Q15neg(UserCommandedCurrent.UpperLimit);
    Set_CRSALValue(ConvertEngUnitsToFract(DEFAULT_USERCOMMANDEDCURRENT, Cal.IWind_cnt, Cal.IWind_eng),&UserCommandedCurrent);

    BiasCurrent.UpperLimit = ConvertEngUnitsToFract(MAX_BIASCURRENT, Cal.IWind_cnt, Cal.IWind_eng);
    BiasCurrent.LowerLimit = _Q15neg(BiasCurrent.UpperLimit);
    Set_CRSALValue(ConvertEngUnitsToFract(DEFAULT_BIASCURRENT, Cal.IWind_cnt, Cal.IWind_eng),&BiasCurrent);
      
    ScaleIntegrationGain.LowerLimit = MIN_SCALE_INTEGRATION_GAIN;
    ScaleIntegrationGain.UpperLimit = MAX_SCALE_INTEGRATION_GAIN;
    Set_CRSALValue(DEFAULT_SCALE_INTEGRATION_GAIN,&ScaleIntegrationGain);
    
    GainScheduleRPMStdDevTarget.LowerLimit = ConvertEngUnitsToFract(MIN_RPM_STD_DEV_TARGET,RPMs_cnt,RPMs_eng);
    GainScheduleRPMStdDevTarget.UpperLimit = ConvertEngUnitsToFract(MAX_RPM_STD_DEV_TARGET,RPMs_cnt,RPMs_eng);
    Set_CRSALValue(ConvertEngUnitsToFract(DEFAULT_RPM_STD_DEV_TARGET,RPMs_cnt,RPMs_eng),&GainScheduleRPMStdDevTarget);

    
    
    scale_factor.UpperLimit = MAX_SCALE_FACTOR*CRSF_PERCENTAGES;
    scale_factor.LowerLimit = MIN_SCALE_FACTOR*CRSF_PERCENTAGES;
    Set_CRSALValue(DEFAULT_SCALE_FACTOR*CRSF_PERCENTAGES,&scale_factor);

    retract_factor.UpperLimit = MAX_RETRACT_FACTOR*CRSF_PERCENTAGES;
    retract_factor.LowerLimit = MIN_RETRACT_FACTOR*CRSF_PERCENTAGES;
    Set_CRSALValue(DEFAULT_RETRACT_FACTOR*CRSF_PERCENTAGES,&retract_factor);

    CAN_packet_rate.UpperLimit = MAX_CAN_PACKET_RATE;
    CAN_packet_rate.LowerLimit = MIN_CAN_PACKET_RATE;
    Set_CRSALValue(DEFAULT_CAN_PACKET_RATE,&CAN_packet_rate);
    
    BridgeDisableCurrent = ConvertEngUnitsToFract(BRIDGE_DISABLE_CURRENT, Cal.IWind_cnt, Cal.IWind_eng);
    BridgeDisableRPM = ConvertEngUnitsToFract(BRIDGE_DISABLE_RPM, RPMs_cnt,RPMs_eng);

    VoltageConstant = 32767*VOLTAGE_CONSTANT*(ConvertEngUnitsToFract(1, Cal.VBus_cnt, Cal.VBus_eng)-ConvertEngUnitsToFract(0, Cal.VBus_cnt, Cal.VBus_eng))/(ConvertEngUnitsToFract(1,RPMs_cnt,RPMs_eng)-ConvertEngUnitsToFract(0,RPMs_cnt,RPMs_eng));
    
    SC_Range_Max = SC_RANGE_MAX*CRSF_POSITION;
    SC_Range_Min = SC_RANGE_MIN*CRSF_POSITION;
    StopRange = STOP_RANGE*CRSF_POSITION;
    MaxRPMAdjustment = ConvertEngUnitsToFract(MAX_RPM_ADJUSTMENT, RPMs_cnt,RPMs_eng);
    StopGain = MaxRPMAdjustment/StopRange;  //RPMcnts per Range cnts
    
    Status = 0;
    
    
    if(ScaleIntegrationGain.Value == 0)
      StatusBitFields.GainScheduleMode = 0;  
    else
      StatusBitFields.GainScheduleMode = 1;  
        
    StatusBitFields.BattSwitchRequest = 1;  //Start with StatusBitFields.BattSwitchRequest = 1
    StatusBitFields.Mode = PREINDEXPULSE_MODE;  //Always start up into PreIndex mode.


}

void InitPIDGains()
{

    //Set up PID structures.

    
    Iq_PID.abcCoefficients = &abcCoefficient_Iq[0];
    Iq_PID.controlHistory = &controlHistory_Iq[0];
    PIDInit(&Iq_PID);
    kCoeffs_Iq[0] = Q15(.9);  //Tuned 12/10/19 //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_Iq[1] = Q15(0.012); //Tuned 12/10/19 //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_Iq[2] = Q15(0.0); //Der Gain    controller must be scaled up.
    PIDCoeffCalc((fractional *) & kCoeffs_Iq[0], &Iq_PID);
#ifdef TUNE_WINDING_QUADRATURE
    PIDptr = &Iq_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_Iq;
#endif 
    
    Id_PID.abcCoefficients = &abcCoefficient_Id[0];
    Id_PID.controlHistory = &controlHistory_Id[0];
    PIDInit(&Id_PID);
    kCoeffs_Id[0] = Q15(.9); //Tuned 12/10/19 //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_Id[1] = Q15(0.012); //Tuned 12/10/19 //Int Gain    higher gain in the system, the output of the PID
    //kCoeffs_Id[0] = Q15(.880); //Prop Gain  These gains must be between 0-1, to get
    //kCoeffs_Id[1] = Q15(.014); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_Id[2] = Q15(0.0); //Der Gain    controller must be scaled up.
    PIDCoeffCalc((fractional *) & kCoeffs_Id[0], &Id_PID);
#ifdef TUNE_WINDING_FLUX
    PIDptr = &Id_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_Id;
#endif 
   
    
    ShuntReg_PID.abcCoefficients = &abcCoefficient_ShuntReg[0];
    ShuntReg_PID.controlHistory = &controlHistory_ShuntReg[0];
    PIDInit(&ShuntReg_PID);
    ShuntReg_GSAL.GainScaleFactor = 2;  //Used to Scale output of PID calculation, specified in bits to shift result, so powers of two..
    ShuntReg_GSAL.LowerActuatorLimit = -32768; //Best that can be done is to pull the voltage down as hard as possible
    ShuntReg_GSAL.UpperActuatorLimit = 0; //Can't raise the voltage...
    kCoeffs_ShuntReg[0] = Q15(.6); //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_ShuntReg[1] =  Q15(0.006); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_ShuntReg[2] = Q15(0.00); //Der Gain    controller must be scaled up.
    PIDCoeffCalc((fractional *) & kCoeffs_ShuntReg[0], &ShuntReg_PID);
#ifdef TUNE_SHUNT_REGULATOR
    PIDptr = &ShuntReg_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_ShuntReg;
#endif 
    
    BattChargeILim_PID.abcCoefficients = &abcCoefficient_BattChargeILim[0];
    BattChargeILim_PID.controlHistory = &controlHistory_BattChargeILim[0];
    PIDInit(&BattChargeILim_PID);
    BattChargeILim_GSAL.GainScaleFactor = 0;  //Used to Scale output of PID calculation, specified in bits to shift result, so powers of two..
    kCoeffs_BattChargeILim[0] = Q15(.4); //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_BattChargeILim[1] = Q15(0.05); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_BattChargeILim[2] = Q15(0.0); //De=r Gain    controller must be scaled up.
    BattChargeILim_GSAL.LowerActuatorLimit = -32768;  //Can lower target bus voltage to limit battery current
    BattChargeILim_GSAL.UpperActuatorLimit = 0;      //Not allowed to raise target bus voltage
    PIDCoeffCalc((fractional *) & kCoeffs_BattChargeILim[0], &BattChargeILim_PID);
#ifdef TUNE_BATT_CHARGE_CURRENT
    PIDptr = &BattChargeILim_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_BattChargeILim;
#endif 
    
    
    BattDrawILim_PID.abcCoefficients = &abcCoefficient_BattDrawILim[0];
    BattDrawILim_PID.controlHistory = &controlHistory_BattDrawILim[0];
    PIDInit(&BattDrawILim_PID);
    BattDrawILim_GSAL.GainScaleFactor = 0;  //Used to Scale output of PID calculation, specified in bits to shift result, so powers of two..
    kCoeffs_BattDrawILim[0] = Q15(.1); //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_BattDrawILim[1] = Q15(0.05); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_BattDrawILim[2] = Q15(0.0); //De=r Gain    controller must be scaled up.
    BattDrawILim_GSAL.LowerActuatorLimit = 0;  //A Negative reduction is not allowed
    BattDrawILim_GSAL.UpperActuatorLimit = ConvertEngUnitsToFract(MAX_WINDCURRENTLIMIT, Cal.IWind_cnt, Cal.IWind_eng); 
    PIDCoeffCalc((fractional *) & kCoeffs_BattDrawILim[0], &BattDrawILim_PID);
#ifdef TUNE_BATT_DRAW_CURRENT
    PIDptr = &BattDrawILim_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_BattDrawILim;
#endif 
    
    VqVdLim_PID.abcCoefficients = &abcCoefficient_VqVdLim[0];
    VqVdLim_PID.controlHistory = &controlHistory_VqVdLim[0];
    PIDInit(&VqVdLim_PID);
    VqVdLim_GSAL.GainScaleFactor = 0;  //Used to Scale output of PID calculation, specified in bits to shift result, so powers of two..
    kCoeffs_VqVdLim[0] = Q15(.8); //Prop Gain  These gains must be between 0-1, to get
    kCoeffs_VqVdLim[1] = Q15(0.0032); //Int Gain    higher gain in the system, the output of the PID
//    kCoeffs_VqVdLim[1] = Q15(0.00); //Int Gain    higher gain in the system, the output of the PID
    kCoeffs_VqVdLim[2] = Q15(0.0); //Der Gain    controller must be scaled up.
    VqVdLim_GSAL.LowerActuatorLimit = 0;  //Negative commands not allowed b/c we don't want to lower bus voltage target
    VqVdLim_GSAL.UpperActuatorLimit = 32767; //This allows a BIG voltage correction request when motor isn'm moving and Iq/Id loop has lost authority.  Setting this to a smaller value would increase response time due to smaller error to unwind. In fact, this isn't a practical problem since the system will run with zero correction needed for awhile before a correction is needed.
    PIDCoeffCalc((fractional *) & kCoeffs_VqVdLim[0], &VqVdLim_PID);
#ifdef TUNE_VQVD_DISTANCE
    PIDptr = &VqVdLim_PID; //Point to Shunt gains/PID for adjustment in UARTRxInterrupt.c
    kCoeffs = kCoeffs_VqVdLim;
#endif    
    
}


/* Filter and mask defines for CAN*/
/* Macros used to write filter/mask ID to Register CiRXMxSID and CiRXFxSID */
/* For example, to set up the filter to accept a value of 0x123, the macro when called as */
/* CAN_FILTERMASK2REG_SID(0x123) will write the register space to accept message with ID 0x123 */
/* Use for Standard Messages Only */
#define CAN_FILTERMASK2REG_SID(x) ((x & 0x07FF)<<5)
/* The Macro will set the MIDE bit in CiRXMxSID */
#define CAN_SETMIDE(sid) (sid|0x0008)
/* The Macro will set the EXIDE bit in CiRXFxSID to only accept extended messages */
#define CAN_FILTERXTD(sid) (sid|0x0008)
/* The macro will clear the EXIDE bit in CiRXFxSID to only accept standard messages */
#define CAN_FILTERSTD(sid) (sid & 0xFFF7)
/* Macro used to write filter/mask ID to Register CiRXMxSID, CiRXMxEID, CiRXFxSID and CiRXFxEID */
/* For example, to set up the filter to accept a value of 0x123, the macro when called as */
/* CAN_FILTERMASK2REG_SID(0x123) will write the register space to accept message with ID 0x123 */
/* Use for Extended Messages only*/
#define CAN_FILTERMASK2REG_EID0(x) (x & 0xFFFF)
#define CAN_FILTERMASK2REG_EID1(x) (((x & 0x1FFC)<<3)|(x & 0x3))

void InitCAN1()
{
    unsigned long tmp_EID;

C1CTRL1bits.REQOP=4;  //Put ECAN module in config mode
while (C1CTRL1bits.OPMODE!=4);  //Wait until it is in config mode  TODO:  Needs timeout

C1CTRL1bits.CANCKS = 0x1;


//Setup for 1Mbit/sec
//C1CFG1bits.BRP = 0;
//C1CFG1bits.SJW = 0;  /* Synchronization Jump Width set to 1 TQ */
//C1CFG2bits.SEG1PH = 0x7;  /* Phase Segment 1 time is 8 TQ */
//C1CFG2bits.SEG2PHTS = 0x1;  /* Phase Segment 2 time is set to be programmable */
//C1CFG2bits.SEG2PH = 0x7;  /* Phase Segment 2 time is 8 TQ */
//C1CFG2bits.PRSEG = 0x2;  /* Propagataion time 3 TQ */
//C1CFG2bits.SAM = 0x1;  /* Bus line is sampled three times at the sample point */


//Setup for 500kbit/sec
//C1CFG1bits.BRP = 1;
//C1CFG1bits.SJW = 0;  /* Synchronization Jump Width set to 1 TQ */
//C1CFG2bits.SEG1PH = 0x7;  /* Phase Segment 1 time is 8 TQ */
//C1CFG2bits.SEG2PHTS = 0x1;  /* Phase Segment 2 time is set to be programmable */
//C1CFG2bits.SEG2PH = 0x7;  /* Phase Segment 2 time is 8 TQ */
//C1CFG2bits.PRSEG = 0x2;  /* Propagataion time 3 TQ */
//C1CFG2bits.SAM = 0x1;  /* Bus line is sampled three times at the sample point */
//


//Setup for 250kbit/sec with 20 time quanta
//C1CFG1bits.BRP = 3;
//C1CFG1bits.SJW = 0;  /* Synchronization Jump Width set to 1 TQ */
//C1CFG2bits.SEG1PH = 0x7;  /* Phase Segment 1 time is 8 TQ */
//C1CFG2bits.SEG2PHTS = 0x1;  /* Phase Segment 2 time is set to be programmable */
//C1CFG2bits.SEG2PH = 0x7;  /* Phase Segment 2 time is 8 TQ */
//C1CFG2bits.PRSEG = 0x2;  /* Propagataion time 3 TQ */
//C1CFG2bits.SAM = 0x1;  /* Bus line is sampled three times at the sample point */

//Setup for 125kbit/sec
C1CFG1bits.BRP = 7;
C1CFG1bits.SJW = 0;  /* Synchronization Jump Width set to 1 TQ */
C1CFG2bits.SEG1PH = 0x7;  /* Phase Segment 1 time is 8 TQ */
C1CFG2bits.SEG2PHTS = 0x1;  /* Phase Segment 2 time is set to be programmable */
C1CFG2bits.SEG2PH = 0x7;  /* Phase Segment 2 time is 8 TQ */
C1CFG2bits.PRSEG = 0x2;  /* Propagataion time 3 TQ */
C1CFG2bits.SAM = 0x1;  /* Bus line is sampled three times at the sample point */


/* Assign 12 buffers in DMA ram*/
C1FCTRLbits.DMABS=0b100;  //Eight buffers for Tx, and eight for Rx



// Enable buffers and set tx buffer priority
C1TR01CONbits.TXEN0 = 1; /* ECAN1, Buffer 0 is a Transmit Buffer */
C1TR01CONbits.TXEN1 = 1; /* ECAN1, Buffer 1 is a Transmit Buffer */
C1TR23CONbits.TXEN2 = 1; /* ECAN1, Buffer 2 is a Transmit Buffer */
C1TR23CONbits.TXEN3 = 1; /* ECAN1, Buffer 3 is a Transmit Buffer */
C1TR45CONbits.TXEN4 = 1; /* ECAN1, Buffer 4 is a Transmit Buffer */
C1TR45CONbits.TXEN5 = 1; /* ECAN1, Buffer 5 is a Transmit Buffer */
C1TR67CONbits.TXEN6 = 1; /* ECAN1, Buffer 6 is a Transmit Buffer */
C1TR67CONbits.TXEN7 = 1; /* ECAN1, Buffer 7 is a Transmit Buffer */

C1TR01CONbits.TX0PRI = 0b11; /* Message Buffer 0 Priority Level */
C1TR01CONbits.TX1PRI = 0b11; /* Message Buffer 1 Priority Level */
C1TR23CONbits.TX2PRI = 0b11; /* Message Buffer 2 Priority Level */
C1TR23CONbits.TX3PRI = 0b11; /* Message Buffer 3 Priority Level */
C1TR45CONbits.TX4PRI = 0b11; /* Message Buffer 4 Priority Level */
C1TR45CONbits.TX5PRI = 0b11; /* Message Buffer 5 Priority Level */
C1TR67CONbits.TX6PRI = 0b11; /* Message Buffer 6 Priority Level */
C1TR67CONbits.TX7PRI = 0b11; /* Message Buffer 6 Priority Level */

//Set up recieve buffers, mask, etc. for recieving extended frames
/* Enable window to access acceptance filter registers */
C1CTRL1bits.WIN = 0x1;


/* Select Acceptance Filter Mask 0 for Acceptance Filter 0 */
C1FMSKSEL1bits.F0MSK=0x00;
/* Configure Acceptance Filter Mask 0 register to care about all bits. (bits set to 0 here don't count.
Mask Bits (29-bits) : 0b0 0000 0000 0000 0000 0001 1111 1111
SID<10:0> : 0b111 1111 1111 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b11
..EID<17:16>
EID<15:0> : 0b1111 1111 1111 1111 ..EID<15:0> */
C1RXM0SIDbits.SID = (0x1FFC0000) >> 18;
C1RXM0SIDbits.EID = (0x00030000) >> 16;
C1RXM0EIDbits.EID = (0x0000FFFF);

/* Configure Acceptance Filter 0 to match extended identifier, Controller ID = from #define and CMD ID = dec(10) to set mode.
Filter Bits (29-bits) : 0b0 0000 0000 0000 0000 000x xxxx xxxx
SID<10:0> : 0b00000000000 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b00         ..EID<17:16>
EID<15:0> : 0b0000000xxxxxxxxx ..EID<15:0> */
tmp_EID = Assemble_packetID(CAN_SRCID, 10, 0);
C1RXF0SIDbits.SID = (tmp_EID & 0x1FFC0000) >> 18;
C1RXF0SIDbits.EID = (tmp_EID & 0x00030000) >> 16;
C1RXF0EIDbits.EID = (tmp_EID & 0x0000FFFF);

/* Acceptance Filter 0 to check for Extended Identifier */
C1RXM0SIDbits.MIDE = 0x1;
C1RXF0SIDbits.EXIDE= 0x1;

/* Acceptance Filter 0 to use Message Buffer 8 to store message */
C1BUFPNT1bits.F0BP = 0x8;
/* Enable Acceptance Filter 0 */
C1FEN1bits.FLTEN0=0x1;



/* Select Acceptance Filter Mask 1 for Acceptance Filter 1,  This accepts the packet that includes the spring controller range measurement bits */
C1FMSKSEL1bits.F1MSK=0x01;
/* Configure Acceptance Filter Mask 1 register to care about all bits except bottom nine of EID which is the sequence number. (bits set to 0 here don't count.
Mask Bits (29-bits) : 0b0 0000 0000 0000 0000 0001 1111 1111
SID<10:0> : 0b111 1111 1111 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b11
..EID<17:16>
EID<15:0> : 0b1111 1111 1111 1111 ..EID<15:0> */
C1RXM1SIDbits.SID = (0x1FFC0000) >> 18;
C1RXM1SIDbits.EID = (0x00030000) >> 16;
C1RXM1EIDbits.EID = (0x0000FE00);  //Ignore bottom nine bits for the sequence number since this packet is coming from the battery controller

/* Configure Acceptance Filter 0 to match extended identifier, Controller ID = from #define and CMD ID = dec(00) to correspond to data packet with range in it from the spring converter, and any sequence number.
Filter Bits (29-bits) : 0b0 0000 0000 0000 0000 000x xxxx xxxx
SID<10:0> : 0b00000000000 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b00         ..EID<17:16>
EID<15:0> : 0b0000000xxxxxxxxx ..EID<15:0> */
tmp_EID = Assemble_packetID(SPRINGCONTROLLER_CAN_SRCID, 00, 0);
C1RXF1SIDbits.SID = (tmp_EID & 0x1FFC0000) >> 18;
C1RXF1SIDbits.EID = (tmp_EID & 0x00030000) >> 16;
C1RXF1EIDbits.EID = (tmp_EID & 0x0000FE00);

/* Acceptance Filter 1 to check for Extended Identifier */
C1RXM1SIDbits.MIDE = 0x1;
C1RXF1SIDbits.EXIDE= 0x1;

/* Acceptance Filter 1 to use Message Buffer 9 to store message */
C1BUFPNT1bits.F1BP = 0x9;
/* Enable Acceptance Filter 1 */
C1FEN1bits.FLTEN1=0x1;


//THis code sets up acceptance filter for data packets from the battery controller.  Not used in this version so commented out.
///* Select Acceptance Filter Mask 1 for Acceptance Filter 1,  This accepts the packet that includes the stop-charge bits */
//C1FMSKSEL1bits.F1MSK=0x01;
///* Configure Acceptance Filter Mask 1 register to care about all bits except bottom nine of EID which is the sequence number. (bits set to 0 here don't count.
//Mask Bits (29-bits) : 0b0 0000 0000 0000 0000 0001 1111 1111
//SID<10:0> : 0b111 1111 1111 ..SID<10:0> or EID<28:18>
//EID<17:16> : 0b11
//..EID<17:16>
//EID<15:0> : 0b1111 1111 1111 1111 ..EID<15:0> */
//C1RXM1SIDbits.SID = (0x1FFC0000) >> 18;
//C1RXM1SIDbits.EID = (0x00030000) >> 16;
//C1RXM1EIDbits.EID = (0x0000FE00);  //Ignore bottom nine bits for the sequence number since this packet is coming from the battery controller
//
///* Configure Acceptance Filter 0 to match extended identifier, Controller ID = from #define and CMD ID = dec(00) to coorespond to data packet with current in it from the power converter, and any sequence number.
//Filter Bits (29-bits) : 0b0 0000 0000 0000 0000 000x xxxx xxxx
//SID<10:0> : 0b00000000000 ..SID<10:0> or EID<28:18>
//EID<17:16> : 0b00         ..EID<17:16>
//EID<15:0> : 0b0000000xxxxxxxxx ..EID<15:0> */
//tmp_EID = Assemble_packetID(BATTERYCONTROLLER_CAN_SRCID, 01, 0);
//C1RXF1SIDbits.SID = (tmp_EID & 0x1FFC0000) >> 18;
//C1RXF1SIDbits.EID = (tmp_EID & 0x00030000) >> 16;
//C1RXF1EIDbits.EID = (tmp_EID & 0x0000FE00);
//
///* Acceptance Filter 1 to check for Extended Identifier */
//C1RXM1SIDbits.MIDE = 0x1;
//C1RXF1SIDbits.EXIDE= 0x1;
//
///* Acceptance Filter 1 to use Message Buffer 9 to store message */
//C1BUFPNT1bits.F1BP = 0x9;
///* Enable Acceptance Filter 1 */
//C1FEN1bits.FLTEN1=0x1;








/* Clear window to access ECAN control registers */
C1CTRL1bits.WIN = 0x0;

//Put CAN1 into Normal mode
C1CTRL1bits.REQOP = 0;
while(C1CTRL1bits.OPMODE != 0);

//Enable CAN Transceiver
CAN_SILENT = 0;
CAN_ENABLE = 1;

}

void InitDma12()  //DMA channel 1 is used to transfer data to the CAN controller for subsequent transmission
                  //DMA channel 2 is used to transfer received data from the CAN controller to the CPU memory
{

    /* Initialize the DMA channel 0 for ECAN TX and clear the colission flags */
DMACS0bits.PWCOL1 = 0;
DMACS0bits.XWCOL1 = 0;
/* Set up Channel 1 for peripheral indirect addressing mode normal operation, word operation */
/* and select TX to peripheral */
DMA1CON = 0x2020;
/* Set up the address of the peripheral ECAN1 (C1TXD) */
DMA1PAD = 0x0442;
/* Set the data block transfer size of 8 */
DMA1CNT = 7;
/* Automatic DMA TX initiation by DMA request */
DMA1REQ = 0x0046;  //IRQ select register
/* DPSRAM atart address offset value */
DMA1STA = __builtin_dmaoffset(&ECAN1MSGBUF);
/* Enable the channel */
DMA1CONbits.CHEN = 1;  

/* Initialize DMA Channel 2 for ECAN RX and clear the collision flags */
DMACS0bits.PWCOL2 = 0;
DMACS0bits.XWCOL2 = 0;
/* Set up Channel 2 for Peripheral Indirect addressing mode (normal operation, word operation */
/* and select as RX to peripheral */
DMA2CON = 0x0020;
/* Set up the address of the peripheral ECAN1 (C1RXD) */
DMA2PAD = 0x0440;
/* Set the data block transfer size of 8 */
DMA2CNT = 7;
/* Automatic DMA Rx initiation by DMA request */
DMA2REQ = 0x0022;
/* DPSRAM atart address offset value */
DMA2STA = __builtin_dmaoffset(&ECAN1MSGBUF);
/* Enable the channel */
DMA2CONbits.CHEN = 1;  



/* Enable ECAN1 interrupt */
_C1IP = 3;
IEC2bits.C1IE = 1;
/* Enable transmit interrupt */
C1INTEbits.TBIE = 0;
/* Enable ECAN1 receive Interrupt */
C1INTEbits.RBIE = 1;


}


void InitDma0()  //DMA channel 0 is used to transfer data at the end of the ADC1 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 = 6;  //6
IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
IEC0bits.DMA0IE = 1; //Set the DMA interrupt enable bit
DMA0CONbits.CHEN = 1;

}



void InitDma3()  //DMA channel 3 is used to transfer data at the end of the ADC2 conversion process
{
DMA3CONbits.AMODE = 0; // Configure DMA for Register indirect with post increment (used with conversion order mode)
DMA3CNT = NUMAIO*INNERFILTERSAMPLES-1;

DMA3CONbits.MODE = 2; // Configure DMA for Continuous mode with ping-pong
DMA3PAD = (int)&ADC2BUF0;
DMA3REQ = 21;  //Select ADC2 convert done
DMA3STA = __builtin_dmaoffset(Buffer2A);
DMA3STB = __builtin_dmaoffset(Buffer2B);
_DMA3IP = 5;
IFS2bits.DMA3IF = 0; //Clear the DMA interrupt flag bit
IEC2bits.DMA3IE = 1; //Set the DMA interrupt enable bit
DMA3CONbits.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 InitADC1_WithIntrpt()
{
    //AD1CON1bits.SSRC = 2;  //Clock source select -  010 causes Timer3 compare to end sampling and start conversion
    AD1CON1bits.SSRC = 3;  // 011 causes the MCPWM Module special event 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 = 8;  //Conversion clock select - Conversion time is 5*Tcy, see datasheet.  Datasheet indicates 4 but Scott has identified issue that requires this to be 8 to elimate "flat-spot" problem.
    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

    _AD1IP = 5;
    _AD1IF = 0;  //Clear Interrupt
    _AD1IE = 0;  //Do not Enable ADC Interrupt, not needed.
    AD1CON1bits.ADON = 0;  //Don't enable ADC yet, wait until everything else is set up and enable in main

}

void InitADC2_WithIntrpt()
{
    AD2CON1bits.SSRC = 2;  //Clock source select -  010 causes Timer5 compare to end sampling and start conversion for ADC2

    AD2CON1bits.ASAM = 1; //Auto-sample start bit, this is enabled in PWM interupt.
    AD2CON1bits.AD12B = 1; //12 bit mode, disables simultaneous sampling
    AD2CON1bits.FORM = 2; //Report Results as un-signed Integers.  i.e. dddd dddd dddd 0000 is the twelve bits

    AD2CON2bits.VCFG = 3; //Use VRef+/VRef- as reference, driven by precision reference in our board.
    AD2CON2bits.BUFM = 0;
    AD2CON2bits.CSCNA = 1;  //ScanINput Selections for CH0+ during Sample A bit
    AD2CON2bits.CHPS = 0;  //Converts CH0

    AD2CON3bits.ADCS = 8;  //Conversion clock select - Conversion time is 5*Tcy, see datasheet.  Datasheet indicates 4 but Scott has identified issue that requires this to be 8 to elimate "flat-spot" problem.
    AD2CON3bits.SAMC = 0x1f;  //Auto-sample time bits.  This is only used in SSRC = 7...
    
    AD2PCFGL =  0xf3ff;  // select specified analog input pins for ADC2

    AD2CSSL = ~0xf3ff; // Scan specified inputs
//Use Conversion Order mode
    AD2CON1bits.ADDMABM = 1;  //DMA buffers are built in conversion order mode.
    AD2CON2bits.SMPI = NUMAIO-1;

# if INNERFILTERSAMPLES == 1
    AD2CON4bits.DMABL = 0;
# endif
# if INNERFILTERSAMPLES == 2
    AD2CON4bits.DMABL = 1;
# endif
# if INNERFILTERSAMPLES == 4
    AD2CON4bits.DMABL = 2;
# endif
# if INNERFILTERSAMPLES == 8
    AD2CON4bits.DMABL = 3;
# endif
# if INNERFILTERSAMPLES == 16
    AD2CON4bits.DMABL = 4;
# endif
# if INNERFILTERSAMPLES == 32
    AD2CON4bits.DMABL = 5;
# endif
# if INNERFILTERSAMPLES == 64
    AD2CON4bits.DMABL = 6;
# endif
# if INNERFILTERSAMPLES == 128
    AD2CON4bits.DMABL = 7;
# endif

    _AD2IP = 5;
    _AD2IF = 0;  //Clear Interrupt
    _AD2IE = 0;  //Enable ADC Interrupt
    AD2CON1bits.ADON = 0;  //Don't enable ADC yet, wait until everything else is set up and enable in main

}


void InitMCPWM()
{
    P1TCONbits.PTCKPS = 0;  //PWM Timebase Period = TCy (1:1 Prescale)
    P1TCONbits.PTOPS = 0;  //1:1 PostScale

   P1TPER = 0x0400;  //Set PWM counter value.  Sets the length of the PWM period in clock cycles, adjusted by prescalers/postcalers.
                      //0x0800 = 2048 = ~20kHz in edge aligned mode, = ~10kHz in center aligned mode
                      //0x0400 = 1024 = ~20kHz in center aligned mode
    //P1TCONbits.PTMOD = 0;  //Generate interrupt on PTPER reset to zero (i.e. at PWM rate) 0 = Edge aligned
    P1TCONbits.PTMOD = 2;  //Generate interrupt on PTPER reset to zero (i.e. at PWM rate) 3 = Center aligned

    _PWMIF = 0; //Clear Interrupt Flat
    _PWMIP = 6 ;
    _PWMIE = 1; //Enable Interrupt

    //PWM1CON2 = 0x0000;  //Engage over-ride on next clock boundary (instead of at PWM time-base) and set SEVOPS postscaler to 1.
    PWM1CON2 = 0x0002;  //Engage over-ride on next PWM time-base
    //P1DTCON1 = 0x00c2;  //Set deadtime prescaler to 8*Tcy and deadtime to 2 for Unit A.  Results in .402 microsecond deadtime.  Keep Unit B at no deadtime
//P1DTCON1 = 0x0000;
    P1DTCON1 = 0x0002;  //Set deadtime prescaler to Tcy and deadtime to 4 for Unit A.    Keep Unit B at no deadtime
    P1DTCON2 = 0x00c0;  //Use deadtime from Unit A for bridge channels, and Unit B for Load dump channel.


    SEVTCMP = 0x0400; //PTPER/2; //0x0001;  //Set Special Event Compare Register to occur when counting upwards from 0

//Setup for Motor Mode
    P1DC1 = 0x0000;   //These duty cycles are such that 0->100% is 0->2*P1TPER.  PWM resolution is less than number of bits here.
    P1DC2 = 0x0000;  //0%
    P1DC3 = 0x0000;  //0%

    P1DC4 = 0x0000;  //0%

    P1OVDCON = 0x0000; //Power up with fet switching off.
    //P1OVDCON = 0x7f00; //Channels 1-3 are in complementary PWM mode
                       //The load dump is  connected to the low side of channel four, so this is selected as active for PWM, and the high side
                       // of channel four is turned off (although it's not connected to anything).

    PWM1CON1 = 0x08ff;  //Enable PWM1HL, PWM2HL, PWM3HL as complementary and PWM4HL as independent.

    P1TCONbits.PTEN = 1;  //Enable Time Base Timer  This is what starts PWM outputs switching

    
    
    P1DC1 = P1TPER; //These duty cycles are such that 0->100% is 0->2*P1TPER.  PWM resolution is less than number of bits here.
    P1DC2 = P1TPER; //50%
    P1DC3 = P1TPER; //50%
    P1DC4 = 0;
}

void InitQEI()
{
 AD1PCFGL |= 0x0038; // Configure QEI pins as digital inputs
 AD2PCFGL |= 0x0038; // Configure QEI pins as digital inputs
//QEI1CON = 0x0604;
QEICONbits.QEIM = 0; // Disable QEI Module
QEICONbits.CNTERR = 0; // Clear any count errors
QEICONbits.QEISIDL = 0; // Continue operation during sleep
QEICONbits.SWPAB = 0; // QEA and QEB not swapped
QEICONbits.PCDOUT = 0; // Normal I/O pin operation
QEICONbits.POSRES = 1; // Index pulse resets position counter
DFLTCONbits.CEID = 1; // Count error interrupts disabled
DFLTCONbits.IMV = 1;  //Specify reset occurs when index pulse active and channes BA= 01
DFLTCONbits.QEOUT = 1; // Digital filters output enabled for QEn pins
DFLTCONbits.QECK = 4; // 1:32 clock divide for digital filter for QEn
POSCNT = 0; // Reset position counter
MAXCNT = ENC_CNTPERREV;  // This gets loaded into POSCNT when index pulse is past while moving backwards
_QEIIF = 0;  //Clear Interrupt
//_QEIIP = ;
_QEIIE = 1; //Enable interrupt on index pulse
QEICONbits.QEIM = 6; // X4 mode with position counter reset by Index
}

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.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


}

