//******************************************************************************
//  Include(s) for External Component API(s)
//******************************************************************************
#include <stdint.h>
//******************************************************************************
// Include(s) for Common Component API(s)
//******************************************************************************
#include <sam4sd32c.h>
#include <conf_board.h>
#include "udc.h"
//******************************************************************************
// Include(s) for Internal Component API(s)
//******************************************************************************
#include "spi.h"
#include "eeprom.h"
//******************************************************************************
//! @fn uint16_t EEPROM_read_status (sensor_axis_e axis, sensor_board_e board)
//!
//! @description
//! reads status of EEPROM.
//!
//! @param    axis     Axis
//!           board    Board
//!
//! @return   EEPROM status
//!
//! @calls    SPI_setDec
//!           SPI_setCs 
//!           SPI_master_write 
//!           SPI_resetAllCs  
//!           SPI_master_read     
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
uint16_t EEPROM_read_status (sensor_axis_e axis, sensor_board_e board)
{
	
	SPI_setDec(chip_EEPROM);
	SPI_ConfigureCs(axis, board);
    SPI_setCs();
	
	//Send request to read status register
	SPI_master_write(EEPROM_RDSR);
	
	//Send dummy data to read required data
	SPI_master_write(0);
	
	SPI_resetAllCs();

	return SPI_master_read();
}
//******************************************************************************
//! @fn void EEPROM_write_status (sensor_axis_e axis, sensor_board_e board, uint8_t data)
//!
//! @description
//! enables writing in EEPROM
//!
//! @param    axis     Axis
//!           board    Board
//!           data     data to write
//!
//! @return   None
//!
//! @calls    EEPROM_read_status
//!           EEPROM_write_enable 
//!           SPI_master_write 
//!           SPI_resetAllCs  
//!           SPI_setDec 
//!           SPI_setCs
//!           EEPROM_read_status    
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
void EEPROM_write_status (sensor_axis_e axis, sensor_board_e board, uint8_t data)
{
	
	while(EEPROM_read_status(axis, board) & EEPROM_RDY);
	EEPROM_write_enable(axis, board);

	SPI_setDec(chip_EEPROM);
	SPI_ConfigureCs(axis, board);
    SPI_setCs();
	
	//Send request to write status register
	SPI_master_write(EEPROM_WRSR);
	//Send data to write
	SPI_master_write(data);
	
	SPI_resetAllCs();
	
	while(EEPROM_read_status(axis, board) & EEPROM_RDY);
}
//******************************************************************************
//! @fn void EEPROM_write_enable (sensor_axis_e axis, sensor_board board)
//!
//! @description
//! writes data into memory 
//!
//! @param    axis     Axis
//!           board    Board
//!
//! @return   None
//!
//! @calls    EEPROM_read_status
//!           SPI_master_write 
//!           SPI_resetAllCs  
//!           SPI_setDec 
//!           SPI_setCs 
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
void EEPROM_write_enable (sensor_axis_e axis, sensor_board_e board)
{
	
	while(EEPROM_read_status(axis, board) & EEPROM_RDY);
	
	SPI_setDec(chip_EEPROM);
	SPI_ConfigureCs(axis, board);
    SPI_setCs();
	
	SPI_master_write(EEPROM_WREN);
	
	SPI_resetAllCs();
}
//******************************************************************************
//! @fn void EEPROM_write_data (sensor_axis_e axis, sensor_board_e board, uint16_t address, uint8_t data)
//!
//! @description
//! writes data into specific address into memory 
//!
//! @param    axis     Axis
//!           board    Board
//!           address  Address
//!           data     Data to write
//!
//! @return   None
//!
//! @calls    EEPROM_read_status
//!           SPI_master_write 
//!           SPI_resetAllCs  
//!           SPI_setDec 
//!           SPI_setCs 
//!           EEPROM_write_enable
//!           delay_ms
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
void EEPROM_write_data (sensor_axis_e axis, sensor_board_e board, uint16_t address, uint8_t data)
{
	
	do{
		EEPROM_write_enable(axis, board);
	}
	while((EEPROM_read_status(axis, board) & EEPROM_WEN_MASK) != EEPROM_WEN);
	
	SPI_setDec(chip_EEPROM);
	SPI_ConfigureCs(axis, board);
    SPI_setCs();
	
	// write WRITE instruction
	SPI_master_write(EEPROM_WRITE);
	// write first half of address
	SPI_master_write((address >> 8) & 0xFF);
	// write second half of address
	SPI_master_write(address & 0xFF);
	// write data
	SPI_master_write(data);
	
	SPI_resetAllCs();
	
	delay_ms(2);
	
	while(EEPROM_read_status(axis, board) & EEPROM_RDY);
}
//******************************************************************************
//! @fn uint8_t EEPROM_read_data (sensor_axis_e axis, sensor_board_e board, uint16_t address)
//!
//! @description
//! reads data from specific address.
//!
//! @param    axis     Axis
//!           board    Board
//!           address  Address
//!
//! @return   Data from specific address
//!
//! @calls    EEPROM_read_status
//!           SPI_master_write 
//!           SPI_resetAllCs  
//!           SPI_setDec 
//!           SPI_setCs 
//!           SPI_master_read
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
uint8_t EEPROM_read_data (sensor_axis_e axis, sensor_board_e board, uint16_t address)
{
	#ifdef MAINBOARD54
	uint32_t timeoutCounter = 0;
	while(EEPROM_read_status(axis, board) & EEPROM_RDY){
		timeoutCounter++;
		if(timeoutCounter > EEPROM_RESPONSE_ATTEMPTS){
			return 0;
		}
	}
	#else
	while(EEPROM_read_status(axis, board) & EEPROM_RDY);
	#endif
	
	SPI_setDec(chip_EEPROM);
	SPI_ConfigureCs(axis, board);
    SPI_setCs();
	
	// write READ instruction
	SPI_master_write(EEPROM_READ);
	// write first half of address
	//uint16_t temp = address;
	SPI_master_write((address >> 8) & 0xFF);
	// write second half of address
	SPI_master_write(address & 0xFF);
	// write dummy data to generate clock and receive required data
	SPI_master_write(0);
	
	SPI_resetAllCs();
	
	// read received data
	return (uint8_t)SPI_master_read();
}

//******************************************************************************
//! @fn void EEPROM_init_spi (void)
//!
//! @description
//! Initializes SPI periphery to the mode needed for EEPROM.
//!
//! @param    N/A
//!
//! @return   N/A
//!
//! @calls    SPI_master_init
//!
//! @req
//!
//! @example
//!
//! @code
//!
//! @endcode
//******************************************************************************
void EEPROM_init_spi(void)
{
    // Master SPI initialization 2 MHz is usable for EEPROM
    SPI_master_init(EEPROM_SPI_FREQ_HZ, SPI_POL_0, SPI_PHA_0, SPI_8_BIT, 0);
}