/*

                         \\\|///
                       \\  - -  //
                        (  @ @  )
+---------------------oOOo-(_)-oOOo-------------------------+
|              Luminaryボードのサンプルプログラム           |
|                        I2Cテスト                          |
|                      by Xiaoran Liu                       |
|                        2008.4.16                          |
|                                                           |
|                  株式会社 日昇テクノロジー                |
|                    http://www.csun.co.jp                  |
|                             Oooo                          |
+-----------------------oooO--(   )-------------------------+
                       (   )   ) /
                        \ (   (_/
                         \_)     

*/
#include "hw_ints.h"
#include "hw_memmap.h"
#include "hw_types.h"
#include "debug.h"
#include "gpio.h"
#include "timer.h"
#include "sysctl.h"
#include "i2c.h"
#include "hw_i2c.h"
#include "interrupt.h"

#include "PCD5544.h"
/*----------------------------------------------------------*\
 | DEFINES                                                  |
\*----------------------------------------------------------*/
// The states in the interrupt handler state machine.
#define STATE_IDLE         0
#define STATE_WRITE_NEXT   1
#define STATE_WRITE_FINAL  2
#define STATE_WAIT_ACK     3
#define STATE_SEND_ACK     4
#define STATE_READ_ONE     5
#define STATE_READ_FIRST   6
#define STATE_READ_NEXT    7
#define STATE_READ_FINAL   8
#define STATE_READ_WAIT    9
/*----------------------------------------------------------*\
 | VARIABLE                                                 |
\*----------------------------------------------------------*/
// The variables that track the data to be transmitted or received.
static unsigned char *g_pucData = 0;
static unsigned long g_ulCount = 0;
// The current state of the interrupt handler state machine.
static volatile unsigned long g_ulState = STATE_IDLE;
/*----------------------------------------------------------*\
 | The error routine that is called			                |
 | if the driver library encounters an error.               |
\*----------------------------------------------------------*/
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif
/*----------------------------------------------------------*\
 | he I2C interrupt handler.                                |
\*----------------------------------------------------------*/
void I2CIntHandler(void) {
    I2CMasterIntClear(I2C0_MASTER_BASE);    // Clear the I2C interrupt.

    // Determine what to do based on the current state.
    switch(g_ulState) {
        // The idle state.
        case STATE_IDLE:
            // There is nothing to be done.
            break;

        // The state for the middle of a burst write.
        case STATE_WRITE_NEXT:
            // Write the next byte to the data register.
            I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
            g_ulCount--;
            // Continue the burst write.
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
            // If there is one byte left, set the next state to the final write state.
            if(g_ulCount == 1)
                g_ulState = STATE_WRITE_FINAL;
            // This state is done.
            break;

        // The state for the final write of a burst sequence.
        case STATE_WRITE_FINAL:
            // Write the final byte to the data register.
            I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
            g_ulCount--;
            // Finish the burst write.
            I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_FINISH);
            // The next state is to wait for the burst write to complete.
            g_ulState = STATE_SEND_ACK;
            // This state is done.
            break;

        // Wait for an ACK on the read after a write.
        case STATE_WAIT_ACK: {
            // See if there was an error on the previously issued read.
			volatile unsigned short err = I2CMasterErr(I2C0_MASTER_BASE);
            if(err == I2C_MASTER_ERR_NONE) {
                // Read the byte received.
                I2CMasterDataGet(I2C0_MASTER_BASE);
                // There was no error, so the state machine is now idle.
                g_ulState = STATE_IDLE;
                // This state is done.
                break;
            	}
            // Fall through to STATE_SEND_ACK.
        	}

        // Send a read request, looking for the ACK to indicate that the write is done.
        case STATE_SEND_ACK: {
            // Put the I2C master into receive mode.
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);
            // Perform a single byte read.
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
            // The next state is the wait for the ack.
            g_ulState = STATE_WAIT_ACK;
            // This state is done.
            break;
            }

        // The state for a single byte read.
        case STATE_READ_ONE: {
            // Put the I2C master into receive mode.
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);
            // Perform a single byte read.
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
            // The next state is the wait for final read state.
            g_ulState = STATE_READ_WAIT;
            // This state is done.
            break;
           }

        // The state for the start of a burst read.
        case STATE_READ_FIRST: {
            // Put the I2C master into receive mode.
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);
            // Start the burst receive.
            I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START);
            // The next state is the middle of the burst read.
            g_ulState = STATE_READ_NEXT;
            // This state is done.
            break;
            }

        // The state for the middle of a burst read.
        case STATE_READ_NEXT: {
            // Read the received character.
            *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;
            // Continue the burst read.
            I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_CONT);
            // If there are two characters left to be read, make the next
            // state be the end of burst read state.
            if(g_ulCount == 2){
                g_ulState = STATE_READ_FINAL;
                }
            // This state is done.
            break;
            }

        // The state for the end of a burst read.
        case STATE_READ_FINAL: {
            // Read the received character.
            *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;
            // Finish the burst read.
            I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
            // The next state is the wait for final read state.
            g_ulState = STATE_READ_WAIT;
            // This state is done.
            break;
            }

        // This state is for the final read of a single or burst read.
        case STATE_READ_WAIT: {
            // Read the received character.
            *g_pucData++  = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;
            // The state machine is now idle.
            g_ulState = STATE_IDLE;
            // This state is done.
            break;
            }
        }
    }
