/*
 * File:   main.c
 * Author: Mike Mellitt
 *         Ben Coffey
 *         Jake Thordahl
 *         Pat Bowlds
 *         Alex Toombs
 *
 * Main file for program to read voltage from battery resistor divider to
 *      monitor charge, MPH, other peripherals
 *
 * Analog pinout on board:
 *      A7:  Battery Stack Voltage (through divider)
 *      A6:  Break sensors
 *
 * Created on April 23, 2013, 4:35 PM
 *
 * Last Modified:  April 23, 2013
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/attribs.h>
#include "configbits.h"
#include <xc.h>
#include <plib.h>
#include <math.h>
#include "Other.h"
#define A 0x41
#define B 0x42
#define C 0x43
#define D 0x44
#define E 0x45
#define F 0x46
#define G 0x47
#define H 0x48
#define I 0x49
#define J 0x4A
#define K 0x4B
#define L 0x4C
#define M 0x4D
#define N 0x4E
#define O 0x4F
#define P 0x50
#define Q 0x51
#define R 0x52
#define S 0x53
#define T 0x54
#define U 0x55
#define V 0x56
#define W 0x57
#define X 0x58
#define Y 0x59
#define Z 0x5A
#define LED 0x50
#define LEDREG 0xFE
#define DAC 0xC0
#define LEDCLR 0x51
#define LEDRIGHT 0x4A
#define ZERO 0x30
#define ONE 0x31
#define TWO 0x32
#define THREE 0x33
#define FOUR 0x34
#define FIVE 0x35
#define SIX 0x36
#define SEVEN 0x37
#define EIGHT 0x38
#define NINE 0x39
#define COLON 0x3A
#define EQUAL 0x3D
#define DECIMAL 0x2E
#define CON 0x52

 #define true 1
 #define false 0

// voltage reading from battery sensor analog pin
double Battery_volt=0;
// voltage reading from break sensor through divider
double Break_volt=0;

int ChargeOn,Phase2,ChargeDone;
int On2,Haz,Night;
int Right,Left;
int But1,But2;
int breaking=0;
int flash=1,error=0;
int startcount=0;

// Loops continuously to adjust current source output
int main(int argc, char** argv) {
    // Timer Interrupts
    ConfigTime();
    // Analog Config pin B7
    ConfigAnalog();
    // I2C Config
    ConfigI2C();

    // disable JTAG so pin 12-15 can be used
    DDPCONbits.JTAGEN = 0;
    AD1PCFGbits.PCFG12 = 1;
    AD1PCFGbits.PCFG13 = 1;
    AD1PCFGbits.PCFG14 = 1;
    AD1PCFGbits.PCFG15 = 1;
    // Configure input ports------------------------------------------------
        //Status
    TRISEbits.TRISE0 = 1;  //charger connected                      //Logic Done
    TRISEbits.TRISE1 = 1;  //phase2
    TRISEbits.TRISE2 = 1;  //charger done
        //Switches
    TRISBbits.TRISB12 = 1; //night
    TRISBbits.TRISB13 = 1; //hazards
    TRISBbits.TRISB14 = 1; //on2
    TRISDbits.TRISD5 = 1;  //right
    TRISDbits.TRISD4 = 1;  //left
        //Buttons
    TRISBbits.TRISB10 = 1; //but2
    TRISBbits.TRISB11 = 1; //but1
    // Configure output ports-----------------------------------------------
    TRISEbits.TRISE3 = 0; //voltage div on
    LATEbits.LATE3 = 1;   //Turn on voltage divider
    TRISDbits.TRISD1 = 0; //Motor Controller on
    LATDbits.LATD1= 0;    //Motor START off
    TRISBbits.TRISB5 = 0; //LeftLED
    LATBbits.LATB5 = 0;   //Start off
    TRISBbits.TRISB4 = 0; //RightLED
    LATBbits.LATB4 = 0;   //Start off
    TRISBbits.TRISB3 = 0; //WarnLED
    LATBbits.LATB3 = 0;   //Start off
    TRISBbits.TRISB2 = 0; //NEULED
    LATBbits.LATB2 = 0;   //Start off
    TRISBbits.TRISB8 = 0; //Plate light
    LATBbits.LATB8 = 0;   //Start off
    TRISBbits.TRISB9 = 0; //Tail light
    LATBbits.LATB9 = 0;   //Start off

    // Create Variables

   SendI2C4(LED,LEDREG,CON,0x1E);
    // run continously to keep program running
    while(1)
    {
        //User Inputs
        ChargeOn=PORTEbits.RE0;
        Phase2=PORTEbits.RE1;
        ChargeDone=PORTEbits.RE2;

        On2=PORTBbits.RB14;
        Haz=PORTBbits.RB13; 
        Night=PORTBbits.RB12;
        Right=PORTDbits.RD5;
        Left=PORTDbits.RD4;

        But1=PORTBbits.RB11;
        But2=PORTBbits.RB10;

        //Outputs
        if(On2&!ChargeOn){
            LATDbits.LATD1= 1;    //Turn on motor
            error=0;
        }
        else if(On2&ChargeOn){
            LATDbits.LATD1= 0;    //Turn off motor
            error=1;
        }
        else{
            LATDbits.LATD1= 0;    //Turn off motor
            error=0;
        }
        if(Night){
            LATBbits.LATB8 = 1;   //Turn on plate light
        }
        else
            LATBbits.LATB8 = 0;   //Turn off plate light



    }
    return (EXIT_SUCCESS);
}
//-------------------------------------------------------------------------------
// TO-DO:  Configure timer and present message over I2C to display
void __ISR(8, IPL3AUTO) Timer2Hand(void)
{
        INTClearFlag(INT_T2);
        if(((Haz|error)|(Right|Left))&flash){  //Causes hazards to flash on and off
            if(Haz|error)
                LATBbits.LATB3 = 1;   //Warning display On
            else if(Right)
                LATBbits.LATB4 = 1;   //Right Light On
            else
                LATBbits.LATB5 = 1;   //Left Light On
            if(!error)
                LATBbits.LATB9 = 1;   //Tail Light On
            flash=0;
        }
        else{
            LATBbits.LATB3 = 0;   //Warning display OFF
            LATBbits.LATB5 = 0;   //Left Light OFF
            LATBbits.LATB4 = 0;   //Right Light OFF
            if(!breaking)
                LATBbits.LATB9 = 0;   //Tail Light OFF if not breaking
            flash=1;
        }
        // write logic to communicate values to peripherals

        // Display Status on I2C display
        if(startcount<25){
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,L);
            SendI2C2(LED,I);
            SendI2C2(LED,G);
            SendI2C2(LED,H);
            SendI2C2(LED,T);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,B);
            SendI2C2(LED,I);
            SendI2C2(LED,K);
            SendI2C2(LED,E);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,S);
            SendI2C2(LED,T);
            SendI2C2(LED,A);
            SendI2C2(LED,R);
            SendI2C2(LED,T);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,U);
            SendI2C2(LED,P);
            startcount++;
        }
        else if(ChargeDone){
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,D);
            SendI2C2(LED,O);
            SendI2C2(LED,N);
            SendI2C2(LED,E);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,C);
            SendI2C2(LED,H);
            SendI2C2(LED,A);
            SendI2C2(LED,R);
            SendI2C2(LED,G);
            SendI2C2(LED,I);
            SendI2C2(LED,N);
            SendI2C2(LED,G);
        }
        else if(Phase2){
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,T);
            SendI2C2(LED,R);
            SendI2C2(LED,I);
            SendI2C2(LED,C);
            SendI2C2(LED,K);
            SendI2C2(LED,L);
            SendI2C2(LED,E);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,C);
            SendI2C2(LED,H);
            SendI2C2(LED,A);
            SendI2C2(LED,R);
            SendI2C2(LED,G);
            SendI2C2(LED,I);
            SendI2C2(LED,N);
            SendI2C2(LED,G);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,E);
            SendI2C2(LED,S);
            SendI2C2(LED,T);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,T);
            SendI2C2(LED,I);
            SendI2C2(LED,M);
            SendI2C2(LED,E);
            SendI2C2(LED,COLON);
            SendI2C3(LED,LEDREG,LEDRIGHT);
        }
        else if(ChargeOn){
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,C);
            SendI2C2(LED,H);
            SendI2C2(LED,A);
            SendI2C2(LED,R);
            SendI2C2(LED,G);
            SendI2C2(LED,I);
            SendI2C2(LED,N);
            SendI2C2(LED,G);
            SendI2C3(LED,LEDREG,LEDRIGHT);
 
        }
        else if (!On2){
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,R);
            SendI2C2(LED,E);
            SendI2C2(LED,A);
            SendI2C2(LED,D);
            SendI2C2(LED,Y);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,T);
            SendI2C2(LED,O);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,T);
            SendI2C2(LED,U);
            SendI2C2(LED,R);
            SendI2C2(LED,N);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,O);
            SendI2C2(LED,N);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,B);
            SendI2C2(LED,A);
            SendI2C2(LED,T);
            SendI2C2(LED,T);
            SendI2C2(LED,E);
            SendI2C2(LED,R);
            SendI2C2(LED,Y);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,V);
            SendI2C2(LED,O);
            SendI2C2(LED,L);
            SendI2C2(LED,T);
            SendI2C2(LED,A);
            SendI2C2(LED,G);
            SendI2C2(LED,E);
            SendI2C2(LED,COLON);
            SendI2C3(LED,LEDREG,LEDRIGHT);

        }
        else{
            SendI2C3(LED,LEDREG,LEDCLR);
            SendI2C2(LED,D);
            SendI2C2(LED,R);
            SendI2C2(LED,I);
            SendI2C2(LED,V);
            SendI2C2(LED,I);
            SendI2C2(LED,N);
            SendI2C2(LED,G);
            SendI2C3(LED,LEDREG,LEDRIGHT);
            SendI2C2(LED,M);
            SendI2C2(LED,O);
            SendI2C2(LED,D);
            SendI2C2(LED,E);
            SendI2C3(LED,LEDREG,LEDRIGHT);

        }
}

// Configure bits for Timer operation
void ConfigTime()
{
    // Stops Timer and Clears register
    T2CON = 0x0;
    TMR2 = 0x0;
    // Set PR to 65535 originally 16000 with 3E80
    PR2 = 0xAFFF;
    
    // Set prescaler at 1:256
    T2CONSET = 0x0070;
    // Start Timer
    T2CONSET = 0x8000;
    INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
    // Enables Global Interrupts
    INTEnableInterrupts();
    // Enables Timer2 Interrupts
    INTEnable(INT_T2, INT_ENABLED);
    // Clears timer2 flag
    INTClearFlag(INT_T2);
    // Timer2 has priority 3
    INTSetVectorPriority(INT_T2,3); 
}
//----------------------------------------------------------------------------------------------------------------------------
// Configure analog registers to read value from sensors
void ConfigAnalog()
{
    // ensure the ADC is off before setting the configuration
    CloseADC10();
    // Turn module on  |ouput in integer| trigger mode auto | enable autosample
    #define PARAM1  ADC_MODULE_ON | ADC_FORMAT_INTG | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON
    // ADC ref external   | disable offset test    | disable scan mode
    //      | perform 8 samples | use dual buffers | use alternate mode
    #define PARAM2  ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_2 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON
    // use ADC PB clock| set sample time | auto
    #define PARAM3  ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_15
    // AN7 as analog inputs
    #define PARAM4	ENABLE_AN6_ANA | ENABLE_AN7_ANA
    // do not assign channels to scan
    #define PARAM5	SKIP_SCAN_ALL

    // configure to sample AN7 B7 and AN8
    SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN6|  ADC_CH0_NEG_SAMPLEB_NVREF | ADC_CH0_POS_SAMPLEB_AN7);
    // configure ADC using the parameters defined above
    OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 );
    // Note the 65 NS minimum TAD from datasheet, don't use FRM
    //AD1CON3bits.ADCS=0x01;
    EnableADC10();
}

// Read analog pin values for battery stack voltage and break voltage
void getAnalog()
{
    while ( ! mAD1GetIntFlag() )
    {
        // wait for the first conversion to complete so there
        // will be vaild data in ADC result registers
    }
    Battery_volt = ReadADC10(7)*.003185;  // pin 7 stack voltage
    Break_volt = ReadADC10(6)*.003185;  // pin 6 break voltage

    mAD1ClearIntFlag();
    // Clear ADC interrupt flag
}
//------------------------------------------------------------------------------------------------------------------------------------
// Configure I2C registers
void ConfigI2C()
{
    //1 USES RD10 AS SCL1 AND RD 9 AS SDA1
    /// I2CxCON I2CxSTAT I2CxADD I2CxMSK I2CxTRN I2CxRCV
    I2C1BRG=0x030;                  //390 for 80MHz to 100KHz
    I2C1CONbits.A10M=0;             //Use 7-bit addresses
    I2C1CONbits.DISSLW=1;           //disable slew control for standard
    I2C1CONbits.ACKDT=0;            //Use and ACK not NACK
    I2C1ADD=22;                     //Sets slave address for PIC32
    TRISD=1;                        //Sets Port D to input
    I2C1CONbits.ON=1;               //turn on I2C
}

// Start I2C
void I2C_start(void)
{
    I2C1CONbits.SEN=1;          //send start
    while(I2C1CONbits.SEN){}  //waits till start bit detected
}

// Restart I2C
void I2C_restart(void)
{
    I2C1CONbits.RSEN=1;         //send restart
    while(I2C1CONbits.RSEN){}  //waits till start bit detected
}

// Stop I2C
void I2C_stop(void)
{
    I2C1CONbits.PEN=1;          //send stop
    while(I2C1CONbits.PEN){}    //waits till stop bit detected
}

// Write char of data to I2C line
char I2C_write(char data)
{
    I2C1TRN=data;                   //sends data to transmit register
    while(I2C1STATbits.TRSTAT==1){} //waits to finsh transmission
    return(I2C1STATbits.ACKSTAT);   //returns 0 for ack received
}

// Check for acknowledgement
void mAckI2C1(void)
{
    I2C1CONbits.ACKDT=0;
    I2C1CONbits.ACKEN=1;
    while(I2C1CONbits.ACKEN){}
}

// Check for lack of acknowledgement
void mNAckI2C1(void)
{
I2C1CONbits.ACKDT=1;
I2C1CONbits.ACKEN=1;
while(I2C1CONbits.ACKEN){}
}

// Read data back from I2C line
char I2C_read(char ack)
{
    I2C1CONbits.RCEN=1;
    while(I2C1CONbits.RCEN){}
    //Reception is started, send ack/nack after read
    if(ack==0)
    {mNAckI2C1();}
    else
    {mAckI2C1();}
    //Reception should be complete - pull out data
    return(I2C1RCV);
}

// Make I2C line wait for registers to clear
void I2C_idle()
{
    while((I2C1CON&0x001F)!=0){}
    // Wait for Acken, Rcen, Pen, Rsen and Sen to clear
}

// Send data to I2C line at given address
void SendI2C3(char addrs,char regis, char data)
{
    char ack;
    I2C_start();
    ack=I2C_write(addrs); //Address for LED is 0x50
    ack=I2C_write(regis); //0xFE for LED
    ack=I2C_write(data);  //0x20to0x7F standard
    I2C_stop();
}

void SendI2C4(char addrs,char regis, char data, char con)
{
    char ack;
    I2C_start();
    ack=I2C_write(addrs); //Address for LED is 0x50
    ack=I2C_write(regis); //0xFE for LED
    ack=I2C_write(data);  //0x20to0x7F standard
    ack=I2C_write(con);  //0x20to0x7F standard
    I2C_stop();
}

// Writes to standard registers
void SendI2C2(char addrs, char data)
{
    char ack;
    I2C_start();
    ack=I2C_write(addrs); //Address for LED is 0x50
    ack=I2C_write(data);  //0x20to0x7F standard
    I2C_stop();
}