#include "ustv_spi.h"
//#include "spi.h"
#include <p33FJ64MC804.h>
#include <delay.h>
#include <Libpic30.h>

//#define USE_DMA_FOR_SPI

unsigned char results[50];

/****************************************************************************************************/
// SPI1 configuration et fonctions
/****************************************************************************************************/
void initSPI1(void)
{
    /* Holds the information about SPI configuartion */

    /* The following code shows the SPI register configuration for Master mode */

    IFS0bits.SPI1IF = 0;	// Clear the Interrupt Flag
    IEC0bits.SPI1IE = 0;	// Disable the Interrupt

    // SPI1CON1 Register Settings
    SPI1CON1bits.DISSCK = 0;// Internal Serial Clock is Enabled
    SPI1CON1bits.DISSDO = 0;// SDOx pin is controlled by the module
    SPI1CON1bits.MODE16 = 0;// 1 : Communication is word-wide (16 bits)
                                                    // 0 : Communication is char-wide (8 bits)
    SPI1CON1bits.SMP = 0;	// Input data is sampled at the middle of data output time
    SPI1CON1bits.CKE = 1;	// Serial output data changes on transition from active clock to idle clock state
    SPI1CON1bits.CKP = 0;	// Idle state for clock is a low level; active state is a high level
    SPI1CON1bits.MSTEN = 1;	// Master mode Enabled
    SPI1CON1bits.SPRE = 0b111;	// 0b111 : 1:1
                                    // 0b110 : 2:1
                                    // 0b101 :
    SPI1CON1bits.PPRE = 0b01;	// 0b00 : 64:1
                                    // 0b01 : 16:1
                                    // 0b10 : 4:1
                                    // 0b11 : 1:1

    // SPI1CON2 Register Settings
    SPI1CON2bits.FRMEN = 0;	// 0 : framing disabled
                                                    // 1 : framing enabled
    SPI1CON2bits.SPIFSD = 0;// 0 : Frame sync pulse output Master
                                                    // 1 : Frame sync pulse input Slave
    SPI1CON2bits.FRMPOL = 0;// 0 : sync pulse active low
                                                    // 1 : sync pulse active high
    SPI1CON2bits.FRMPOL = 0;// 1 : sync pulse coincides first bit
                                                    // 0 : sync pulse precedes first bit

    SPI1STATbits.SPIEN = 1;	// Enable SPI module


    #ifdef USE_DMA_FOR_SPI
        // Force First word after Enabling SPI
        DMA0REQbits.FORCE=1;
        while(DMA0REQbits.FORCE==1);
    #else
        SPI1BUF = 0x0000;       // Write data to be transmitted
        // Interrupt Controller Settings
        IFS0bits.SPI1IF = 0; 	// Clear the Interrupt Flag
        IEC0bits.SPI1IE = 1;	// Enable the Interrupt **
        while ( SPI1STATbits.SPITBF ) ;
    #endif

    #ifdef USE_RFID
        SS_RFID=1;
    #endif
    #ifdef USE_SRAM
        SS_SRAM=1;
    #endif
    #ifdef USE_ECG
        SS_ECG=1;
    #endif
#ifdef USE_OLED
        SS_OLED=1;
#endif
 
}   

void setSPI1_CKP_CKE(int ckp,int cke)
{	
    SPI1STATbits.SPIEN = 0;	// Disable SPI module
    SPI1CON1bits.CKE = cke;
    SPI1CON1bits.CKP = ckp;
    SPI1STATbits.SPIEN = 1;	// Enable SPI module    
    while ( SPI1STATbits.SPITBF ) ;
}


void invertSPI1_CKP(void)
{	
    SPI1STATbits.SPIEN = 0;	// Disable SPI module
    SPI1CON1bits.CKP = !SPI1CON1bits.CKP;
    SPI1STATbits.SPIEN = 1;	// Enable SPI module    
    while ( SPI1STATbits.SPITBF ) ;
}

void setHighSpeedClk(unsigned char yn,unsigned char device)
{
    if(device == SRAM || device != OLED)
    {
        if(yn)
        {
            SPI1STATbits.SPIEN = 0;	// Disable SPI module
            //Reglage de l'horloge spi a 4.096Mhz
            SPI1CON1bits.SPRE = 0b111;
            SPI1CON1bits.PPRE = 0b10;
            SPI1STATbits.SPIEN = 1;	// Enable SPI module
        }
        else
        {
            SPI1STATbits.SPIEN = 0;	// Disable SPI module
            //Reglage de l'horloge spi a 1Mhz
            SPI1CON1bits.SPRE = 0b111;
            SPI1CON1bits.PPRE = 0b01;
            SPI1STATbits.SPIEN = 1;	// Enable SPI module
        }
    }
}

