
/* DriverLib Defines */
#include "driverlib.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

/* Slave Address for I2C Slave */
#define SLAVE_ADDRESS       0x64
#define NUM_OF_REC_BYTES    2

//static uint8_t Read;
static uint8_t RX;
static uint8_t TXByteCtr;
//static float horAngle, verAngle, intensity;
static uint16_t X1, X2, Y1, Y2;

/* Variables */
static uint8_t TXData[3] = {0x12, 0x5f, 0x0c};
static uint8_t RXData[NUM_OF_REC_BYTES];
static volatile uint32_t xferIndex;
static volatile bool stopSent;




/* I2C Master Configuration Parameter */
const eUSCI_I2C_MasterConfig i2cConfig =
{
        EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        3000000,                                // SMCLK = 3MHz
        EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
        0,                                      // No byte counter threshold
        EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
};

#define TIMER_PERIOD    0xB71B

/* Timer_A UpMode Configuration Parameter */
const Timer_A_UpModeConfig upConfig =
{
        TIMER_A_CLOCKSOURCE_SMCLK,              // SMCLK Clock Source
        TIMER_A_CLOCKSOURCE_DIVIDER_64,          // SMCLK/1 = 3MHz
        TIMER_PERIOD,                           // 5000 tick period
        TIMER_A_TAIE_INTERRUPT_DISABLE,         // Disable Timer interrupt
        TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE ,    // Enable CCR0 interrupt
        TIMER_A_DO_CLEAR                        // Clear value
};

// UART Configuration
const eUSCI_UART_Config uartConfig =
{
        EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source

		//19200
		39,
		1,
		0,



        EUSCI_A_UART_NO_PARITY,                  // No Parity
        EUSCI_A_UART_LSB_FIRST,                  // LSB First
        EUSCI_A_UART_ONE_STOP_BIT,               // One stop bit
        EUSCI_A_UART_MODE,                       // UART mode
        EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // Oversampling
};


bool Setup_Register(unsigned char, unsigned char, unsigned char);
uint16_t Read_Data_Register(unsigned char);

void khzclock_Calibration();
void Setup_Config();
void UART_Transmit(uint16_t);
void ADC_Calibration();


const uint32_t default_config[] = {
        0x000c000f,
        0x00101010,
        0x0011004c,
        0x00125f0c,
        0x0013ada5,
        0x00140080,
        0x00150000,
        0x00160600,
        0x00170000,
        0x00182693,
        0x00190004,
        0x001a4280,
        0x001b0060,
        0x001c2094, // SDA/SCL pad slew rate limiter enabled
                    // INT output: enabled
                    // INT input: disabled
        0x001d0000,
        0x001e0001,
        0x001f0000,
        0x00200320,
        0x00210513,
        0x00220320,
        0x00230113,
        0x00240000,
        0x00252414,
        0x00262414,
        0x00270022,
        0x00280000,
        0x00290300,
        0x002a1770,
        0x002b157c,
        0x002c4268,
        0x002d2710,
        0x002e0000,
        0x002f0000,
        0x00300000,
        0x00310000,
        0x00320040,
        0x00330000,
        0x0034E400,
        0x00388080,
        0x00398080,

        // Initial values
        0x003a1e00,
        0x003b1e00,
        0x003c1e00,
        0x003d1e00,

        0x003e0000,
        0x0040806d,
        0x00411f2f,
        0x00424000,
        0x00430000,
        0x00440005,
        //0x00460020, // Decimation rate for sample mode: 4
        0x00460030,
		0x004800df, // INT_STATUS register: sample interrupt
        0x00490000,
        0x00450008, // Operation Mode: Sample Mode
};

int main(void)

{
    /* Disabling the Watchdog  */
    MAP_WDT_A_holdTimer();

    /* Setting DCO to 12MHz */
    CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);

    /* Setting DCO to 24MHz (upping Vcore)
    FlashCtl_setWaitState(FLASH_BANK0, 2);
    FlashCtl_setWaitState(FLASH_BANK1, 2);
    MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
    CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24);
    */

    /* Select Port 1 for I2C - Set Pin 6, 7 to input Primary Module Function,
     *   (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL).
     */

    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
            GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Selecting P1.2 and P1.3 in UART mode */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
            GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

    stopSent = false;
    memset(RXData, 0x00, NUM_OF_REC_BYTES);

    /* Initializing I2C Master to SMCLK at 100khz with no autostop */
    MAP_I2C_initMaster(EUSCI_B0_BASE, &i2cConfig);

    /* Specify slave address */
    MAP_I2C_setSlaveAddress(EUSCI_B0_BASE, SLAVE_ADDRESS);

    /* Set Master in transmit mode */
    MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    /* Enable I2C Module to start operations */
    MAP_I2C_enableModule(EUSCI_B0_BASE);

    /* Configuring UART Module */
    MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
    MAP_UART_enableModule(EUSCI_A0_BASE);

    /* Enable and clear the interrupt flag */
    MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);

    //Enable master Receive interrupt
    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    MAP_Interrupt_enableSleepOnIsrExit();
    MAP_Interrupt_enableInterrupt(INT_EUSCIB0);


    //MAP_Interrupt_enableSleepOnIsrExit();
    MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
    MAP_Interrupt_enableInterrupt(INT_TA1_0);

    MAP_Interrupt_enableMaster();

    // set interrupt pin as input
    MAP_GPIO_setAsInputPin(GPIO_PORT_P6, GPIO_PIN7);

    printf("reading chip id and version value\n");
    Read_Data_Register(0x08);

    printf("setting up registers\n");
    Setup_Register(0x0f, 0x00, 0x01);       // Resetting the device
    Setup_Config();                         //004 Configuration

    printf("default config loaded\n");

    //printf("calibrating 32 khzclock\n");
    //khzclock_Calibration();

    // Setup_Register(0x3A, 0x20, 0x70);
    // Setup_Register(0x3B, 0x1D, 0x50);
    // Setup_Register(0x3C, 0x, 0x);
    // Setup_Register(0x3D, 0x, 0x);



    /*
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P2, GPIO_PIN7);
    MAP_GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN7);
    MAP_Interrupt_enableInterrupt(INT_PORT2);*/

    Setup_Register(0x49, 0x08, 0x20);
    //ADC_Calibration();
    //Setup_Register(0x49, 0x08, 0x20);

    while (1)
    {

    	if (P6IN & BIT7) {

    	//if (data_available == 1) {
    			   Setup_Register(0x49, 0x08, 0x20);

    		 	 	X1 = Read_Data_Register(0x00);
    		        X2 = Read_Data_Register(0x01);
    		        Y1 = Read_Data_Register(0x02);
    		        Y2 = Read_Data_Register(0x03);

    		       MAP_UART_transmitData(EUSCI_A0_BASE, 0x0a);
    		       UART_Transmit(X1);
    		       UART_Transmit(X2);
    		       UART_Transmit(Y1);
    		       UART_Transmit(Y2);



    		      // data_available = 0;
    	}


    }
}