/*----------------------------------------------------------*\
 | Write to the Atmel device.                               |
\*----------------------------------------------------------*/
void AtmelWrite(unsigned char *pucData, unsigned long ulOffset,unsigned long ulCount) {
    // Save the data buffer to be written.
    g_pucData = pucData;
    g_ulCount = ulCount;
    // Set the next state of the interrupt state machine based on the number of
    // bytes to write.
    if(ulCount != 1)
        g_ulState = STATE_WRITE_NEXT;
    else
        g_ulState = STATE_WRITE_FINAL;
    // Set the slave address and setup for a transmit operation.
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50 | (ulOffset >> 8), false);
    // Place the address to be written in the data register.
    I2CMasterDataPut(I2C0_MASTER_BASE, ulOffset);
    // Start the burst cycle, writing the address as the first byte.
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    // Wait until the I2C interrupt state machine is idle.
    while(g_ulState != STATE_IDLE);
    }
/*----------------------------------------------------------*\
 | Read from the Atmel device.                              |
\*----------------------------------------------------------*/
void
AtmelRead(unsigned char *pucData, unsigned long ulOffset,unsigned long ulCount) {
    // Save the data buffer to be read.
    g_pucData = pucData;
    g_ulCount = ulCount;
    // Set the next state of the interrupt state machine based on the number of
    // bytes to read.
    if(ulCount == 1)
        g_ulState = STATE_READ_ONE;
    else
        g_ulState = STATE_READ_FIRST;
    // Start with a dummy write to get the address set in the EEPROM.
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50 | (ulOffset >> 8), false);
    // Place the address to be written in the data register.
    I2CMasterDataPut(I2C0_MASTER_BASE, ulOffset);
    // Perform a single send, writing the address as the only byte.
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    // Wait until the I2C interrupt state machine is idle.
    while(g_ulState != STATE_IDLE);
    }
/*----------------------------------------------------------*\
 | MIAN ENTRY                                               |
\*----------------------------------------------------------*/
int main(void) {
    volatile unsigned long ulLoop;
    unsigned char pucData[16];
    unsigned long ulIdx;

    // Set the clocking to run directly from the crystal.
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	// Enable the GPIO pin to read the select button.
	GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
	GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); 
	if( GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_4) == 0 ) for(;;);

    // Configure the GPIO that drives the on-board LED.
    GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_5, GPIO_DIR_MODE_OUT);

	LCD_Backlight_On();
	LCD_Init();
	LCD_Cls();
	LCD_GotoXY(22, 0);	LCD_PrintStr("LM3S102", 0);
	LCD_GotoXY(12, 1);	LCD_PrintStr("Eval Board", 0);
	LCD_GotoXY(20, 2);	LCD_PrintStr("I2C test", 0);
	LCD_GotoXY(12, 4);	LCD_PrintStr("CSUN Tech.", 0);
	LCD_GotoXY(0, 5);	LCD_PrintStr("www.csun.co.jp", 0);
	//LCD_Backlight_Off();

    // Enable the peripherals used by this example.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    // Enable processor interrupts.
    IntMasterEnable();
    // Configure the appropriate pins to be I2C instead of GPIO.
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    // Initialize the I2C master.
    //I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);
    I2CMasterInit(I2C0_MASTER_BASE, false);
    // Enable the I2C interrupt.
    IntEnable(INT_I2C0);
    // Enable the I2C master interrupt.
    I2CMasterIntEnable(I2C0_MASTER_BASE);

    // Write a data=address pattern into the first 16 bytes of the Atmel device.
    for(ulIdx = 0; ulIdx < 8; ulIdx++)
        pucData[ulIdx] = ulIdx;
    //AtmelWrite(pucData, 0, 16);
    AtmelWrite(pucData, 0, 8);

    // Read back the first 16 bytes of the Atmel device and verify that it
    // contains the data it should.
    AtmelRead(pucData, 0, 8);
    for(ulIdx = 0; ulIdx < 8; ulIdx++) {
        if(pucData[ulIdx] != ulIdx) {
			LCD_GotoXY(10, 3);	LCD_PrintStr(" Data error ", 1);
            goto Over;
            }
        }

    // Success.
	LCD_GotoXY(10, 3);	LCD_PrintStr("  Success  ", 1);
Over:
    // Loop forever.
    while(1) {
		if( GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_4) == 0 ) {
			//LCD_GotoXY(30, 3);	LCD_PrintStr("BP2", 1);
	        // Turn on the LED.
	        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0);
			}
		else {
			//LCD_GotoXY(30, 3);	LCD_PrintStr("BP2", 0);
	        // Turn off the LED.
	        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, GPIO_PIN_5);
			}
	    }
	}
/*----------------------------------------------------------*\
 | END OF FILE                                              |
\*----------------------------------------------------------*/
