/* 
* classSpi.h
*
* Created: 21/05/2018 9:23:49
* Author: Ledo
*/


#ifndef __CLASSSPI_H__
#define __CLASSSPI_H__

#include <sam4e.h>
#include "tipos.h"
#include "classPio.h"
#ifndef SPI_WPMR_WPKEY_PASSWD
#define SPI_WPMR_WPKEY_PASSWD SPI_WPMR_WPKEY((uint32_t) 0x535049)
#endif

/** Time-out value (number of attempts). */
#define SPI_TIMEOUT       15000

#define div_ceil(a, b)      (((a) + (b) - 1) / (b))

/** Clock phase. */
#define SPI_CPHA    (1 << 0)
/** Clock polarity. */
#define SPI_CPOL    (1 << 1)
/** SPI mode definition. */
#define SPI_MODE_0  0
#define SPI_MODE_1  (SPI_CPHA)
#define SPI_MODE_2  (SPI_CPOL)
#define SPI_MODE_3  (SPI_CPOL | SPI_CPHA)

/** Status codes used by the SPI driver. */
typedef enum
{
	SPI_ERROR = -1,
	SPI_OK = 0,
	SPI_ERROR_TIMEOUT = 1,
	SPI_ERROR_ARGUMENT,
	SPI_ERROR_OVERRUN,
	SPI_ERROR_MODE_FAULT,
	SPI_ERROR_OVERRUN_AND_MODE_FAULT
} spi_status_t;

/** SPI Chip Select behavior modes while transferring. */
typedef enum spi_cs_behavior {
	/** CS does not rise until a new transfer is requested on different chip select. */
	SPI_CS_KEEP_LOW = SPI_CSR_CSAAT,
	/** CS rises if there is no more data to transfer. */
	SPI_CS_RISE_NO_TX = 0,
	/** CS is de-asserted systematically during a time DLYBCS. */
	SPI_CS_RISE_FORCED = SPI_CSR_CSNAAT
} spi_cs_behavior_t;

/**
 * \brief Generate Peripheral Chip Select Value from Chip Select ID
 * \note When chip select n is working, PCS bit n is set to low level.
 *
 * \param chip_sel_id The chip select number used
 */
#define spi_get_pcs(chip_sel_id) ((~(1u<<(chip_sel_id)))&0xF)

extern classPio Puerto;
class classSpi
{
//variables
public:
protected:
private:

//functions
public:
	classSpi();
	~classSpi();
	void spi_reset(Spi *p_spi);
	void spi_enable(Spi *p_spi);
	void spi_disable(Spi *p_spi);
	void spi_set_lastxfer(Spi *p_spi);
	void spi_set_master_mode(Spi *p_spi);
	void spi_set_slave_mode(Spi *p_spi);
	uint32_t spi_get_mode(Spi *p_spi);
	void spi_set_variable_peripheral_select(Spi *p_spi);
	void spi_set_fixed_peripheral_select(Spi *p_spi);
	uint32_t spi_get_peripheral_select_mode(Spi *p_spi);
	void spi_enable_peripheral_select_decode(Spi *p_spi);
	void spi_disable_peripheral_select_decode(Spi *p_spi);
	uint32_t spi_get_peripheral_select_decode_setting(Spi *p_spi);
	void spi_enable_mode_fault_detect(Spi *p_spi);
	void spi_disable_mode_fault_detect(Spi *p_spi);
	uint32_t spi_get_mode_fault_detect_setting(Spi *p_spi);
	void spi_enable_tx_on_rx_empty(Spi *p_spi);
	void spi_disable_tx_on_rx_empty(Spi *p_spi);
	uint32_t spi_get_tx_on_rx_empty_setting(Spi *p_spi);
	void spi_enable_loopback(Spi *p_spi);
	void spi_disable_loopback(Spi *p_spi);
	void spi_enable_clock(Spi *p_spi);
	void spi_disable_clock(Spi *p_spi);
	void spi_set_peripheral_chip_select_value(Spi *p_spi, uint32_t ul_value);
	void spi_set_delay_between_chip_select(Spi *p_spi, uint32_t ul_delay);
	spi_status_t spi_read(Spi *p_spi, uint16_t *us_data, uint8_t *p_pcs);
	spi_status_t spi_write(Spi *p_spi, uint16_t us_data, uint8_t uc_pcs,
	uint8_t uc_last);
	void spi_set_clock_polarity(Spi *p_spi, uint32_t ul_pcs_ch,
	uint32_t ul_polarity);
	void spi_set_clock_phase(Spi *p_spi, uint32_t ul_pcs_ch, uint32_t ul_phase);
	void spi_configure_cs_behavior(Spi *p_spi, uint32_t ul_pcs_ch,
	uint32_t ul_cs_behavior);
	void spi_set_bits_per_transfer(Spi *p_spi, uint32_t ul_pcs_ch,
	uint32_t ul_bits);
	int16_t spi_calc_baudrate_div(const uint32_t baudrate, uint32_t mck);
	int16_t spi_set_baudrate_div(Spi *p_spi, uint32_t ul_pcs_ch,
	uint8_t uc_baudrate_divider);
	void spi_set_transfer_delay(Spi *p_spi, uint32_t ul_pcs_ch,
	uint8_t uc_dlybs, uint8_t uc_dlybct);
	void spi_set_writeprotect(Spi *p_spi, uint32_t ul_enable);
	uint32_t spi_get_writeprotect_status(Spi *p_spi);
	uint32_t spi_read_status(Spi *p_spi);
	uint32_t spi_is_enabled(Spi *p_spi);
	void spi_put(Spi *p_spi, uint16_t data);
	uint16_t spi_get(Spi *p_spi);
	uint32_t spi_is_tx_empty(Spi *p_spi);
	uint32_t spi_is_tx_ready(Spi *p_spi);
	uint32_t spi_is_rx_full(Spi *p_spi);
	uint32_t spi_is_rx_ready(Spi *p_spi);
	void spi_enable_interrupt(Spi *p_spi, uint32_t ul_sources);
	void spi_disable_interrupt(Spi *p_spi, uint32_t ul_sources);
	uint32_t spi_read_interrupt_mask(Spi *p_spi);
	void spi_master_init(Spi *p_spi, uint32_t freq);
	uint8_t spi_transfer(uint8_t byte);
protected:
private:
	classSpi( const classSpi &c );
	classSpi& operator=( const classSpi &c );

}; //classSpi

#endif //__CLASSSPI_H__
