//----------------------------------------------------------------------------
//  Description:  This file contains functions that allow the MSP430 device to 
//  access the SPI interface of the CC1100/CC2500. 
//
//  Modified by M J Burns
//  March 2007
//----------------------------------------------------------------------------


#include "include.h"
#include "TI_CC_spi.h"


//----------------------------------------------------------------------------
//  void TI_CC_SPISetup(void)
//
//  DESCRIPTION:
//  Configures the assigned interface to function as a SPI port and
//  initializes it.
//----------------------------------------------------------------------------
//  void TI_CC_SPIWriteReg(char addr, char value)
//
//  DESCRIPTION:
//  Writes "value" to a single configuration register at address "addr".
//----------------------------------------------------------------------------
//  void TI_CC_SPIWriteBurstReg(char addr, char *buffer, char count)
//
//  DESCRIPTION:
//  Writes values to multiple configuration registers, the first register being
//  at address "addr".  First data byte is at "buffer", and both addr and
//  buffer are incremented sequentially (within the CCxxxx and MSP430,
//  respectively) until "count" writes have been performed.
//----------------------------------------------------------------------------
//  char TI_CC_SPIReadReg(char addr)
//
//  DESCRIPTION:
//  Reads a single configuration register at address "addr" and returns the
//  value read.
//----------------------------------------------------------------------------
//  void TI_CC_SPIReadBurstReg(char addr, char *buffer, char count)
//
//  DESCRIPTION:
//  Reads multiple configuration registers, the first register being at address
//  "addr".  Values read are deposited sequentially starting at address
//  "buffer", until "count" registers have been read.
//----------------------------------------------------------------------------
//  char TI_CC_SPIReadStatus(char addr)
//
//  DESCRIPTION:Reads sta
//  Special read function for reading status registers (Address 0x30 - 0x3D).  
//  Reads the status register at "addr" and returns the value read.
//----------------------------------------------------------------------------
//  void TI_CC_SPIStrobe(char strobe)
//
//  DESCRIPTION:
//  Special write function for writing to command strobe registers.  Writes
//  to the strobe at address "addr".
//----------------------------------------------------------------------------

char  ccstatus;         // Holds the status byte return from the CC1100/CC1150

// Delay function

void TI_CC_Wait(unsigned int cycles)
{
  while(cycles>15)                          // 15 cycles consumed by overhead
    cycles--; 
}  

// SPI port functions

void TI_CC_SPISetup(void)
{
  UCB0CTL1 = UCSWRST;                       // Hold USCI in Reset state

// UCIB Settings:
    // Master 
    // 3 Pin SPI
    // 8 data bits
    // Clock Source: SMCLK (8.192 MHz)
    // Bit Rate Divider (BR0, BR1): 4 (Bit Rate = 2048 kbps)
    // No Modulation
    // Clock Phase - UCCKPH High (see page 12-11)
    // MSB first

  UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_0; 
  UCB0CTL1 |= UCSSEL_2;
  UCB0BR0 = 0x04;
  UCB0BR1 = 0;
  
  UCB0CTL1 &= ~UCSWRST;                     // Enable USCI
}

void TI_CC_SPIWriteReg(char addr, char value)
{
    TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;           // Set CSN low to enable the CC1100/CC1150
    while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);       // Wait for SO to go low, indicating that the CC1100 is ready
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    UCB0TXBUF = addr & 0x3F;                     // Send address - note that bits 6 and 7 are low, indicating Write Single Register mode
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    ccstatus = UCB0RXBUF;                        // Read status from the CC1100/CC1150 
    UCB0TXBUF = value;                           // Load data for TX after addr
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;            // SET CSN high to disable the CC1100/CC1150
}

void TI_CC_SPIWriteBurstReg(char addr, char *buffer, char count)
{
    char i;

    TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;           // Set CSN low to enable the CC1100
    while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);       // Wait for SO to go low, indicating that the CC1100 is ready
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    UCB0TXBUF = (addr & 0x3F) | 0x40;            // Send address - note that bit 6 is high and bit 7 low, indicating Write Burst Mode
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    ccstatus = UCB0RXBUF;                        // Read status from the CC1100/CC1150 
    
    for (i = 0; i < count; i++)
    {
      UCB0TXBUF = buffer[i];                     // Send data
      while ((UCB0STAT&UCBUSY) > 0);             // Wait for UCB0 to go idle
    }
    
    TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;            // SET CSN high to disable the CC1100
}

