/*****************************************************************************/
#include <MyType.h>
#include "spi.h"
/*****************************************************************************/

#define SPI_PRESCALE_MIN  8


/* SPI0 (Serial Peripheral Interface 0) */
#define S0SPCR         (*((volatile unsigned char *) 0xE0020000))
#define S0SPSR         (*((volatile unsigned char *) 0xE0020004))
#define S0SPDR         (*((volatile unsigned char *) 0xE0020008))
#define S0SPCCR        (*((volatile unsigned char *) 0xE002000C))
#define S0SPTCR        (*((volatile unsigned char *) 0xE0020010))
#define S0SPTSR        (*((volatile unsigned char *) 0xE0020014))
#define S0SPTOR        (*((volatile unsigned char *) 0xE0020018))
#define S0SPINT        (*((volatile unsigned char *) 0xE002001C))

/* General Purpose Input/Output (GPIO) */
#define IOPIN0         (*((volatile unsigned long *) 0xE0028000))
#define IOSET0         (*((volatile unsigned long *) 0xE0028004))
#define IODIR0         (*((volatile unsigned long *) 0xE0028008))
#define IOCLR0         (*((volatile unsigned long *) 0xE002800C))
#define IOPIN1         (*((volatile unsigned long *) 0xE0028010))
#define IOSET1         (*((volatile unsigned long *) 0xE0028014))
#define IODIR1         (*((volatile unsigned long *) 0xE0028018))
#define IOCLR1         (*((volatile unsigned long *) 0xE002801C))

/* Pin Connect Block */
#define PINSEL0        (*((volatile unsigned long *) 0xE002C000))
#define PINSEL1        (*((volatile unsigned long *) 0xE002C004))
#define PINSEL2        (*((volatile unsigned long *) 0xE002C014))


// SP0SPCR  Bit-Definitions
#define CPHA    3
#define CPOL    4
#define MSTR    5
// SP0SPSR  Bit-Definitions
#define SPIF	7

#define SPI_IODIR      IODIR0
#define SPI_SCK_PIN    4		/* Clock       P0.4  out */
#define SPI_MISO_PIN   5		/* from Card   P0.5  in  */
#define SPI_MOSI_PIN   6		/* to Card     P0.6  out */
#define SPI_SS_PIN	   7		/* Card-Select P0.7 - GPIO out */

#define SPI_PINSEL     PINSEL0
#define SPI_SCK_FUNCBIT   8
#define SPI_MISO_FUNCBIT  10
#define SPI_MOSI_FUNCBIT  12
#define SPI_SS_FUNCBIT    44

#define SPI_PRESCALE_REG  S0SPCCR

#define SELECT_CARD()   IOCLR0 = (1 << SPI_SS_PIN)
#define UNSELECT_CARD() IOSET0 = (1 << SPI_SS_PIN)


/*****************************************************************************/

void SPISetSpeed(U8 speed)
{
	speed &= 0xFE;
	if (speed < SPI_PRESCALE_MIN) {
		speed = SPI_PRESCALE_MIN;
	}
	SPI_PRESCALE_REG = speed;
}


void SPIInit(void)
{
	// setup GPIO
	SPI_IODIR |= (1 << SPI_SCK_PIN) | (1 << SPI_MOSI_PIN) | (1 << SPI_SS_PIN);
	SPI_IODIR &= ~(1 << SPI_MISO_PIN);

	// reset Pin-Functions  
	SPI_PINSEL &= ~((3 << SPI_SCK_FUNCBIT) | (3 << SPI_MISO_FUNCBIT) | (3 << SPI_MOSI_FUNCBIT));
	SPI_PINSEL |= ((1 << SPI_SCK_FUNCBIT) | (1 << SPI_MISO_FUNCBIT) | (1 << SPI_MOSI_FUNCBIT));

	PINSEL1 &= ~(3 << (SPI_SS_FUNCBIT - 32));
	PINSEL1 |= (0 << (SPI_SS_FUNCBIT - 32));

	// set Chip-Select high - unselect card
	UNSELECT_CARD();

	// enable SPI-Master
	S0SPCR = (1 << MSTR) | (0 << CPOL);	// TODO: check CPOL

	SPISetSpeed(0);
}

/*****************************************************************************/

/*****************************************************************************/

U8 SPISend(U8 outgoing)
{
	U8 incoming;

	S0SPDR = outgoing;
	while (!(S0SPSR & (1 << SPIF)));
	incoming = S0SPDR;

	return incoming;
}


/**************************************************
Function: SPI_Write_Buf();

Description:
  Writes contents of buffer '*pBuf' to nRF24L01
  Typically used to write TX payload, Rx/Tx address */
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
	unsigned char status,byte_ctr;
	SELECT_CARD();                   		// Set nRF24L01_CSN low, init SPI tranaction
	status = SPISend(reg);    					// Select register to write to and read status byte
  	for(byte_ctr=0; byte_ctr<bytes; byte_ctr++) // then write all byte in buffer(*pBuf)
    	status = SPISend(*pBuf++);            
	UNSELECT_CARD(); 								// Set nRF24L01_CSN high again
  	return(status);          					// return nRF24L01 status byte
}

/**************************************************
Function: SPI_RW_Reg();

Description:
  Writes value 'value' to register 'reg' */
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
	unsigned char status;
	SELECT_CARD();
	status = SPISend(reg);      // select register
  	SPISend(value);             // ..and write value to it..
	UNSELECT_CARD();
  	return(status);            // return nRF24L01 status byte
}

/**************************************************
Function: SPI_Read();

Description:
  Read one byte from nRF24L01 register, 'reg'  */
/**************************************************/
unsigned char SPI_Read(unsigned char reg)
{
	unsigned char reg_val;
	SELECT_CARD();
  	SPISend(reg);            // Select register to read from..
  	reg_val = SPISend(0);    // ..then read registervalue
	UNSELECT_CARD();
  	return(reg_val);        // return register value
}

/**************************************************
Function: SPI_Read_Buf();

Description:
  Reads 'bytes' #of bytes from register 'reg'
  Typically used to read RX payload, Rx/Tx address */
/**************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
	unsigned char status,byte_ctr;
	SELECT_CARD();
  	status = SPISend(reg);       		// Select register to write to and read status byte
	for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
    	pBuf[byte_ctr] = SPISend(0);    // Perform SPISend to read byte from nRF24L01
	UNSELECT_CARD();
  	return(status);                    // return nRF24L01 status byte
}
