//******************************************************************************
// RECEIVER PROGRAM
//
// This program configures the RCVR system for use with the EEG-DBS system
//
// Richard Pinnell, 2011
// 
//******************************************************************************

#include <stdint.h>
#include <signal.h>
#include <msp430x20x3.h>

#include "CC1100-CC2500.h"
#include "TI_CC_CC1100-CC2500.h"
#include "TI_CC_msp430.h"
#include "TI_CC_spi.h"
#include "TI_CC_hardware_board.h"

// sets up timing for transmission of UART bits
#define Bitime  0x45            // For UART transmission at 115.2Kbaud/sec
#define TXD_1	0x02		

#define TX_PAYLOADSIZE  11
#define RX_PAYLOADSIZE  17

unsigned int p, pw, count, TXData, RXData, RXReady, receiveEEG, DESTIN_ADDR, repeat;
unsigned int i, j, bn, bytecount;
unsigned char BitCnt;

extern char paTable[];
extern char paTableLen;

char sendTX[TX_PAYLOADSIZE];

char rxBuffer[RX_PAYLOADSIZE];

void SetupClock(void)
{
  BCSCTL1 = CALBC1_8MHZ;                      // uses internal sub-master clock at 8MHz
  DCOCTL = CALDCO_8MHZ;                       // derives the digitally-controlled oscillator from the internal submaster clock, again at 8MHz
}

// sets up the input / output pins appropriate for interacting with the transceiver, the buffer MCU, and the PC
void SetupIO(void)
{
  P2SEL &= 0x00;                               //I/O       
  TI_CC_GDO0_PxDIR &= 0x00;                    //input
  TI_CC_GDO0_PxIES = TI_CC_GDO0_PIN;           //int on falling edge (end of pkt)
  TI_CC_GDO0_PxIFG = 0;                        //clear flag; Port1.3
  TI_CC_GDO0_PxIE = TI_CC_GDO0_PIN;            //enable int on end of packet  
  
  P1SEL &= ~0x02;                            
  P1DIR &= ~0x02;                  
  P1IES = 0x02;           
  P1IFG = 0;            
  P1IE = 0x02;  
  
  P1DIR &= ~0x04;
  
  P1DIR |= 0x08;
  P1OUT |= 0x08;  
  
  P1DIR |= 0x01;
  P1OUT &= ~0x01;
  
  P2SEL &= ~0x40;
  P2DIR |= 0x40;
  P2OUT &= ~0x40;
}

void SetupUART (void)
{
  TACCTL0 = OUT;			// Timer A Capture/Compare Control 0 Register: Output bit = sets the output high. TXD Idle as Mark
  TACTL = TASSEL_2 + MC_1;	// Timer A Control Register: clock source = SMCLK, up mode - counts up to TACCR0 (see below)
  TACCTL0 = CM0 + CCIE;		// Timer A Capture/Compare Control 0 Register: Capture Mode = 'no capture', and enable interrupts			
  TACCR0 = Bitime;                // The timer counts up to the value stored in 'Bitime' (0x45)
}

// sets up and configures the cc2500 transceiver
void setup_cc2500(void)
{
  TI_CC_SPISetup();                            //initialize SPI port
  TI_CC_PowerupResetCCxxxx();                  //reset CCxxxx
  writeRFSettings();                           //write RF settings to config reg
  
  if (P1IN & 0x04)
  {
    TI_CC_SPIWriteReg(TI_CCxxx0_ADDR,     0xDD);
    TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR,   0x32);
    DESTIN_ADDR = 0xCC;
  }
  else
  {
    TI_CC_SPIWriteReg(TI_CCxxx0_ADDR,     0xBB);  // Device address.
    TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR,   0x00); // Channel number.
    DESTIN_ADDR = 0xAA;
  }
  
  
  TI_CC_SPIWriteBurstReg(TI_CCxxx0_PATABLE, paTable, paTableLen);//Write PATABLE
  //  TI_CC_SPIStrobe(TI_CCxxx0_SCAL);             // cc2500 calibration
  TI_CC_SPIStrobe(TI_CCxxx0_SRX);              //initialize CCxxxx in RX mode.
  for(j=0;j<25000;j++);                        // wait a bit to finish calibration
}