char TI_CC_SPIReadReg(char addr)
{
  char x;
    
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSN low to enable the CC1100/CC1150
  while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);         // Wait for SO to go low, indicating that the CC1100 is ready
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  UCB0TXBUF = (addr & 0x3F) | 0x80;              // Send address - note that bit 6 must be low and bit 7 high to indicate a read single request                        // Wait for UCB0 to go idle
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle  
  ccstatus = UCB0RXBUF;                          // Read status from the CC1100/CC1150 
  UCB0TXBUF = 0;                                 // Send a dummy byte - this necessary in order to generate the 8 SCLK pulses required to read 
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  x = UCB0RXBUF;                                 // Read the data from the CC1100/CC1150 
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;              // SET CSN high to disable the CC1100/CC1150
  
  return x;
}

void TI_CC_SPIReadBurstReg(char addr, char *buffer, char count)
{
  unsigned int i;
 
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSN low to enable the CC1100/CC1150
  while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);         // Wait for SO to go low, indicating that the CC1100 is ready
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  UCB0TXBUF = addr | 0xC0;                       // Send address - note that bits 6 and 7 must be high to indicate a read burst request                        // Wait for UCB0 to go idle
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle  
  ccstatus = UCB0RXBUF;                          // Read status from the CC1100/CC1150 
 
  for (i = 0; i < count; i++)
  {
    UCB0TXBUF = i;                               // Dummy write to provide a clock for the 1st read data byte
    while ((UCB0STAT&UCBUSY) > 0);               // Wait for UCB0 to go idle
    buffer[i] = UCB0RXBUF;                       // Store data from last data RX
  }
  
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;              // /CS disable
}

char TI_CC_SPIReadStatus(char addr)
{
  char x;
    
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSN low to enable the CC1100/CC1150
  while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);         // Wait for SO to go low, indicating that the CC1100 is ready
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  UCB0TXBUF = (addr & 0x3F) | 0xC0;              // Send address - note that bits 6 and 7 are high to indicate a read status request                        // Wait for UCB0 to go idle
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle  
  ccstatus = UCB0RXBUF;                          // Read status from the CC1100/CC1150 
  UCB0TXBUF = 0;                                 // Send a dummy byte - this necessary in order to generate the 8 SCLK pulses required to read 
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  x = UCB0RXBUF;                                 // Read the data from the CC1100/CC1150 
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;              // SET CSN high to disable the CC1100/CC1150
  
  return x;
}

void TI_CC_SPIStrobe(char strobe)
{
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSN low to enable the CC1100/CC1150
  while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);         // Wait for SO to go low, indicating that the CC1100 is ready
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  UCB0TXBUF = strobe & 0x3F;                     // Send address - note that bits 6 and 7 are low, indicating Write Command Strobe
  while ((UCB0STAT&UCBUSY) > 0);                 // Wait for UCB0 to go idle
  ccstatus = UCB0RXBUF;                          // Read status from the CC1100/CC1150 
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;              // SET CSN high to disable the CC1100/CC1150
 }

// See Section 19.1.2 of the CC1100 specifications for an explaination of this sequence
// Note: SCLK (P3_3) and SIMO (P3_1) must de defined as DO bits (P3DIR |= 0x0A) in order for this sequence to work!!!

void TI_CC_PowerupResetCCxxxx(void) {

  P1OUT |= 0x10;      // Set P1_4 (JP200 pin 7)
  
// Take over control of the SCLK and SIMO pins    
  
  TI_CC_SPI_PxSEL &= ~(TI_CC_SPI_SCLK | TI_CC_SPI_SIMO);

  TI_CC_SPI_PxOUT |= TI_CC_SPI_SCLK;             // Set SCLK High
  TI_CC_SPI_PxOUT &= ~TI_CC_SPI_SIMO;            // Set SIMO Low   
  
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSn Low   
  TI_CC_Wait(30);
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;              // Set CSn High for at least 40 usec
  TI_CC_Wait(160);
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;             // Set CSn Low
  
  while (TI_CC_SPI_PxIN&TI_CC_SPI_SOMI);         // Wait for SO to go low, indicating that the CC1100 is ready
  
// Return control of the SCLK and SIMO pins to UCB0
  
  TI_CC_SPI_PxSEL |= (TI_CC_SPI_SCLK | TI_CC_SPI_SIMO);
 
  TI_CC_SPIStrobe(TI_CCxxx0_SRES);               // Send SRES Command Strobe
  
  P1OUT &= ~0x10;     // Reset P1_4 (JP200 pin 7)
}

