/*! ----------------------------------------------------------------------------
 * @file	spi.c
 * @brief	SPI access function implementations
 * @version 5.0
 * @date 18/05/2017
 */
 
#include "spi.h"
#include "deca_device_api.h"
#include "nrf_delay.h"                  // NordicSemiconductor::nRF_Drivers:nrf_delay
#include "nrf_log.h"
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"                   // NordicSemiconductor::nRF_Drivers:nrf_gpio
#include "app_util_platform.h"
#include "boards.h"
#include "app_error.h"    

#define SPI_INSTANCE  0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */


/**@brief Low level abstract function to open and initialise access to the SPI device.
 *
 * @return 	returns 0 for success, or -1 for error
 */
int SPI_init()
{
	nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
	spi_config.frequency = 	NRF_DRV_SPI_FREQ_1M;
	spi_config.mode      = 	NRF_DRV_SPI_MODE_0;
	spi_config.bit_order = 	NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
	//config.ss_pin    =	SPIM0_SS_PIN;
	spi_config.miso_pin  =	SPIM0_MISO_PIN;
	spi_config.mosi_pin	 =	SPIM0_MOSI_PIN;
	spi_config.sck_pin	 =	SPIM0_SCK_PIN;
	spi_config.orc		 =	0x00;
	
    //spi_config.ss_pin = SPIM0_SS_PIN;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL));
	
	nrf_gpio_cfg_output	(SPIM0_SS_PIN);
	nrf_gpio_pin_write	(SPIM0_SS_PIN, 1); 

	return 0;

} 

/**@brief Low level abstract function to close the the SPI device.
 *
 * @return 	returns 0 for success, or -1 for error
 */
int SPI_Uninit(void)
{
	nrf_drv_spi_uninit(&spi);
	return 0;
} 


/**@brief Low level abstract function to write to the SPI
 *
 * @param[in] headerLength size of the header
 * @param[in] headerBuffer header content
 * @param[in] bodylength size of the data 
 * @param[in] bodyBuffer content of the data
 * @return 	returns 0 for success, or -1 for error
 */
int writetospi
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       bodylength,
    const uint8 *bodyBuffer
)
{
    //decaIrqStatus_t  stat ;
    //stat = decamutexon() ;
	
	// prepare TX buffer
	uint8_t txBuff[headerLength+bodylength];		
	for(uint8_t i=0;i<headerLength;i++)
	{
		txBuff[i] = headerBuffer[i];
	}
	for(uint8_t i=0;i<bodylength;i++)
	{
		txBuff[headerLength+i] = bodyBuffer[i];
	}	

	// Drive CS Low
	nrf_gpio_pin_write (SPIM0_SS_PIN, 0);
	
	// Send data
	nrf_drv_spi_transfer (&spi, txBuff, headerLength+bodylength, NULL, 0);
	
	// Drive CS High
	nrf_gpio_pin_write (SPIM0_SS_PIN, 1);
	
	//decamutexoff(stat) ;

    return 0;
}


/**@brief Low level abstract function to read from the SPI
 *
 * @param[in] headerLength size of the header
 * @param[in] headerBuffer header content
 * @param[in] bodylength size of the readdata 
 * @param[out] bodyBuffer content of the readdata
 * @return 	returns 0 for success, or -1 for error
 */
int readfromspi
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       readlength,
    uint8       *readBuffer
)
{

	//decaIrqStatus_t  stat ;
	//stat = decamutexon() ;
	
	uint8 rxBodyBuff[readlength+headerLength];
		
	// Drive CS Low
	nrf_gpio_pin_write (SPIM0_SS_PIN, 0);
	
	// Send data
	nrf_drv_spi_transfer (&spi, headerBuffer, headerLength, rxBodyBuff, readlength+headerLength);
		
	// Drive CS High
	nrf_gpio_pin_write (SPIM0_SS_PIN, 1);
	
	// get "read part" of rxBodyBuff
	for(uint8 i=0;i<readlength;i++)
	{
		readBuffer[i] = rxBodyBuff[headerLength+i];
	}	

	//decamutexoff(stat) ;
	
    return 0;
}


/**@brief Change SPI frequency
 *
 * @param[in] freq frequency
 */
static void SPI_ChangeRate(nrf_drv_spi_frequency_t freq)
{
	NRF_SPIM_Type * p_spim = spi.p_registers;
	nrf_spim_frequency_set (p_spim, (nrf_spim_frequency_t)freq);
}

/**@brief Set SPI rate to less than 3 MHz to properly perform DW1000 initialisation.
 *
 */
void SPI_SetLowRate (void)
{
    SPI_ChangeRate (NRF_DRV_SPI_FREQ_1M);
}

/**@brief Set SPI rate as close to 8 MHz as possible for optimum performances.
 *
 */
void SPI_SetHighRate (void)
{
    SPI_ChangeRate (NRF_DRV_SPI_FREQ_8M);
}

/**@brief Set SPI cs high
 *
 */
void SPI_SetCsHigh (void)
{
    nrf_gpio_pin_write (SPIM0_SS_PIN, 1);
}

/**@brief Set SPI cs low
 *
 */
void SPI_SetCsLow (void)
{
    nrf_gpio_pin_write (SPIM0_SS_PIN, 0);
}
