#include <cc2msp430f2112.h>
#include "cc2500_regs.h"

/*******************************************************************************
CURRENT LOAD UP CODE BEFORE LOOP
Doubt the below delays are required, Just had them to be safe
 * ****************************************************************************/
/*	//Setup SPI on F2112
	__delay_cycles(5000); 			
        spi_setup(); 					
  
	//PowerUp reset CC2500
	__delay_cycles(5000);
	cc_powerup_reset(); 		// Reset CCxxxx
  
	//Write RFSettings
	__delay_cycles(1000);		
	writeRFSettings();				// Write RF settings to config reg
  
	//Write Patable
	__delay_cycles(1000);

        initial_power[0] = 0x00;
	cc_write_burst_reg( TI_CCxxx0_PATABLE, initial_power, 1);	//Write PATABLE, Would like to move this into the WriteRFSettings Function
	
	//Initialize CC2500 in Idle Mode
	cc_strobe(TI_CCxxx0_SRX);     	// When a pkt is received, it will
									// signal on GDO0 and wake CPU
								
	//Enable interrupts
	__bis_SR_register(GIE);      	// 		  __bis_SR_register(LPM3_bits + GIE) to go into Low power mode as well.
	
	// Configure GDO0
	//Unsure if this is needed as of yet. Port may change as well in the future depending on where we map it
	P2DIR &= ~GDO0_PIN;
	GDO0_PxIE |= GDO0_PIN;        	// Enable int on end of packet
	GDO0_PxIES |= GDO0_PIN;       	// Int on falling edge (end of pkt)
	GDO0_PxIFG &= ~GDO0_PIN;      	// Clear flag
        
    */    

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
	
/*******************************************************************************
Declare Functions
 ****************************************************************************/

void spi_setup(void);
void cc_powerup_reset(void);
void wait_cycles(uint16_t);
void writeRFSettings(void);
void cc_write_reg(uint8_t, uint8_t);
void cc_write_burst_reg(uint8_t, uint8_t*, uint8_t);
uint8_t cc_read_reg(uint8_t addr);
void cc_read_burst_reg(uint8_t addr, uint8_t *buffer, uint8_t count);
uint8_t cc_read_status(uint8_t);
void cc_strobe(uint8_t);




/*******************************************************************************
Functions Listed Below
 ****************************************************************************/


/*******************************************************************************
 * @fn spi_setup(void)
 * @brief  Setting up SPI Settings for the MSP430F2112
 * ****************************************************************************/
void spi_setup(void)
{
  CSn_PxOUT |= CSn_PIN;
  CSn_PxDIR |= CSn_PIN;         // /CS disable

  UCB0CTL1 |= UCSWRST;                      // **Disable USCI state machine**
  UCB0CTL0 |= UCMST+UCMSB+UCSYNC+UCCKPL;    // 3-pin, 8-bit SPI master
  UCB0CTL1 |= UCSSEL_2;                     // SMCLK
 
  UCB0BR0 = 0x02;                           // UCLK/2
  UCB0BR1 = 0;

	SPI_USCIB0_PxSEL |= SPI_USCIB0_SIMO		// Or SPI_USCIB0_PxSEL |= SPI..etc etc
                          | SPI_USCIB0_SOMI
                          | SPI_USCIB0_UCLK;
						  
	SPI_USCIB0_PxDIR |= (SPI_USCIB0_SIMO | SPI_USCIB0_UCLK);	
        SPI_USCIB0_PxDIR &= ~(SPI_USCIB0_SOMI);

                                            // SPI option select
  //SPI_USCIB0_PxDIR |= SPI_USCIB0_SIMO | SPI_USCIB0_UCLK;
                                            // SPI TXD out direction
  UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
}

/*******************************************************************************
 * @fn cc_powerup_reset(void)
 * @brief Power Up Reset of the CC2500
 * ****************************************************************************/
void cc_powerup_reset(void)
{
  CSn_PxOUT |= CSn_PIN;
  TI_CC_Wait(45);
  CSn_PxOUT &= ~CSn_PIN;
  TI_CC_Wait(45);
  CSn_PxOUT |= CSn_PIN;
  TI_CC_Wait(45);

  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = TI_CCxxx0_SRES;               // Send strobe
  
  // Strobe addr is now being TX'ed Option 1
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  while(SPI_USCIB0_PxIN & SPI_USCIB0_SOMI); // Wait until the device has reset
  CSn_PxOUT |= CSn_PIN;         // /CS disable
  
 //Option 2
 // Strobe addr is now being TX'ed
 //while(!(UTCTL0 & TXEPT));                 // Wait for TX complete
 // TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         // /CS disable

}


