/*******************************************************************************
  Main Source File

  Company:
    Microchip Technology Inc.

  File Name:
    main.c

  Summary:
    This file contains the "main" function for a project.

  Description:
    This file contains the "main" function for a project.  The
    "main" function calls the "SYS_Initialize" function to initialize the state
    machines of all modules in the system
 *******************************************************************************/

/*******************************************************************************
* Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries.
*
* Subject to your compliance with these terms, you may use Microchip software
* and any derivatives exclusively with Microchip products. It is your
* responsibility to comply with third party license terms applicable to your
* use of third party software (including open source software) that may
* accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*******************************************************************************/


// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "definitions.h"                // SYS function prototypes
#include <string.h>


/* Application's state machine enum */
typedef enum
{
	APP_STATE_INITIALIZE,
    APP_STATE_EEPROM_WRITE_ENABLE,
    APP_STATE_EEPROM_WRITE,
    APP_STATE_EEPROM_READ_STATUS,
    APP_STATE_EEPROM_CHECK_STATUS,
    APP_STATE_EEPROM_READ,
    APP_STATE_DATA_COMPARISON,
    APP_STATE_XFER_SUCCESSFUL,
    APP_STATE_XFER_ERROR

} APP_STATES;

/* EEPROM Commands */
#define EEPROM_CMD_WREN                     0x06
#define EEPROM_CMD_WRITE                    0x02
#define EEPROM_CMD_RDSR                     0x05
#define EEPROM_CMD_READ                     0x03

#define EEPROM_ADDRESS                      0x000000
#define LED_On()                            LED_Set()
#define LED_Off()                           LED_Clear()

#define EEPROM_DATA                         "WRITING AND READING DATA FROM EEPROM!"
#define EEPROM_DATA_LEN                     sizeof(EEPROM_DATA)

/* Global variables */

// EEPROM CMD (1) + EEPROM ADDR (3) + EEPROM_DATA_LEN
uint8_t  txData[(4 + EEPROM_DATA_LEN)];
uint8_t  rxData[(4 + EEPROM_DATA_LEN)];
volatile bool isTransferDone = false;
APP_STATES state = APP_STATE_INITIALIZE;

/* This function will be called by SPI PLIB when transfer is completed */
void SPIEventHandler(uintptr_t context )
{
    /* De-assert the chip select */
    EEPROM_CS_Set();

    isTransferDone = true;
}

void EEPROM_Initialize (void)
{
    EEPROM_HOLD_Set();
    EEPROM_WP_Set();
    EEPROM_CS_Set();
    LED_Off();
}
// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

int main ( void )
{
    uint32_t eepromAddr = EEPROM_ADDRESS;

    /* Initialize all modules */
    SYS_Initialize ( NULL );

    while(1)
    {
        /* Check the application's current state. */
        switch (state)
        {
            case APP_STATE_INITIALIZE:
                EEPROM_Initialize();
                /* Register callback with the SPI PLIB */
                FLEXCOM2_SPI_CallbackRegister(SPIEventHandler, (uintptr_t) 0);
                state = APP_STATE_EEPROM_WRITE_ENABLE;
                break;

            case APP_STATE_EEPROM_WRITE_ENABLE:
                // Enable Writes to EEPROM
                txData[0] = EEPROM_CMD_WREN;
                EEPROM_CS_Clear();
                FLEXCOM2_SPI_Write(txData, 1);
                state = APP_STATE_EEPROM_WRITE;
                break;

            case APP_STATE_EEPROM_WRITE:
                if (isTransferDone == true)
                {
                    isTransferDone = false;
                    //Copy the write command and the memory address to write to
                    txData[0] = EEPROM_CMD_WRITE;
                    txData[1] = (uint8_t)(eepromAddr>>16);
                    txData[2] = (uint8_t)(eepromAddr>>8);
                    txData[3] = (uint8_t)(eepromAddr);
                    //Copy the data to be written to EEPROM
                    memcpy(&txData[4], EEPROM_DATA, EEPROM_DATA_LEN);
                    EEPROM_CS_Clear();
                    FLEXCOM2_SPI_Write(txData, (4 + EEPROM_DATA_LEN));
                    state = APP_STATE_EEPROM_READ_STATUS;
                }
                break;

            case APP_STATE_EEPROM_READ_STATUS:
                if (isTransferDone == true)
                {
                    isTransferDone = false;
                    /* Read the status of the internal write operation  */
                    txData[0] = EEPROM_CMD_RDSR;
                    EEPROM_CS_Clear();
                    FLEXCOM2_SPI_WriteRead(txData, 1, rxData, 2);
                    state = APP_STATE_EEPROM_CHECK_STATUS;
                }
                break;

            case APP_STATE_EEPROM_CHECK_STATUS:
                if (isTransferDone == true)
                {
                    isTransferDone = false;
                    if(!(rxData[1] & 0x01))
                    {
                        /* It means write has been completed */
                        state = APP_STATE_EEPROM_READ;
                    }
                    else
                    {
                        // Keep reading the status of the internal write operation
                        txData[0] = EEPROM_CMD_RDSR;
                        EEPROM_CS_Clear();
                        FLEXCOM2_SPI_WriteRead(txData, 1, rxData, 2);
                    }
                }
                break;

            case APP_STATE_EEPROM_READ:

                // Copy the read command and the memory address to read from
                txData[0] = EEPROM_CMD_READ;
                txData[1] = (uint8_t)(eepromAddr>>16);
                txData[2] = (uint8_t)(eepromAddr>>8);
                txData[3] = (uint8_t)(eepromAddr);

                EEPROM_CS_Clear();
                FLEXCOM2_SPI_WriteRead(txData, 4, rxData, (4 + EEPROM_DATA_LEN));
                state = APP_STATE_DATA_COMPARISON;

                break;

            case APP_STATE_DATA_COMPARISON:
                if (isTransferDone == true)
                {
                    isTransferDone = false;
                    if (memcmp(&txData[4], &rxData[4], EEPROM_DATA_LEN) != 0)
                    {
                        /* It means received data is not same as transmitted data */
                        state = APP_STATE_XFER_ERROR;
                    }
                    else
                    {
                        /* It means received data is same as transmitted data */
                        state = APP_STATE_XFER_SUCCESSFUL;
                    }
                }
                break;

            case APP_STATE_XFER_SUCCESSFUL:
                LED_On();
                break;

            case APP_STATE_XFER_ERROR:
                LED_Off();
                break;

            default:
                break;
        }
    }
}

/*******************************************************************************
 End of File
*/