void invertSPI1_CKE(void)
{	
    SPI1STATbits.SPIEN = 0;	// Disable SPI module
    SPI1CON1bits.CKE = !SPI1CON1bits.CKE;
    SPI1STATbits.SPIEN = 1;	// Enable SPI module    
    while ( SPI1STATbits.SPITBF ) ;
}

/*-----------------------------------------------------------------------*/
/* Set CipSelect (Platform dependent)                  */
/*-----------------------------------------------------------------------*/
void ChipSelectSpi1SetValue( unsigned int value, unsigned int device)
{
    switch(device)
    {
        case RFID:
                SS_RFID = value;
                break;
        case SRAM:
                SS_SRAM = value;
                break;
        #ifdef USE_ECG
        case ECG:
                SS_ECG = value;
                break;
        #endif
        case OLED:
                SS_OLED = value;
                break;
//		case GYRO:
//			SS_GYRO = value;
//			break;                
        default:
                break;
    }
}

/*-----------------------------------------------------------------------*/
/* Transmit a byte via SPI  (Platform dependent)                  */
/*-----------------------------------------------------------------------*/
void WriteSingleCommandSpi1( unsigned char command, unsigned char device)
{	   
    unsigned char commands[1];
    commands[0]=command;
    WriteMultipleCommandMultipleReadSpi1(commands, 1, results, 0, device, 0);
}


/*-----------------------------------------------------------------------*/
/* Transmit a byte via SPI  (Platform dependent)                  */
/*-----------------------------------------------------------------------*/
void WriteSingleCommandPlusNOPSpi1( unsigned char command, unsigned char device )
{	    
    unsigned char commands[2];
    commands[0]=command;
    commands[1]=0x00;
    WriteMultipleCommandMultipleReadSpi1(commands, 2, results, 0, device, 0);
}

/*-----------------------------------------------------------------------*/
/* Transmit multiple bytes via SPI  (Platform dependent)                  */
/*-----------------------------------------------------------------------*/
void WriteMultipleCommandSpi1( unsigned char commands[], int nbCommands, unsigned char device )
{	
    unsigned char results[1];
    WriteMultipleCommandMultipleReadSpi1(commands, nbCommands, results, 0, device, 0);
}

/*-----------------------------------------------------------------------*/
/* Transmit single byte via SPI  (Platform dependent)                  */
/*-----------------------------------------------------------------------*/
void WriteSingleCommandMultipleReadSpi1(unsigned char command, unsigned char results[], int nbResults, unsigned char device, unsigned char invertReadCKE )
{	    
    unsigned char commands[1];
    commands[0]=command;
    WriteMultipleCommandMultipleReadSpi1(commands, 1, results, nbResults, device, invertReadCKE);
}


/*-----------------------------------------------------------------------*/
/* Transmit multiple bytes, read multiple bytes via SPI (Platform dependent) */
/* Inversion possible de la polarité de CKE entre le write et le read    */
/*-----------------------------------------------------------------------*/
void WriteMultipleCommandMultipleReadSpi1(unsigned char commands[], int nbCommands, unsigned char results[], int nbResults, unsigned char device, unsigned char invertReadCKE )
{		
    int i =0;
    IEC1bits.INT2IE = 0;		//active les interruptions sur INT2 (MMA8453)
    IEC1bits.INT1IE=0;                  //active les interruption sur INT1 (MAG)
    IEC0bits.INT0IE = 0;		//desactive les interruptions sur INT20 (ecg)
    RTCCResetInt();
    IEC2bits.DMA3IE = 0; 						// Enable DMA interrupt
    IEC1bits.DMA2IE = 0; 						// Enable DMA interrupt
    IEC0bits.DMA1IE = 0; 						// Enable DMA interrupt
    IEC0bits.T3IE = 0; // Enable Timer3 interrupt

    //on déclenche le SS
    ChipSelectSpi1SetValue(0, device);
    //On passe l'horloge spi a 4.096MHz (en fonction du perif)
    setHighSpeedClk(1,device);

    //On envoie les commandes
    volatile unsigned char dummy;
    for (i=0; i<nbCommands; i++)
    {
            SPI1BUF=(unsigned int)commands[i];
            while ( SPI1STATbits.SPITBF ) ;
            dummy = SPI1BUF;
            while ( !SPI1STATbits.SPIRBF ) ;
            dummy = SPI1BUF;
    }

    //on permute la valeur de CKE si le flag d'inversion de CKE est active
    if(invertReadCKE)
    invertSPI1_CKE();

    for (i=0; i<nbResults; i++)
    {
            //On envoie un signal nul
            SPI1BUF=0x0000;
            //Le passage a 0 de TBF indique la fin de transmission, on attend qu'il revienne à 0
            while ( SPI1STATbits.SPITBF ) ;
            dummy = SPI1BUF;
            //Le passage à 1 de RBF indique que les données reçues sont dispo dans le buffer, on attend qu'il passe à 1
            while ( !SPI1STATbits.SPIRBF ) ;
            results[i] = SPI1BUF;
    }

    //on permute la valeur de CKE si le flag d'inversion de CKE est active
    if(invertReadCKE)
    invertSPI1_CKE();

    //on termine le SS
    ChipSelectSpi1SetValue(1, device);
    //On remet l'horloge spi a 1MHz
    setHighSpeedClk(0,device);

    #ifdef USE_MMA8453
            IEC1bits.INT2IE = 1;		//active les interruptions sur INT2 (MMA8453)
    #endif
    #ifdef USE_RTCC
             RTCCSetInt();
    #endif
    #ifdef USE_ECG
            IEC0bits.INT0IE = 1;		//desactive les interruptions sur INT20 (ecg)
    #endif
    #ifdef USE_MAG3110
            IEC1bits.INT1IE=1;		//active les interruption sur INT1 (MAG)
    #endif
    IEC2bits.DMA3IE = 1; 						// Enable DMA interrupt
    IEC1bits.DMA2IE = 1; 						// Enable DMA interrupt
    IEC0bits.DMA1IE = 1; 						// Enable DMA interrupt
    IEC0bits.T3IE = 1; // Enable Timer3 interrupt
}