/*******************************************************************************
 * @fn TI_CC_Wait(unsigned int cycles)
 * @brief 	Delay function. # of CPU cycles delayed is similar to "cycles". Specifically,
			it's ((cycles-15) % 6) + 15.  Not exact, but gives a sense of the real-time
			delay.  Also, if MCLK ~1MHz, "cycles" is similar to # of useconds delayed.
 * ****************************************************************************/
void TI_CC_Wait(unsigned int cycles)
{
  while(cycles>15)                          // 15 cycles consumed by overhead
    cycles = cycles - 6;                    // 6 cycles consumed each iteration
}



/*******************************************************************************
 * @fn writeRFSettings(void)
 * @brief Write RF settings into the CC2500
 * ****************************************************************************/
void writeRFSettings(void)
{
  // Write register settings
  cc_write_reg(TI_CCxxx0_IOCFG2,   0x0F);  // GDO2 output pin config. //YEs
  cc_write_reg(TI_CCxxx0_IOCFG0,   0x06);  // GDO0 output pin config. //YES
  cc_write_reg(TI_CCxxx0_PKTLEN,   0x3D);  // Packet length.    //YES
  cc_write_reg(TI_CCxxx0_PKTCTRL1, 0x00);  // Packet automation control.// 01 = Addresing //00 = Stock //YES
  cc_write_reg(TI_CCxxx0_PKTCTRL0, 0x01);  // Packet automation control.// //YES
  cc_write_reg(TI_CCxxx0_ADDR,     0x00);  // Device address.// YES
  cc_write_reg(TI_CCxxx0_CHANNR,   0xCC); // Channel number.// YES BE FOR NO GDO BF FOR GDO
  cc_write_reg(TI_CCxxx0_FSCTRL1,  0x08); // Freq synthesizer control.// YES
  cc_write_reg(TI_CCxxx0_FSCTRL0,  0x00); // Freq synthesizer control. //Yes
  cc_write_reg(TI_CCxxx0_FREQ2,    0x5D); // Freq control word, high byte //Yes
  cc_write_reg(TI_CCxxx0_FREQ1,    0x44); // Freq control word, mid byte. //Yes
  cc_write_reg(TI_CCxxx0_FREQ0,    0xB1); // Freq control word, low byte. //YEs
  cc_write_reg(TI_CCxxx0_MDMCFG4,  0xC6); // Modem configuration.// YES
  cc_write_reg(TI_CCxxx0_MDMCFG3,  0x83); // Modem configuration. //YES
  cc_write_reg(TI_CCxxx0_MDMCFG2,  0x70); // Modem configuration.// YES 70=No Syn
  cc_write_reg(TI_CCxxx0_MDMCFG1,  0x23); // Modem configuration.//  YES 4 Pre Bytes
  cc_write_reg(TI_CCxxx0_MDMCFG0,  0x3B); // Modem configuration.// YERSD
  cc_write_reg(TI_CCxxx0_DEVIATN,  0x44); // Modem dev (when FSK mod en) //yES
  cc_write_reg(TI_CCxxx0_MCSM1 ,   0x2F); //MainRadio Cntrl State Machine
  cc_write_reg(TI_CCxxx0_MCSM0 ,   0x18); //MainRadio Cntrl State Machine
  cc_write_reg(TI_CCxxx0_FOCCFG,   0x16); // Freq Offset Compens. Config //YES
  cc_write_reg(TI_CCxxx0_BSCFG,    0x1C); //  Bit synchronization config.
  cc_write_reg(TI_CCxxx0_AGCCTRL2, 0xC7); // AGC control.
  cc_write_reg(TI_CCxxx0_AGCCTRL1, 0x00); // AGC control.
  cc_write_reg(TI_CCxxx0_AGCCTRL0, 0xB2); // AGC control.
  cc_write_reg(TI_CCxxx0_FREND1,   0xB6); // Front end RX configuration.
  cc_write_reg(TI_CCxxx0_FREND0,   0x10); // Front end RX configuration.
 cc_write_reg(TI_CCxxx0_FSCAL3,   0xEA); // Frequency synthesizer cal.
cc_write_reg(TI_CCxxx0_FSCAL2,   0x0A); // Frequency synthesizer cal.
cc_write_reg(TI_CCxxx0_FSCAL1,   0x00); // Frequency synthesizer cal.
cc_write_reg(TI_CCxxx0_FSCAL0,   0x11); // Frequency synthesizer cal.
    
  cc_write_reg(TI_CCxxx0_FSTEST,   0x59); // Frequency synthesizer cal.
  cc_write_reg(TI_CCxxx0_FSTEST,   0x59); // Frequency synthesizer cal.
  
  cc_write_reg(TI_CCxxx0_TEST2,    0x88); // Various test settings.
  cc_write_reg(TI_CCxxx0_TEST1,    0x31); // Various test settings.
  cc_write_reg(TI_CCxxx0_TEST0,    0x0B);  // Various test settings.
}

