/*================================================================================================
 
 spi.c								SiWiCom copyright 2006       		   		v1.0 (2006-05-11)
 
 Name: Joakim Nilsson				E-mail: mail@jopin.se
 Name: Christoffer Martinsson		E-mail: cm@cmtec.se

 Description: Routines for SPI interface. Basic design by CM. Modifyed and extended by JN 
			  for project SiWiCom 2006
 
 SPI configuration is done by hardware.h witch must contain definitions for:
 (X=letter i.e PORTX=PORTB, n=number i.e PXn=PB4)		

		SPI_PORT	PORTX 	(Example: #define SPI_PORT	PORTB)		// PORTB as SPI-port
 		SPI_DDR		DDRX	(Example: #define SPI_DDR	DDRB) 		// DDRB as direction for SPI pindirection
 		
		MOSI		PXn 	(Example: #define MOSI	PB3)			// Master Out - Slave In	
		MISO		PXn		(Example: #define MISO	PB4)			// Master In - Slave Out
		SCK			PXn		(Example: #define SCK	PB5				// Serial Clock
		
		Processor as SPI-master or SPI-slave, example:
		#define _SPI_MASTER_
		//#define _SPI_SLAVE_

		If processor is defined as _SPI_MASTER_, Chip select port(s) (at least one, max 8) must be asigned as: 
		#define SPI_CS0_PORT	PORTX
					.
					.
					.
		#define SPI_CS7_PORT	PORTX


		and SPI direction for the above asigned port(s) as:
		#define SPI_CS0_DDR		DDRX
					.
					.
					.
		#define SPI_CS7_DDR		DDRX
		
		and SPI pin(s) used for chip select as:
			
		#define SPI_CS0			PXn
					.
					.
					.
		#define SPI_CS7			PXn
	
================================================================================================*/
#include "hardware.h"
#include <inttypes.h>
#include <avr/io.h>
#include "spi.h"

/*================================================================================================
 Functions
================================================================================================*/
/*================================================================================================
 spiWrite
 
 Description: Write data to SPI.

 Input: data to send
 Return: -
------------------------------------------------------------------------------------------------*/
void spiWrite(uint8_t data)
{
		SPDR = data;
		while(!(SPSR & (1<<SPIF)));
}

/*================================================================================================
 spiRead
 
 Description: Read data from SPI buffer.

 Input: -
 Return: SPI-value
------------------------------------------------------------------------------------------------*/
uint8_t spiRead(void)
{
		return SPDR;		
}
/*================================================================================================
 spiSetHighSpeed
 
 Description: Set datatrasfer to fc/4.

 Input: -
 Return: -
------------------------------------------------------------------------------------------------*/
void spiSetHighSpeed(void)
{
		SPCR &= ~(1<<SPR0);		
		SPCR &= ~(1<<SPR1);		
}
/*================================================================================================
 spiSetLowSpeed
 
 Description: Set datatrasfer to fc/64.

 Input: -
 Return: -
------------------------------------------------------------------------------------------------*/
void spiSetLowSpeed(void)
{
		SPCR &= ~(1<<SPR0);		
		SPCR |= (1<<SPR1);			
}

/*================================================================================================
 spiInit
 
 Description: Init SPI interface as master or slave depending on the "hardware.h" configuration.

 Input: -
 Return: -
------------------------------------------------------------------------------------------------*/
void spiInit(void)
{
#ifdef _SPI_MASTER_								//If defined as master in hardware.h
	
	#ifdef SPI_CS0
		SPI_CS0_DDR |= (1<<SPI_CS0);
		SPI_CS0_PORT |= (1<<SPI_CS0);
	#endif

	#ifdef SPI_CS1
		SPI_CS1_DDR |=(1<<SPI_CS1);
		SPI_CS1_PORT |= (1<<SPI_CS1);
	#endif
	
	#ifdef SPI_CS2
		SPI_CS2_DDR |=(1<<SPI_CS2);
		SPI_CS2_PORT |= (1<<SPI_CS2);
	#endif
	
	#ifdef SPI_CS3
		SPI_CS3_DDR |=(1<<SPI_CS3);
		SPI_CS3_PORT |= (1<<SPI_CS3);
	#endif

	#ifdef SPI_CS4
		SPI_CS4_DDR |=(1<<SPI_CS4);
		SPI_CS4_PORT |= (1<<SPI_CS4);
	#endif

	#ifdef SPI_CS5
		SPI_CS5_DDR |=(1<<SPI_CS5);
		SPI_CS5_PORT |= (1<<SPI_CS5);
	#endif

	#ifdef SPI_CS6
		SPI_CS6_DDR |=(1<<SPI_CS6);
		SPI_CS6_PORT |= (1<<SPI_CS6);
	#endif

	#ifdef SPI_CS7
		SPI_CS7_DDR |=(1<<SPI_CS7);
		SPI_CS7_PORT |= (1<<SPI_CS7);
	#endif

	SPI_DDR |= (1<<MOSI)|(1<<SCK);				// MOSI and SCLK as output
	SPI_PORT |= (1<<MISO)		;				// Pullup on SO (slave out)
	SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPI2X);		// SPI enable, SPI-Master, SC = fc/2 
	