#ifdef USE_CC2530_MT
#ifdef CC2530_SPI_MODE

/*-----------------------------------------------------------------------*/
/*                  Command Synchronous Request sur le CC2530            */
/*                                                                       */
/*-----------------------------------------------------------------------*/

void CC2530SREQ(unsigned char commands[], int nbCommands, unsigned char results[], unsigned char nbResults[], unsigned char device, unsigned char invertReadCKE )
{
	int i=0;

        //On désactive les interruptions pour que le front descendant provoqué ne soit pas comptabilisé dans les IT
        CC2530DisableInterrupt();

        //on déclenche le SS
        CC2530_MRDY = 0;
	ChipSelectSpi1SetValue(0, device);

        //On attend que le CC2530 soit prêt
        unsigned char Srdy = CC2530_SRDY;
        while(Srdy == 1)
        {
            Srdy = CC2530_SRDY;
        }
        
	//On envoie les commandes
	volatile unsigned char dummy;
	for (i=0; i<nbCommands; i++)
	{
		SPI1BUF=(unsigned int)commands[i];
		while ( SPI1STATbits.SPITBF ) ;
		dummy = SPI1BUF;
		while ( !SPI1STATbits.SPIRBF ) ;
		dummy = SPI1BUF;
	}

	//on permute la valeur de CKE si le flag d'inversion de CKE est active
	if(invertReadCKE)
    	invertSPI1_CKE();
        
        //On attend l'arrivée du SRDY en provenance du Zigbee
        Srdy = CC2530_SRDY;
        while(Srdy == 0)
        {
            Srdy = CC2530_SRDY;
        }


	//On récupère la length du message sur le premier byte lu
	SPI1BUF=0x0000;
        //Le passage a 0 de TBF indique la fin de transmission, on attend qu'il revienne à 0
        while ( SPI1STATbits.SPITBF ) ;
        dummy = SPI1BUF;
        //Le passage à 1 de RBF indique que les données reçues sont dispo dans le buffer, on attend qu'il passe à 1
        while ( !SPI1STATbits.SPIRBF ) ;
        nbResults[0] = SPI1BUF+2;
	for (i=0; i<nbResults[0]; i++)
	{
		//On envoie un signal nul
		SPI1BUF=0x0000;
		//Le passage a 0 de TBF indique la fin de transmission, on attend qu'il revienne à 0
		while ( SPI1STATbits.SPITBF ) ;
		dummy = SPI1BUF;
		//Le passage à 1 de RBF indique que les données reçues sont dispo dans le buffer, on attend qu'il passe à 1
		while ( !SPI1STATbits.SPIRBF ) ;
		results[i] = SPI1BUF;
	}

	//on permute la valeur de CKE si le flag d'inversion de CKE est active
	if(invertReadCKE)
    	invertSPI1_CKE();

        //on termine le SS
        CC2530_MRDY = 1;
	ChipSelectSpi1SetValue(1, device);

        //On réactive les interruptions pour que le front descendant provoqué ne soit pas comptabilisé dans les IT
        CC2530EnableInterrupt();
}