/*******************************************************************************
 * @fn void cc_write_reg(uint8_t addr, uint8_t value)
 * @brief Write single register value to CC2500
 * ****************************************************************************/
void cc_write_reg(uint8_t addr, uint8_t value)
{
  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = addr;                         // Send address
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = value;                        // Send data
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  CSn_PxOUT |= CSn_PIN;                     // /CS disable
}



/*******************************************************************************
 * @fn cc_write_burst_reg(uint8_t addr, uint8_t *buffer, uint8_t count)
 * @brief Write multiple values to CC2500
 * ****************************************************************************/
void cc_write_burst_reg(uint8_t addr, uint8_t *buffer, uint8_t count)
{
  uint16_t i;

  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = addr | TI_CCxxx0_WRITE_BURST; // Send address
  for (i = 0; i < count; i++)
  {
    while (!(IFG2&UCB0TXIFG));              // Wait for TXBUF ready
    UCB0TXBUF = buffer[i];                  // Send data
  }
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  CSn_PxOUT |= CSn_PIN;         // /CS disable
}






/*******************************************************************************
 * @fn uint8_t cc_read_reg(uint8_t addr)
 * @brief read single register from CC2500
 * ****************************************************************************/
uint8_t cc_read_reg(uint8_t addr)
{
  uint8_t x;

  CSn_PxOUT &= ~CSn_PIN;        			// /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = (addr | TI_CCxxx0_READ_SINGLE);// Send address
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = 0;                            // Dummy write so we can read data
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  CSn_PxOUT |= CSn_PIN;         			// /CS disable
  x = UCB0RXBUF;                            // Read data

  return x;
}

/*******************************************************************************
 * @fn cc_read_burst_reg(uint8_t addr, uint8_t *buffer, uint8_t count)
 * @brief read multiple registers from CC2500
 * ****************************************************************************/
void cc_read_burst_reg(uint8_t addr, uint8_t *buffer, uint8_t count)
{
  uint8_t i;

  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = (addr | TI_CCxxx0_READ_BURST);// Send address
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  UCB0TXBUF = 0;                            // Dummy write to read 1st data byte
  // Addr byte is now being TX'ed, with dummy byte to follow immediately after
  IFG2 &= ~UCB0RXIFG;                       // Clear flag
  while (!(IFG2&UCB0RXIFG));                // Wait for end of 1st data byte TX
  // First data byte now in RXBUF
  for (i = 0; i < (count-1); i++)
  {
    UCB0TXBUF = 0;                          //Initiate next data RX, meanwhile..
    buffer[i] = UCB0RXBUF;                  // Store data from last data RX
    while (!(IFG2&UCB0RXIFG));              // Wait for RX to finish
  }
  buffer[count-1] = UCB0RXBUF;              // Store last RX byte in buffer
  CSn_PxOUT |= CSn_PIN;         // /CS disable
}




/*******************************************************************************
 * @fn uint8_t cc_read_status(uint8_t addr)
 * @brief send status command and read returned status byte
 * ****************************************************************************/
uint8_t cc_read_status(uint8_t addr)
{
  uint8_t status;

  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = (addr | TI_CCxxx0_READ_BURST);// Send address
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = 0;                            // Dummy write so we can read data
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  status = UCB0RXBUF;                       // Read data
  CSn_PxOUT |= CSn_PIN;         // /CS disable

  return status;
}


/*******************************************************************************
 * @fn void cc_strobe(uint8_t strobe)
 * @brief  Send a Strobe Command to the CC2500 -> Used to change CC states etc
 * ****************************************************************************/
void cc_strobe(uint8_t strobe)
{
  CSn_PxOUT &= ~CSn_PIN;        // /CS enable
  while (!(IFG2&UCB0TXIFG));                // Wait for TXBUF ready
  UCB0TXBUF = strobe;                       // Send strobe
  // Strobe addr is now being TX'ed
  while (UCB0STAT & UCBUSY);                // Wait for TX to complete
  CSn_PxOUT |= CSn_PIN;         // /CS disable
}

