/*
 * File:   main.c
 * Author: cterndru
 *
 * Created on May 1, 2015, 3:53 AM
 */

#include <stdio.h>
#include <stdlib.h>
#include "Accel.h"
#include "Light.h"
#include "Memory.h"
#include "configbits.h"
#include <sys/attribs.h>

#define DATA_ENTRIES 11
#define DEVICE_ID_ADDRESS 10


int ready_to_write_timer = 0;

void __ISR(_RTCC_VECTOR,IPL4AUTO)alarm_handler(void){
    IFS0bits.RTCCIF = 0; // clear RTCC interrupt flag
    //ready_to_write_RTC = 1;


    LATBbits.LATB8 = 1;


}

 __ISR(12,IPL3AUTO)measurement_handler(void){ 	// change 12 to actual vector name
    IFS0bits.T3IF = 0; // clear the interrupt flag
    ready_to_write_timer = 1;
}

/*
 *
 */
int main(int argc, char** argv) {

    DDPCONbits.JTAGEN = 0;
    ANSELB = 0;
    // Pin remapping
    SYSKEY = 0x0;
    SYSKEY = 0xaa996655;
    SYSKEY = 0x556699aa;
    CFGCONbits.IOLOCK = 0;
    TRISBbits.TRISB9 = 1;	// Pin 1	Com Port V. Divider- Set to input
    U1RXRbits.U1RXR = 0b0101; 		// Pin 2 U1RX
    RPC7Rbits.RPC7R = 0b0001;		// Pin 3	U1TX
    U1CTSRbits.U1CTSR = 0b0110;		// Pin 4 U1CTS
    RPC9Rbits.RPC9R = 0b0001;             // Pin 5 U1RTS
    INT3Rbits.INT3R = 0b0011;             // Pin 9 Light Int (Int 3)
    SS1Rbits.SS1R = 0b0000;              // Pin 19 SS1
    RPA1Rbits.RPA1R = 0b0011;		// Pin 20 SDO1
    TRISBbits.TRISB0 = 0;	// Pin 21 CS- Set to output
    SDI1Rbits.SDI1R = 0b0010;		// Pin 22 SDI1
    INT2Rbits.INT2R = 0b0110;		// Pin 26 Accel. Int (Int 2)
    INT4Rbits.INT4R = 0b0110;             // Pin 25 Accel. Int (Int 4)
    TRISCbits.TRISC5 = 0;	// Pin 38 Power PS Pin- Set to output
    LATCbits.LATC5 = 0;     	// Set PS low
    CFGCONbits.IOLOCK = 1;
        // enable secondary oscillator
    OSCCONbits.SOSCEN = 1;
    while (!OSCCONbits.SOSCRDY);
    SYSKEY = 0x0;

    TRISBbits.TRISB8 = 0;
    LATBbits.LATB8 = 0;

 
    // toggle I2C clk 9 times
    TRISBbits.TRISB3 = 0;
    LATBbits.LATB3 = 0;
    int i;
   // i2c_start();
    for (i=0; i<18; i++) {
        LATBbits.LATB3 = !LATBbits.LATB3;
    }
    //i2c_start();
    //i2c_stop();


    spi_init();
    i2c_init();
    accel_init();
    LS_init();

    U1BRG = 51;         // 10 for 57600, 64 for 9600 (for 10 MHz PBCLK)
                        // 51 for 9600 (8 MHz PBCLK)
    U1MODE = 0x0000;
    U1STASET = 0x1400;  // enable transmit/receive
    U1MODE = 0x8000;    // not setting individual bits; 8 bits, no parity, etc...


    T3CONbits.ON = 0; // disable timer 2
    T3CONbits.TCKPS = 0x6; // 1:64 prescaler
    //T2CONbits.T32 = 1; // enable 32-bit mode
    TMR3 = 0x0000; // clear timer 3
    //TMR2 = 0x0000; // clear timer 2
    //PR2 = 0xF424; // timer will interrupt every half second (0x1312D)
                  // 2625A (10 MHz)
    PR3 = 0xF424;
    IFS0bits.T3IF = 0; // clear Timer 2 interrupt flag
    IPC3bits.T3IP = 3; // set priority to 3
    IEC0bits.T3IE = 1; // enable interrupt
    T3CONbits.ON = 1; // enable timer 2
    while (!T3CONbits.ON);
    

// values for initializing RTC
    int hr10 = 0;
    int hr01 = 0;
    int min10 = 0;
    int min01 = 0;
    int sec10 = 0;
    int sec01 = 0;

    // place microcontroller into sleep mode if WAIT instruction issued
    OSCCONbits.SLPEN = 1; // sleep mode

    RTCCONbits.RTCOE = 0;

        // Enable multi-vectored interrupts
    INTCONbits.MVEC = 1;

    RTCCONbits.RTSECSEL = 0;

    

    //while(RTCCONbits.RTCSYNC);
    SYSKEY = 0x00000000;
    SYSKEY = 0xaa996655;
    SYSKEY = 0x556699aa;
    while(RTCCONbits.RTCSYNC);
    RTCCONSET = 0x8;
    RTCCONbits.RTCWREN = 1;

    IEC0bits.RTCCIE = 0;

    RTCCONbits.ON = 0;
    while (RTCCONbits.RTCCLKON);

    

    IFS0bits.RTCCIF = 0; // clear RTCC interrupt flag
    IPC6bits.RTCCIP = 0; // set priority to 4
    IPC6bits.RTCCIP = 4; // set priority to 4
    //IEC0bits.RTCCIE = 1; // enable interrupt

    

    RTCTIMEbits.HR10 = hr10;
    RTCTIMEbits.HR01 = hr01;
    RTCTIMEbits.MIN10 = min10;
    RTCTIMEbits.MIN01 = min01;
    RTCTIMEbits.SEC10 = sec10;
    RTCTIMEbits.SEC01 = sec01;

    // set alarm to occur at 1 min
    // will wake up MCU
    
    RTCALRMCLR = 0xcfff;
    ALRMTIMEbits.HR10 = 0;
    ALRMTIMEbits.HR01 = 0;
    ALRMTIMEbits.MIN10 = 0;
    ALRMTIMEbits.MIN01 = 0;
    ALRMTIMEbits.SEC10 = 0;
    ALRMTIMEbits.SEC01 = 0;

    RTCALRMbits.AMASK = 1;   // once per second, look into half second
    while(RTCALRMbits.ALRMSYNC);
    //RTCALRMbits.AMASK = 0x3; // once a minute
    
    RTCALRMbits.CHIME = 1; // indefinite repeat
    RTCALRMbits.ARPT = 0xFF;

    RTCALRMbits.ALRMEN = 1; // enable the alarm

    IEC0bits.RTCCIE = 1; // enable interrupt

    //**********************
    RTCCONbits.ON = 1;
    while(!RTCCONbits.RTCCLKON);

    

    RTCCONbits.RTCWREN = 0;
    while(RTCCONbits.RTCWREN);
    SYSKEY = 0x00000000;

    // enable interrupts
    asm("ei");

    unsigned long address = 0; 
    unsigned int uv;
    struct accel_data ad;

    spi_erase_flash();

    while (1)
    {                                                                                                                                           
        // collect data on
        if (ready_to_write_timer) {
            spi_write_flash(RTCTIME >> 24,address);
           //readVal = spi_read_flash(address);
           ++address;

           spi_write_flash(RTCTIME >> 16,address);
           //readVal = spi_read_flash(address);
           ++address;

           spi_write_flash(RTCTIME >> 8,address);
           //readVal = spi_read_flash(address);
           ++address;

           spi_write_flash(RTCTIME,address);
           //readVal = spi_read_flash(address);
           ++address;

            // store light then axdl

           uv = LS_measure();
           spi_write_flash(uv/100,address);
           //readVal = spi_read_flash(address);
           ++address;

           ad = accel_measure();
           spi_write_flash(ad.xl,address);
           //testVal1 = spi_read_flash(address);
           ++address;
           spi_write_flash(ad.xh,address);
           //testVal2 = spi_read_flash(address);
           ++address;
           spi_write_flash(ad.yl,address);
           //testVal3 = spi_read_flash(address);
           ++address;
           spi_write_flash(ad.yh,address);
           //testVal4 = spi_read_flash(address);
           ++address;
           spi_write_flash(ad.zl,address);
           //testVal5 = spi_read_flash(address);
           ++address;
           spi_write_flash(ad.zh,address);
           //testVal6 = spi_read_flash(address);
           ++address;
           ready_to_write_timer = 0;
           // Issue wait instruction to CPU to put MCU to sleep
           asm("WAIT");
        }

        while (PORTBbits.RB9 == 1) {
                while(U1STAbits.URXDA);
                while(!U1STAbits.URXDA);
                char command = U1RXREG;

                switch(command) {
                    case 'B':
                        offload_data(0);
                        break;
                    case 'T':
                        while (!U1STAbits.TRMT);
                        U1TXREG = 'T';
                        set_device_time();
                        break;
                    case 'C':
                        while (!U1STAbits.TRMT);
                        U1TXREG = 'C';
                        spi_erase_flash();
                        break;
                    case 'D':
                        while (!U1STAbits.TRMT);
                        U1TXREG = 'D';
                        set_device_id();
                        break;
                    default:
                        break;
                }
                address = DATA_ENTRIES;
        }


   }

    //while(1);
    return (EXIT_SUCCESS);
}