#elif _SPI_SLAVE_									//If defined as slave in hardware.h
	
	SPI_DDR |= (1<<MISO);							// MOSI and SCLK as output
	SPI_PORT |=(1<<SS);								// Pull-Up on SS
	SPCR |= (1<<SPE);								// SPI enable, SPI-Slave

#endif							
}

/*================================================================================================
 spiChipSelect
 
 Description: Select device for communication via SPI. Protects chipselect on two devices at the 
 same time and secure that chosen chipselect is an initialised legal channel.

 Input: uint8_t (The number of the desired chipselect. (Between 0 and 7) )
 Return: -
------------------------------------------------------------------------------------------------*/
void spiChipSelect(uint8_t chipselect){

/*All chipselectports disabled (high state)*/
	#ifdef SPI_CS0
		SPI_CS0_PORT |=(1<<SPI_CS0);		
	#endif

	#ifdef SPI_CS1
		SPI_CS1_PORT |=(1<<SPI_CS1);		
	#endif
	
	#ifdef SPI_CS2
		SPI_CS2_PORT |=(1<<SPI_CS2);		
	#endif

	#ifdef SPI_CS3
		SPI_CS3_PORT |=(1<<SPI_CS3);		
	#endif

	#ifdef SPI_CS4
		SPI_CS4_PORT |=(1<<SPI_CS4);	
	#endif

	#ifdef SPI_CS5
		SPI_CS5_PORT |=(1<<SPI_CS5);	
	#endif

	#ifdef SPI_CS6
		SPI_CS6_PORT |=(1<<SPI_CS6);		
	#endif

	#ifdef SPI_CS7
		SPI_CS7_PORT |=(1<<SPI_CS7);		
	#endif

/*Selected port as chipselect*/
	#ifdef SPI_CS0
		if(chipselect==0)
		SPI_CS0_PORT &=~(1<<SPI_CS0);		
	#endif

	#ifdef SPI_CS1
		if(chipselect==1)
		SPI_CS1_PORT &=~(1<<SPI_CS1);		
	#endif
	
	#ifdef SPI_CS2
		if(chipselect==2)
		SPI_CS2_PORT &=~(1<<SPI_CS2);		
	#endif

	#ifdef SPI_CS3
		if(chipselect==3)
		SPI_CS3_PORT &=~(1<<SPI_CS3);		
	#endif

	#ifdef SPI_CS4
		if(chipselect==4)
		SPI_CS4_PORT &=~(1<<SPI_CS4);		
	#endif

	#ifdef SPI_CS5
		if(chipselect==5)
		SPI_CS5_PORT &=~(1<<SPI_CS5);		
	#endif

	#ifdef SPI_CS6
		if(chipselect==6)
		SPI_CS6_PORT &=~(1<<SPI_CS6);		
	#endif

	#ifdef SPI_CS7
		if(chipselect==7)
		SPI_CS7_PORT &=~(1<<SPI_CS7);		
	#endif
}

/*================================================================================================
spiChipDeSelect
 
 Description: Deselect all SPI channels
 Input: -
 Return: -
------------------------------------------------------------------------------------------------*/
void spiChipDeSelect(void)
{
/*All chipselectports disabled (high state)*/
	#ifdef SPI_CS0
		SPI_CS0_PORT |=(1<<SPI_CS0);		
	#endif

	#ifdef SPI_CS1
		SPI_CS1_PORT |=(1<<SPI_CS1);		
	#endif
	
	#ifdef SPI_CS2
		SPI_CS2_PORT |=(1<<SPI_CS2);		
	#endif

	#ifdef SPI_CS3
		SPI_CS3_PORT |=(1<<SPI_CS3);		
	#endif

	#ifdef SPI_CS4
		SPI_CS4_PORT |=(1<<SPI_CS4);	
	#endif

	#ifdef SPI_CS5
		SPI_CS5_PORT |=(1<<SPI_CS5);	
	#endif

	#ifdef SPI_CS6
		SPI_CS6_PORT |=(1<<SPI_CS6);		
	#endif

	#ifdef SPI_CS7
		SPI_CS7_PORT |=(1<<SPI_CS7);		
	#endif

}
/*================================================================================================
 End
================================================================================================*/