/*-----------------------------------------------------------------------*/
/*                  Command Synchronous Request sur le CC2530            */
/*                                                                       */
/*-----------------------------------------------------------------------*/

void CC2530AREQ(unsigned char commands[], int nbCommands, unsigned char device, unsigned char invertReadCKE )
{
	int i=0;

        //On désactive les interruptions pour que le front descendant provoqué ne soit pas comptabilisé dans les IT
        CC2530DisableInterrupt();

        //on déclenche le SS
        CC2530_MRDY = 0;
	ChipSelectSpi1SetValue(0, device);

        //On attend que le CC2530 soit prêt
        unsigned char Srdy = CC2530_SRDY;
        while(Srdy == 1)
        {
            Srdy = CC2530_SRDY;
        }

	//On envoie les commandes
	volatile unsigned char dummy;
	for (i=0; i<nbCommands; i++)
	{
		SPI1BUF=(unsigned int)commands[i];
		while ( SPI1STATbits.SPITBF ) ;
		dummy = SPI1BUF;
		while ( !SPI1STATbits.SPIRBF ) ;
		dummy = SPI1BUF;
	}

        //On attend l'arrivée du SRDY en provenance du Zigbee
        Srdy = CC2530_SRDY;
        while(Srdy == 0)
        {
            Srdy = CC2530_SRDY;
        }

        //on termine le SS
        CC2530_MRDY = 1;
	ChipSelectSpi1SetValue(1, device);

        //On réactive les interruptions pour que le front descendant provoqué ne soit pas comptabilisé dans les IT
        CC2530EnableInterrupt();
}

/*-----------------------------------------------------------------------*/
/*                  POLL Command sur le CC2530            */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void CC2530POLL(unsigned char results[], unsigned char nbResults[], unsigned char device, unsigned char invertReadCKE )
{
	int i=0;
        int nbCommands = 3;

        //on déclenche le SS
        CC2530_MRDY = 0;
	ChipSelectSpi1SetValue(0, device);

	//On envoie les 3 commandes 0 typique du POLL (page 18 de la spec)
	volatile unsigned char dummy;
	for (i=0; i<nbCommands; i++)
	{
		SPI1BUF=0x0000;
		while ( SPI1STATbits.SPITBF ) ;
		dummy = SPI1BUF;
		while ( !SPI1STATbits.SPIRBF ) ;
		dummy = SPI1BUF;
	}

	//on permute la valeur de CKE si le flag d'inversion de CKE est active
	if(invertReadCKE)
    	invertSPI1_CKE();

        //On attend l'arrivée du SRDY en provenance du Zigbee :
        //!!!!!!!!!!!!! Catastrophe au niveau timing : 1600uS sur un AF_DATA_REQUEST !!!!!!!!!!!
        unsigned char Srdy = CC2530_SRDY;
        while(Srdy == 0)
        {
            Srdy = CC2530_SRDY;
        }


        //On récupère la length du message sur le premier byte lu
	SPI1BUF=0x0000;
        //Le passage a 0 de TBF indique la fin de transmission, on attend qu'il revienne à 0
        while ( SPI1STATbits.SPITBF ) ;
        dummy = SPI1BUF;
        //Le passage à 1 de RBF indique que les données reçues sont dispo dans le buffer, on attend qu'il passe à 1
        while ( !SPI1STATbits.SPIRBF ) ;
        nbResults[0] = SPI1BUF+2;

	for (i=0; i<nbResults[0]; i++)
	{
		//On envoie un signal nul
		SPI1BUF=0x0000;
		//Le passage a 0 de TBF indique la fin de transmission, on attend qu'il revienne à 0
		while ( SPI1STATbits.SPITBF ) ;
		dummy = SPI1BUF;
		//Le passage à 1 de RBF indique que les données reçues sont dispo dans le buffer, on attend qu'il passe à 1
		while ( !SPI1STATbits.SPIRBF ) ;
		results[i] = SPI1BUF;
	}

	//on permute la valeur de CKE si le flag d'inversion de CKE est active
	if(invertReadCKE)
    	invertSPI1_CKE();

        //on termine le SS
        CC2530_MRDY = 1;
	ChipSelectSpi1SetValue(1, device);
}

#endif
#endif

/* This is SPI interrupt routine */
void __attribute__((interrupt, no_auto_psv)) _SPI1Interrupt (void)
{
	IFS0bits.SPI1IF = 0;
} 