void set_device_time(void) {
    // wait till PC sends hours
    while(!U1STAbits.URXDA);
    char hours = U1RXREG;
    // send acknowledge
    while (!U1STAbits.TRMT);
    U1TXREG = 'S';
    // wait till PC sends minutes
    while(!U1STAbits.URXDA);
    char minutes = U1RXREG;
    // send acknowledge
    while (!U1STAbits.TRMT);
    U1TXREG = 'S';
    // wait till PC sends seconds
    while(!U1STAbits.URXDA);
    char seconds = U1RXREG;
    // send acknowledge
    while (!U1STAbits.TRMT);
    U1TXREG = 'S';

    // set device time
    while(RTCCONbits.RTCSYNC);
    asm("di");
    SYSKEY = 0x0;
    SYSKEY = 0xAA996655;
    SYSKEY = 0x556699AA;
    RTCCONbits.RTCWREN = 1;
    RTCCONSET = 0x8;
    RTCCONCLR = 0x8000;

    while(!RTCCONbits.RTCWREN);

    while (!U1STAbits.TRMT);

    //RTCCONCLR = 0x8000;
    while(RTCCONbits.RTCCLKON);

    //while(RTCCONbits.RTCSYNC);
    while(RTCTIMEbits.HR01 != hours%10){
        RTCTIMEbits.HR10 = hours/10;
        RTCTIMEbits.HR01 = hours % 10;
        RTCTIMEbits.MIN10 = minutes/10;
        RTCTIMEbits.MIN01 = minutes % 10;
        RTCTIMEbits.SEC10 = seconds/10;
        RTCTIMEbits.SEC01 = seconds % 10;
    }
    asm("ei");

    RTCCONSET = 0x8000;
    RTCCONbits.RTCWREN = 0;



    while(RTCCONbits.RTCWREN);
    while(!RTCCONbits.RTCCLKON);
    SYSKEY = 0x0;
}