// transmits a single byte via UART
void TX_Byte (void)
{
  BitCnt = 0xA;			// Load Bit counter, 8data + ST/SP (10 bits in total = A)
  TXData |= 0x100;			// Add mark stop bit to TXData
  TXData = TXData << 1;				// Add space start bit - remember start bit is 0, and stop bit is 1.
  TACCTL0 =  CM1 + CCIS0 + OUTMOD0 + CCIE;	// Timer A Capture/Compare Control 0 Register: set to capture on rising edge, capture an internal event on CCISA, enable interrupts 
  while ( CCTL0 & CCIE );				// Wait for TX completion
}

void calc_bn (void)
{    
  bn = (RXData>>2) & 0x03;
  count = RXData & 0x03;
  for (j=0;j<count;j++) bn = bn * 10;    
}

void transmit_cmd (void)
{
  P2IE &= ~0x40;
  P2IFG &= ~0x40;
  P1IFG &= ~0x02;         //clear flag manually
  P1IE &= ~0x02; 
  TI_CC_SPIStrobe(TI_CCxxx0_STX);
  for(i=0;i<repeat;i++)
  {
    TI_CC_SPIWriteReg(TI_CCxxx0_PKTLEN, TX_PAYLOADSIZE);
    RFSendPacket(sendTX, TX_PAYLOADSIZE);
    _BIS_SR(LPM0_bits + GIE);
  }        
  WDTCTL = 0x34;
  
}
int main (void)
{  
  WDTCTL = WDTPW + WDTHOLD;                     
  
  SetupClock();
  SetupIO();
  SetupUART();
  setup_cc2500();   
  
  sendTX[0] = DESTIN_ADDR;   
  sendTX[8] = 0x23;
  sendTX[10] = 0xEF;
  //  bytecount = 1;
  
  _EINT();				        // Enable interrupts   
  _BIS_SR(GIE);                                //enable interrupts       
  
  RXData = 0;
  RXReady = 0;
  receiveEEG = 0;
  pw = 20;
  bytecount = 1;
  
  TI_CC_SPIStrobe(TI_CCxxx0_SRX);     
  TI_CC_SPIStrobe(TI_CCxxx0_SFRX);
  
  for(;;)
  {           
    if (receiveEEG == 1)
    {      
      if (TI_CC_SPIReadStatus(TI_CCxxx0_RXBYTES)>=17)
      {             
        TI_CC_SPIReadBurstReg(TI_CCxxx0_RXFIFO, rxBuffer, 17);
        P1OUT |= 0x01;      
        
        for(j=0;j<12;j++)
        {
          TXData = rxBuffer[j+1];
          TX_Byte();
        }
        
        TXData = 0x00;
        TX_Byte();
        TXData = 0x00;
        TX_Byte();                
        
        receiveEEG = 0;
        P1OUT &= ~0x01;      
        
      }
      else  WDTCTL = 0x34;
    }
    if (TI_CC_SPIReadStatus(TI_CCxxx0_RXBYTES) > 0x80) WDTCTL = 0x34;   
    
       
    // sends 'check for command' pulse to buffer MCU to trigger an interrupt
    P2OUT |= 0x40;
    for(i=0;i<10;i++);
    P2OUT &= ~0x40;
    for(i=0;i<100;i++);
    
    // NEW CODE FOR TRANSMITTING ALL THE COMMANDS...
    
    if (RXData > 0)
    {
      
      if (RXData < 0x10)  // If the command is activate/deactivate DBS or power up/down the system
      {
        sendTX[1] = RXData;            
        if (RXData == 0x0D) repeat = 3000;
        else repeat = 1;     
        transmit_cmd();      
      }
      else if (RXData > 0) // If the command is to change frequency or pulse-width
      {
        sendTX[1] = 0x89;
        bytecount++;
        sendTX[bytecount] = RXData;
        
        if (bytecount == 5)
        {        
          // SET PW MULTIPLIER
          RXData = sendTX[5];
          calc_bn();       
          sendTX[6] = (bn >> 8);
          sendTX[7] = (bn & 0xFF);         
          
          // SET FREQ MULTIPLIER
          RXData = sendTX[3];
          calc_bn();
          sendTX[3] = sendTX[4];
          sendTX[4] = (bn >> 8);
          sendTX[5] = (bn & 0xFF);         
          
          repeat = 1;
          transmit_cmd();
        }
        else
        {            
          RXData = 0;
          SetupIO();
          SetupUART();
        }  
      }
    }
    _BIS_SR(GIE);               
    
  }
}

