/*
 * File:   main.c
 * Author: hamilton
 *
 * Created on November 4, 2013, 4:11 PM
 */

#include <dsp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xc.h"
#include "UART.h"
#include "config.h"
#include "extern.h"
#include "conv.h"
#include "init.h"
#include "can.h"
#include "CalibrationConstants.h"
#include "libq.h"
#include "park.h" 
#include "svgen.h"
#include "types.h"
#include "I2C.h"
#include "crc.h"
#include "PerformCalibration.h"

#ifdef DEBUG
#include "WindingCurrentLimits.h"
#endif
_FOSCSEL(FNOSC_PRIPLL)
//_FOSCSEL(FNOSC_FRC)
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON)
_FWDT(FWDTEN_OFF)
_FPOR(FPWRT_PWR128)
_FICD(ICS_PGD1 & JTAGEN_OFF)



void (*getErrLoc(void))(void); // Get Address Error Loc
void (*errLoc)(void); // Function Pointer   




int main(void) {
    int j;



#ifdef DEBUG
    char s[256];
    float last_time = 0;
    char ModeStr[10];

#endif


    /* Configure Oscillator to operate the device at 40Mhz
       Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
       Fosc= 7992075Hz*(41)/(2*2)=79920750Hz for Fosc, Fcy = 39960375Hz (Crystal rate Measured on Test Board) */
    /* Configure PLL prescaler, PLL postscaler, PLL divisor */
    PLLFBD = 38; /* M = PLLFBD + 2 */
    CLKDIVbits.PLLPOST = 0; /* N1 = 2 */
    CLKDIVbits.PLLPRE = 0; /* N2 = 2 */

    __builtin_write_OSCCONH(0x03); /* New Oscillator selection FRC w/ PLL */
    __builtin_write_OSCCONL(0x01); /* Enable Switch */
    while (OSCCONbits.COSC != 0b011); /* Wait for Oscillator to switch to FRC w/ PLL */
    while (OSCCONbits.LOCK != 1); /* Wait for Pll to Lock */


    // __builtin_write_OSCCONH(0x01); /* New Oscillator selection FRC w/ PLL */
    // __builtin_write_OSCCONL(0x01); /* Enable Switch */
    //   while (OSCCONbits.COSC != 0b001); /* Wait for Oscillator to switch to FRC w/ PLL */
    //   while (OSCCONbits.LOCK != 1); /* Wait for Pll to Lock */

    TRISD = 0xffff; //Move this back into InitIO())
    TRISDbits.TRISD1 = 0; //AUXIO_PIN2 Set as Output
    AUXIO_PIN2 = 0;
    AUXIO_PIN3 = 1;
    InitIO();

//SCOTT
    VREF_ENABLE = 1;  //Turn on External Reference
    
    
    InitIIC();
     
    InitU1(); //RS-232
    
    eeprom_timer = 0L;

    
    //init TMR8 to provide timeout for EEPROM Loading
    T8CON = 0x0010; //Start with timer disabled, prescaler = 8
    PR8 = 4995; //4995 = ~1000Hz with Clock at  39960375MHz and prescaler = 1:8.  EEPROM Timeout depends upon this rate.
    _T8IF = 0; //Clear interrupt
    _T8IP = 5;
    _T8IE = 1; //Enable interrupt.
    T8CON = 0x8010;

    
    
    AUXIO_PIN3 = 1;
    LoadCalibration();
    AUXIO_PIN3 = 0;

    InitVariables();
    
    InitPIDGains();

    //init TMR1 to interrupt at rate specified in config.h
    _T1IP = 5;
    TMR1 = 0; //Clear the timer

    PR1 = SetCANTimer(CAN_packet_rate.Value);
    T1CON = 0x8020; //enabled, prescaler 1:64, internal clock
    _T1IF = 0; //Clear Interrupt
    _T1IE = 0; //Keep Interrupt disabled until everything is set up.


    //init TMR5 to provide ~1kHz interuput for speed/position/power control loop.
    T5CON = 0x0010; //Start with timer disabled, prescaler = 8
    PR5 = 4574; //~1092Hz with Clock at  39960375MHz and prescaler = 1:8.  RPM calculation depends upon this rate.
    _T5IF = 0; //Clear interrupt
    _T5IP = 5;
    _T5IE = 1; //Enable interrupt.
    T5CON = 0x8010;

    // init TMR3 to provide the timebase for interrupt that starts the AIO process on ADC0
    //T3CON = 0x8000;
//    T3CON = 0x0000; //Start with timer disabled
//    PR3 = 275; //Rolls over about every 8uSec and initiates ADC sampling.  Required sampling and conversion time is about 4uS, so there's enough margin here, although 4uS seems too short.
//    _T3IP = 5;
//    _T3IF = 0; //Clear interrupt
//    _T3IE = 0; //Disable interrupt.  Not Needed

        // init TMR3 to provide the timebase for interrupt that starts the AIO process on ADC1
    //T5CON = 0x0000; //Start with timer disabled
    //PR5 = 250; //Rolls over about every 8uSec and initiates ADC sampling.  Required sampling and conversion time is about 4uS, so there's enough margin here, although 4uS seems too short.
   // _T5IP = 5;
   // _T5IF = 0; //Clear interrupt
  //  _T5IE = 0; //Disable interrupt.  Not Needed

      
    //Set up DMA channel and ADC
    InitDma0(); //Argument is number of samples to transfer per interrupt.
    InitDma3(); //Argument is number of samples to transfer per interrupt.

    InitADC1_WithIntrpt();
    InitADC2_WithIntrpt();

    InitSPI();

    PORTA = 0;

    //Set up encoder peripheral
    InitQEI();
    halls = (PORTD & 0x0070) >> 4; // Shift RD4/5/6 to least significant bits of variable.
    if (EncoderStatus == NO_ENCODER_SYNC_HAS_OCCURED) //guess at encoder position as middle of hall state since neither a hall effect transition or index pulse has occurred.
        POSCNT = 819 + halls * 136 - 68;

    //Set Up CN pins  CN13/14/15 corresponds to RD4/5/6 which corresponds to Hall W,V,U
    CNPU1bits.CN13PUE = 1;
    CNPU1bits.CN14PUE = 1;
    CNPU1bits.CN15PUE = 1;
    CNEN1bits.CN13IE = 1; // Enable CN13 pin for interrupt detection
    CNEN1bits.CN14IE = 1; // Enable CN13 pin for interrupt detection
    CNEN1bits.CN15IE = 1; // Enable CN13 pin for interrupt detection
    IEC1bits.CNIE = 0; // Enable CN interrupts -- Disabled for now as the hall effect sensors are not currently used.
    IFS1bits.CNIF = 0; //Clear CN Interrupt


    //init CAN bus
    InitCAN1(); //Setup CAN1
    InitDma12(); //Setup two DMA channels for use with CAN1
    for (j = 0; j < ECAN1_NUM_TX_BUFFERS; j++) //Setup CAN messages type and frame type for each message.
    {
        message[j].message_type = CAN_MSG_DATA; //data message
        message[j].frame_type = CAN_FRAME_EXT; //extended (29 bit identifier)
    }

    BRIDGE_ENABLE = 1; //Power up Transistor Driver Power Supplies now that MCPWM is set up.  !!!!!!!!!!!! WHY IS THIS DONE BEFORE MCPWM IS SET UP?  !!!!!!!!!!!!!!!!!!!
    BATTSWITCH_ENABLE = 1; //Turn on BattSwitch FET PS

    // Enable Timer interrupts now that everything is set up.
    AD1CON1bits.ADON = 1; //Enable ADC, this starts sampling and thus creates DMA interrupt from which most everything happens.
    
    AD2CON1bits.ADON = 1; //Enable ADC, this starts sampling and thus creates DMA interrupt for slow rate ADC reads

      //Set up motor control module, this peripheral controls all seven PWM outputs
    InitMCPWM();
    
           
    _T1IE = 1; //Enable 25Hz Interrupt, _T1Interrupt gets called at the beginning of each period.


    //TestWindingCurrentTarget();

    //#ifdef TUNE_SHUNT_REGULATOR //In this tuning scenario, power supply takes the place of a rotating motor and bridge needs to be a pure rectifier      
     //  P1OVDCON = 0xc000; ///For Shunt Regulator Tuning.  Over-ride and turn off all transistor bridge fets
    //#endif
    //P1OVDCON = 0x4000;  ///Turn off all fets except let Load DUmp (4L) be driven by P1DC4)  For calibrating load dump
    // POSCNT = 2780;  //Hard coded for Locked Rotor Test.  This value needs to be determined and set everytime the rotor lock is assembled/disassembled.

    //
    
#ifdef DEBUG
    //  PrintScaling();
    //    TestCurrentMinMax();
#endif
    
   
    
    while (1) {
//#ifdef DEBUG
#if 1 //This is here because the ifdef DEBUG appears in lots of places in the code and hasn't been througly tested recently, but it's nice to shut down the spewing RS-232 for teh deployments
        if (f_time > last_time) //Wait for time to be updated.
        {

            last_time = f_time;

            if(CalibrationMode == 2)  //Calibrate mode has been selected and WindingControl ISR disabled.
            {
                PerformCalibration();
                while(1);  //Stay here forever, cycle power to leave calibration mode
            }
                                
            
            if (raw == 1)
                sprintf(s, "%f     %d     %d     %d       %d        %d      %d                    %d\r\n", f_time,
                    PhaseA_Curr, PhaseB_Curr, VBus_ADC[0], IBatt_ADC[0],DiffPress_ADC[0],AuxTorque_ADC[0],SEVTCMP
                    );
            else
            {

                switch (StatusBitFields.Mode) {
                    case PREINDEXPULSE_MODE:
                        sprintf(ModeStr, "%s", "PRE");
                        break;
                    case TORQUE_MODE:
                        sprintf(ModeStr, "%s", "TOR");
                        break;
                    case GENERATOR_MODE:
                        sprintf(ModeStr, "%s", "GEN");
                        break;
                }

                sprintf(s, "%.3f %s %7.1f RPM   %6.3f A  %6.3f A  %6.3f A       %6.3f A  %6.3f A     %5.3f A    %5.2f A   %5.2f A      %6.1f V   %8.3f V    %6.3f A    %6.1f V  %6.1f V     %5d - %5d     %5d   %5d   %5d   %5d     %6.3f %8.5f %6.3f     %x-%d    %d   %d - %d   %d - %d      %d  %d   %6.3f PSI  %6.3f N-m   %f   %x   %x     %d   %d   %d    %d  %lu\r\n",
                        f_time, ModeStr, ConvertFractToEngUnits(RPMs, RPMs_cnt, RPMs_eng),
                        ConvertFractToEngUnits(UserCommandedCurrent.Value, Cal.IWind_cnt, Cal.IWind_eng),
                        ConvertFractToEngUnits(CommandedCurrent, Cal.IWind_cnt, Cal.IWind_eng),
                        ConvertFractToEngUnits(Iq_PID.controlReference, Cal.IWind_cnt, Cal.IWind_eng),
                        
                        ConvertFractToEngUnits(QuadratureCurrentSamples[0], Cal.IWind_cnt, Cal.IWind_eng),
                        ConvertFractToEngUnits(FluxCurrentSamples[0], Cal.IWind_cnt, Cal.IWind_eng),
                        //ConvertFractToEngUnits(PhaseA_Curr, Cal.IWind_cnt, Cal.IWind_eng),
                        //ConvertFractToEngUnits(PhaseB_Curr, Cal.IWind_cnt, Cal.IWind_eng),
                        
                        ConvertFractToEngUnits(IBattSamples[0], Cal.IBatt_cnt, Cal.IBatt_eng),
                        ConvertFractToEngUnits(IWindReduction_VqVd_Mag, Cal.IWind_cnt, Cal.IWind_eng),
                        ConvertFractToEngUnits(IWindReduction_BattDraw_Mag, Cal.IBatt_cnt, Cal.IBatt_eng),
                        
                        ConvertFractToEngUnits(ShuntReg_PID.controlReference, Cal.VBus_cnt, Cal.VBus_eng),
                        ConvertFractToEngUnits(VBus[ReportingFilterCtr], Cal.VBus_cnt, Cal.VBus_eng),
                        ConvertFractToEngUnits(LoadDumpCurrent[ReportingFilterCtr], LD_Current_cnt, LD_Current_eng),
                        ConvertFractToEngUnits(VoltageModification_Limiter, Cal.VBus_cnt, Cal.VBus_eng),
                        ConvertFractToEngUnits(VoltageModification_BattCurrent, Cal.VBus_cnt, Cal.VBus_eng),

                        ParkParm.qVq, ParkParm.qVd, 
                        
                        iTemp1, iTemp2, iTemp3, iTemp4,
                        (float) kCoeffs[0] / 32767, (float) kCoeffs[1] / 32767, (float) kCoeffs[2] / 32767,
                        
                        _RB0, StatusBitFields.EXT_Voltage_Detect,
                        StatusBitFields.BattSwitchRequest,
                        StatusBitFields.SlowSwitchSetting, BATTERY_SLOW,
                        StatusBitFields.BattSwitchSetting, BATTERY_SWITCH,
                        
                        SEVTCMP, P1DC4,
                        ConvertFractToEngUnits(DiffPressSamples[ADC2_OuterSampleCtr], Cal.DiffPress_cnt, Cal.DiffPress_eng),
                        //ConvertFractToEngUnits(AuxTorqueSamples[ADC2_OuterSampleCtr], Cal.AuxTorque_cnt, Cal.AuxTorque_eng)
                        //22.58*(ConvertFractToEngUnits(AuxTorqueSamples[ADC2_OuterSampleCtr], Cal.AuxTorque_cnt, Cal.AuxTorque_eng)-5.0)/5.0,
                        ConvertFractToEngUnits(AuxTorqueSamples[ADC2_OuterSampleCtr], Cal.AuxTorque_cnt, Cal.AuxTorque_eng),
                        ConvertFractToEngUnits(AuxTorqueSamples[ADC2_OuterSampleCtr], Cal.AuxTorque_cnt, Cal.AuxTorque_eng)   ,
                        BRIDGE_ENABLE,
                        SEVTCMP,
                        SC_Range,SC_RangeCtr,StatusBitFields.SpringRangeValid,StatusBitFields.PermissiveMode,
                        eeprom_timer
                        );
                
////                
//                sprintf(s,"%.3f   %d   %d  %8.5f  %8.5f %8.5f\r\n",
//                        f_time,
//                        P1DC4,LoadDumpCalibration(P1DC4),
//                        ConvertFractToEngUnits(LoadDumpCurrent[ReportingFilterCtr], LD_Current_cnt, LD_Current_eng),
//                        ConvertFractToEngUnits(IBattSamples[0], Cal.IBatt_cnt, Cal.IBatt_eng),
//                        ConvertFractToEngUnits(VBus[ReportingFilterCtr], Cal.VBus_cnt, Cal.VBus_eng)
//                        );
                        
            }

            putsU1(s);




        }
#endif
    }
    return 0;
} //main