void set_device_id(void) {
    // wait till PC sends id
    while(!U1STAbits.URXDA);
    char id = U1RXREG;
    // send acknowledge
    while (!U1STAbits.TRMT);
    U1TXREG = 'S';
    // write ID to memory
    // need to erase before writing to flash
    //spi_WRSR_flash(0x02);
    spi_write_flash(id,DEVICE_ID_ADDRESS);
}


void offload_data(unsigned long address) {

            address = 0;
            const int data_size = 4096;
            unsigned char data[data_size];

            //while(1){
                while(!U1STAbits.TRMT); // wait until transmit shift reg empty
                // Wait until UART RX register has data from PC
                //while(U6RXREG != 'B'); // wait for the 'B' sent by the PC
                U1TXREG = 'B'; // tell PC to send number of bytes to send
                // Wait until UART RX register has data from PC
                while(!U1STAbits.URXDA); // wait for bytes_to_send data from PC
                int bytes_to_send = U1RXREG;
                U1TXREG = 'S'; // tell PC it may begin reading data -- might be unnecessary


                int loop_counter = 0;
                int start = 0;
                int end = bytes_to_send-1;
                int i = 0;
                // BEGINNING OF OLD CODE
                while(1){
                // Wait until UART RX register has data from PC
                    if (!loop_counter){
                        while(U1RXREG != 'W');
                    }
                    else {
                        while(!U1STAbits.URXDA);
                    }
                    //while(U6RXREG != 'W');
                    // Place desired data into UART TX Register...
                    // ...once transmit buffer is empty
                    //while(U6STAbits.UTXBF);

                    while(!U1STAbits.TRMT);
                    for (i=start; i < end+1; i++){
                        // NEW
                        int j = 0;
                        // format real time clock
                        data[j] = spi_read_flash(address);
                        if (address % 11 == 0 && address > 10) {
                            char hour10 = (data[j] & 0x30) >> 4;
                            char hour01 = (data[j] & 0x0F);
                            char hour = hour10*10 + hour01;
                            data[j] = hour;
                        }
                        else if (address % 11 == 1 && address > 10) {
                            char min10 = (data[j] & 0x70) >> 4;
                            char min01 = (data[j] & 0x0F);
                            char min = min10*10 + min01;
                            data[j] = min;
                        }
                        else if (address % 11 == 2 && address > 10) {
                            char sec10 = (data[j] & 0x70) >> 4;
                            char sec01 = (data[j] & 0x0F);
                            char sec = sec10*10 + sec01;
                            data[j] = sec;
                        }
                        ++address;

                        while(U1STAbits.UTXBF);
                        U1TXREG = data[j];
                        ++j; // NEW
                    }
                    ++loop_counter;
                    start += bytes_to_send;
                    if (end == data_size-1){
                        break;
                    }
                    if (end+bytes_to_send > data_size){
                        end = data_size-1;
                    }
                    else {
                        end += bytes_to_send;
                    }
                }
                U1STAbits.OERR = 0; // clear receiver overflow
                //address = 0;
          
}