// this interrupt is triggered upon reception of a UART signal. It configures the timer module
// to receive a UART byte
#pragma vector = PORT1_VECTOR
__interrupt void PORT1_ISR (void)
{
  //  P1OUT |= 0x04;
  RXReady = 1;
  P2IE &= ~0x40;
  P2IFG &= ~0x40;
  P1IFG &= ~0x02;         //clear flag manually
  P1IE &= ~0x02;      
  TACCR0 = 0x01;
  TACCTL0 =  CM1 + CCIS0 + OUTMOD0 + CCIE;
  BitCnt = 0x8;
}

// this interrupt is triggered by the transceiver upon reception of a valid packet,
// and again upon transmitting a packet
#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR (void)
{
  TI_CC_GDO0_PxIFG &= ~TI_CC_GDO0_PIN;         //clear flag manually
  if (RXReady == 0) receiveEEG = 1;
  _BIC_SR_IRQ(LPM0_bits);                      //wake up CPU (clear LPM0 bits from SR)
}

// The timer_A module is set up accordingly to either receive a UART byte (from the
// buffer MCU), or to transmit a UART byte to the PC
#pragma vector = TIMERA0_VECTOR
__interrupt void TIMERA0_ISR (void)
{ 
  P1OUT &= ~0x04;
  if (RXReady == 1)
  {
    P1OUT |= 0x04;
    RXData |= (P1IN & 0x02);
    if (BitCnt == 0x08) TACCR0 = Bitime;
    if (BitCnt > 1)     RXData = RXData << 1;
    BitCnt --;
    if (BitCnt == 0)
    {
      TACCTL0 &= ~CCIE;
      _BIC_SR_IRQ(LPM0_bits);
      RXReady = 0;
      P1IE = 0x02;
      P1IFG &= ~0x02;
      RXData = RXData >> 1;
      P2IE |= 0x40;
      TACCR0 = Bitime;
    }
    P1OUT &= ~0x04;
  }
  
  else
  {  
    // TX Routine
    if ( BitCnt == 0)
    {
      TACCTL0 &= ~CCIE;			// All bits transmitted, disable interrupt
      P1OUT |= 0x08;
    }
    else
    {
      if (TXData & 0x01) P1OUT |= 0x08;
      else P1OUT &= ~0x08;
      
      TXData = TXData >> 1;		// shift the bit to the right by one bit (onto the next bit)
      BitCnt --;				// update the bit counter
    }
  }
  P1OUT &=~0x04;  
}


// PIN ALLOCATION:
//
// P1.0 - N/A
// P1.1 - UART receive (from Buffer MCU)
// P1.2 - N/A
// P1.3 - UART transmit (to PC)
// P1.4 - CSn
// P1.5 - SCLK
// P1.6 - SDO
// P1.7 - SDI
// P2.6 - Interrupt request to Buffer MCU
// P2.7 - GDO0