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

#include <dsp.h>
#include <stdio.h>
#include <limits.h>
#include "xc.h"
#include "UART.h"
#include "config.h"
#include "extern.h"
#include "conv.h"
#include "init.h"
#include "can.h"
#include "ManageTreFoilPosition.h"
#include "StateMachines.h"



_FOSCSEL(FNOSC_FRC) // FNOSC<2:0> = 000(FRC oscillator)  IES0 = 1  (Start with FRC and then switch to user selected clock when ready)
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON) // FCKSM<1:0> = 01 (clock switching enable, fail safe clock monitor disabled)   OSCIOFNC = 0 (OSC2 pin is GPIO)     POSCMD<1:0> = 11  (Primary oscillator disabled)
_FWDT(FWDTEN_OFF) // FWDTEN = 0(watchdog timer software enabled/disabled)  WINDIS = 1 (watchdog timer in non-window mode)  PLLKEN = 1 (clock switch to pll will wait for lock signal)  WDTPRE = 1 (1:128 watchdog prescaler)  WDTPOST<3:0> = 1111 (watchdog postscaler = 1:32768)
_FPOR(FPWRT_PWR128) //PWMPIN = 1 (MCPWM pins controlled by PORT register at device reset)   HPOL = 1 (MCPWM high side pins are active high)  LPOL = 1 (MCPWM low side pins are active high) FPWRT<2:0> = 11 (power on reset timer value = 128ms)
_FICD(ICS_PGD1 & JTAGEN_OFF) // JTAGEN = 0 (JTAG disabled)   ICS<1:0> = 11  (ICD communicate on PGEC1 and PGED1


float PH1PWM_DC = 0;
float PH2PWM_DC = 0;
float PH3PWM_DC = 0;
const int MC_PWM_Period = 0x7fff;


int step;
unsigned int halls = 0;
unsigned int pos;

void SampADC(int ch);
void ScanADC(void);

char ch, cl;


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

int main(void) {


    /* Configure Oscillator to operate the device at ~10Mhz
       Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
       Fosc= 7.37*(43)/(2*8)=19.806875Mhz for Fosc, Fcy = 9.9034375Mhz */
    /* Configure PLL prescaler, PLL postscaler, PLL divisor */
    PLLFBD = 41; /* M = PLLFBD + 2 */
    CLKDIVbits.PLLPOST = 0; /* N1 = 2 */
    CLKDIVbits.PLLPRE = 0; /* N2 = 2 */
    __builtin_write_OSCCONH(0x01); /* New Oscillator selection from FRC only, to FRC w/ PLL */
    //__builtin_write_OSCCONL(0x01); /* Request oscillator switch */
    __builtin_write_OSCCONL(0x03); /* Enable secondary (LP) oscillator and Request oscillator switch */

    while (OSCCONbits.COSC != 0b001); /* Wait for Oscillator to switch to FRC w/ PLL */
    while (OSCCONbits.LOCK != 1); /* Wait for Pll to Lock */

    //Set up UARTS
    InitU1();
    _U1RXIP = 6; //Set U1 Recieve interrupt to highest priority since this is occuring asyncronously to everything else.
    Maxon_FrameA.dle = DLE; //Initialize Frame structure
    Maxon_FrameA.stx = STX;

    InitU2();
    _U2RXIP = 6; //Set U1 Recieve interrupt to highest priority since this is occuring asyncronously to everything else.


    //init TMR1 to interrupt at specified rate, based on 32768Hz crystal SOSC
    _T1IP = 2; //Set to lower priority than all the rest.
    TMR1 = 0; //Clear the timer

#if CAN_PACKET_RATE==25
    PR1 = 1311; //Should give a 25Hz interrupt at 32768Hz clock
    T1CON = 0x8002; //enabled, prescaler 1:1, external clock (SOSC)
#endif
#if CAN_PACKET_RATE==10
    PR1 = 3277; //Should give a 10Hz interrupt at 32768Hz clock
    //  PR1 = 2*3277; //Should give a 5Hz interrupt at 32768Hz clock, this is a backup timer for the IMU generating a new packet at 10Hz, i.e. if something goes haywire with the IMU, this timer will generate start ADC sampling and report data at 5 Hz.
    T1CON = 0x8002; //enabled, prescaler 1:1, external clock (SOSC)
#endif

    _T1IF = 0; //Clear Interrupt
    _T1IE = 0; //Keep Interrupt disabled until everything is set up.


    // init TMR3 to provide the timebase for interrupt that starts the AIO process
    T3CON = 0x8000;
    PR3 = 283 - 1; //Rolls over at 139 kHz and adc sampling.
    _T3IF = 0; //Clear interrupt
    _T3IE = 0; //Keep Interrupt disabled.

    //Setup digital 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+.


    //    TRISD = 0xffff;
    //    TRISDbits.TRISD0 = 0;  //CAN loopback pin, set low to make CAN work properly, or leave it an input?
    //   TRISDbits.TRISD2 = 0;  //Gas Bypass enable
    //    TRISDbits.TRISD3 = 0;  //Stepper Enable
    //    TRISDbits.TRISD12 = 0;  //Laser Rangefinder enable
    //    TRISDbits.TRISD15 = 0;  //UART1 RTS
    TRISD = 0x6F8E;
    _RD0 = 0; //Set CAN loopback pin low
    _RD12 = 1; //Enable rangefinder switch
    _RD6 = 0; //Enable Drive by setting RD6 low


    TRISE = 0xff00;

    TRISGbits.TRISG15 = 0; //EM cable tester enable

    // TRISEbits.TRISE0 = 0;  //Make RE0 an output
    //   TRISEbits.TRISE1 = 0;  //Make RE1 an output

    //raw = 1;  //Force Calibration Mode

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


    //init CAN bus
    int j;
    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)
    }

    //Setup FIR filters
    FIRDelayInit(&ADC_Filter);


    // init TMR2, currently unused
    T2CON = 0x8000;
    PR2 = 0;
    _T2IF = 0; //Clear interrupt
    _T2IE = 0; //Keep Interrupt disabled.


    //Set up output compare for step signal
    OC5CONbits.OCM = 0; //Toggle Pin on counter compare.  Disabled to start, begins when it's time to send steps (in ISR)
    OC5CONbits.OCSIDL = 0; //OC will continue in CPU idle mode.
    OC5CONbits.OCTSEL = 0; //Use Timer 2

    OC5R = 0;

    // IPC6bits.OC5IP = 0x01; // Set Output Compare 5 Interrupt Priority Level
    // IFS1bits.OC5IF = 0; // Clear Output Compare 5 Interrupt Flag
    // IEC1bits.OC5IE = 1; // Enable Output Compare 5 interrupt

    Status.status = 0; //Initialize status union to zeros.
    Status.bits.State = ST_MAXON_POWERED_DOWN;
    Status.bits.ChargeMode = CHARGE_AUTO_VOLT;

    Status.bits.DoorPositionTarget = 0; //Open doors at first powerup, should be open already in most cases
    Status.bits.DoorPositionActual = 1; //Assume they are closed at powerup to ensure opening and home at powerup.

    CAN_ENABLE = 1;
    CTRL_BATT_POWER = 1;
    MAXON_TETHER_POWER = 0; //Start with it possible for MAXON to be powered from Tether
    MAXON_POWER = 0; //Start with MAXON off
    Status.bits.MaxonPower = 0;


    Status.bits.MaxonPwrMode = MAXON_DEFAULTMODE;


    //Convert Default values from engineering units in config.h to working values.


    // Enable Timer interrupts now that everything is set up.
    _T1IE = 1; //Enable Interrupt, _T1Interrupt gets called at the beginning of each period. (10Hz or 25Hz, depending on CAN rate specified in config.h)





    unsigned int last_time_ctr = 0;