/*******************************************************************************
 * eUSCIB0 ISR. The repeated start and transmit/receive operations happen
 * within this ISR.
 *******************************************************************************/
void EUSCIB0_IRQHandler(void)
{
    uint_fast16_t status;

    status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE);
    MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status);

    /* If we reached the transmit interrupt, it means we are at index 1 of
     * the transmit buffer. When doing a repeated start, before we reach the
     * last byte we will need to change the mode to receive mode, set the start
     * condition send bit, and then load the final byte into the TXBUF.
     */
    if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
    {
        /*if (RX == 0) {*/
            if (TXByteCtr) {
                //Send the next data and decrement the byte counter
                MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[3 - TXByteCtr]);
                TXByteCtr--;
            }
            else {
                if (RX == 0) {
                    MAP_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
                    stopSent = true;
                    MAP_Interrupt_disableSleepOnIsrExit();
                }
                else {
                    MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
                    MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
                    xferIndex = 0;
                    MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);
                    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                }
            }
    }

    /* Receives bytes into the receive buffer. If we have received all bytes,
     * send a STOP condition */
    if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
    {
        if(xferIndex == NUM_OF_REC_BYTES - 2)
        {
            MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
            RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
        }
        else if(xferIndex == NUM_OF_REC_BYTES - 1)
        {
            RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
            MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
            xferIndex = 0;
            stopSent = true;
            MAP_Interrupt_disableSleepOnIsrExit();
        }
        else
        {
            RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
        }

    }
}

/*
void khzclock_Calibration(){

	Setup_Register(0x40, 0x00, 0x08); // setting output rate as 50Hz
	Setup_Register(0x45, 0x00, 0x08); // run device in sample mode

	Read_Data_Register(0x00);
	Read_Data_Register(0x01);
	Read_Data_Register(0x02);
	Read_Data_Register(0x03);

	static int count = 0;

	uint8_t j;
	for(j = 0; j<500; j++)
	{
		Read_Data_Register(0x00);
		Read_Data_Register(0x01);
		Read_Data_Register(0x02);
		Read_Data_Register(0x03);
		count++;
	}

}
*/

void Setup_Config() {

    uint8_t i;
    for (i = 0; i < 54; i++) {
        unsigned char address = (unsigned char)(default_config[i] >> 16);
        unsigned char msb = (unsigned char)(default_config[i] >> 8);
        unsigned char lsb = (unsigned char)(default_config[i]);


        while (Setup_Register(address, msb, lsb) != 1);
    }

}

void UART_Transmit(uint16_t data) {

       unsigned char *ptr = (unsigned char*) &data;

       MAP_UART_transmitData(EUSCI_A0_BASE, *ptr++);
       MAP_UART_transmitData(EUSCI_A0_BASE, *ptr);


}

void ADC_Calibration() {

	printf("calibrating X1\n");

		uint16_t offset = 0x1e00;

	    	//if (data_available == 1) {

				do {

					if (P6IN & BIT7) {
	    			   Setup_Register(0x49, 0x08, 0x20);
	    		       Setup_Register(0x32, 0x0f, 0x4f);

	    		       X1 = Read_Data_Register(0x00);

	    		       offset += 1;
	    		       Setup_Register(0x3a, (unsigned char)(offset >> 8), (unsigned char)(offset));

	    		       Setup_Register(0x32, 0x00, 0x40);
					}

				} while (X1 > 3000);



	printf("final offset: %X\n", offset);

}

bool Setup_Register(unsigned char address, unsigned char highByte, unsigned char lowByte){

    while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);

    RX = 0;
    TXByteCtr = 2;

    TXData[0] = address;
    TXData[1] = highByte;
    TXData[2] = lowByte;

    MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]);
    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);


    while(!stopSent)
    {
        MAP_PCM_gotoLPM0InterruptSafe();
    }

    stopSent = false;

    if (address == 0x49)
            return 1;

    uint16_t data = Read_Data_Register(address);


    return (data == (highByte << 8)+lowByte);
}

uint16_t Read_Data_Register(unsigned char address) {

    while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);

    RX = 1;
    TXByteCtr = 0;

    MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, address);
    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);


    while(!stopSent)
    {
        MAP_PCM_gotoLPM0InterruptSafe();
    }

    stopSent = false;

    return (RXData[0] << 8)+RXData[1];
}