//#define MAXON_NOT_PRESENT //Define this if RS-232 debugging is needed and MAXON isn't present.    
#ifdef MAXON_NOT_PRESENT
    float time = 0.0;
    unsigned char s[256];
#endif
 //                  sprintf(s,"U1RXIP = %d\r\n U2RXIP = %d\r\n",
//                           _U1RXIP,
 //                          _U2RXIP);
 //       putsU1(s);


    while (1) {
        if (time_ctr != last_time_ctr) //Wait for time to be updated.
        {

            last_time_ctr = time_ctr;

#ifdef ALLOW_CALIBRATION
            if (raw == 1)
                sprintf(s, "%f             %d     %d     %d\r\n", time,
                    Pressure_ADC[0],
                    TetherVoltage_ADC[0],
                    BattVoltage_ADC[0]
                    );

            else
#endif

#ifdef MAXON_NOT_PRESENT
                time = time + 1.0/CAN_PACKET_RATE; //This will run out of resolution after about 21 days, but isn't used beyond being printed out.
              //  if(!Status.bits.MaxonPower)
             //   {
                                 sprintf(s, "%f   %f         %f    %f        %f   %f   %f       %ld    %d - %d    %d  %d  %d  %d  %d\r\n",
                                    time,
                                    ConvertFractToEngUnits(Pressure_Buf, Pressure_cnt, Pressure_eng),
                                    ConvertFractToEngUnits(TetherVoltage_Buf, TetherVoltage_cnt, TetherVoltage_eng),
                                    ConvertFractToEngUnits(BattVoltage_Buf, BattVoltage_cnt, BattVoltage_eng),
                                    IMU_DataA.yaw, IMU_DataA.pitch, IMU_DataA.roll,
                                        TreFoilPositionActualValue,Status.bits.DoorPositionTarget,Status.bits.DoorPositionActual,
                                    MAXON_CmdFromCAN,Status.bits.MaxonPwrMode,Status.bits.MaxonPower,Status.bits.MaxonEnabled,
                                         WindingCurrent
                                    );



                            putsU1(s);
              //  }

#else
                switch (Status.bits.MaxonPwrMode) {
                    case MAXON_MANUALMODE:
                    {
                        RunCmdsFromCAN();
                        break;
                    }
                    case MAXON_LOWPWRMODE:
                    case MAXON_HOLDPOSMODE:
                    case MAXON_MONITORPOSMODE:
                    {
                        if(StateMachine == VEL_MOVE_STATE_MACHINE)
                           VelMoveStateMachine();
                        
                        if(StateMachine == HOME_MOVE_STATE_MACHINE)
                           HomeMoveStateMachine();

                        break;
                    }
                }
#endif


        }

    }

    return 0;
} //main

