// ******************************************************************
// MULTIMODE DBS DEVICE
// 
// This program configures the microcontroller channel 1 (MCU-1) for use
// with the DBS device. 
//
//
// Richard Pinnell 2012
//*******************************************************************

#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"

#define TX_PAYLOADSIZE  10
#define DESTIN_ADDR  0xFF

#define Bitime    0x8A

unsigned char BitCnt;

extern char paTable[];
extern char paTableLen;

// the following arrays are set-up for transmission and reception
char txBuffer[TX_PAYLOADSIZE + 1];   
char aa = TX_PAYLOADSIZE + 1;

unsigned char BitCnt;
unsigned int dbsone, TXReady, count, TXData, dbstwo;
unsigned int pcount, p, l;
unsigned int x, i, j, n, b, pw, check;
// unsigned int r;

// 16-bit integers to be written to the timer module
uint16_t time1, time2;

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 for communication with MCU-2, the voltage amplifier, bipolar pulse control, and the DBS pulse generator
void SetupIO(void)
{
  // Interrupt settings for communication with the CC2500
   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  

// SYSTEM CONTROL PINS *******************************************
   // P1.0 - Communication with MCU 2
   P1DIR |= 0x01;
   P1OUT |= 0x01;
   // P1.1 - Voltage Amplifier ON/OFF
   P1DIR |= 0x02;
   // P1.3 - Bipolar Pulse Control
   P1DIR |= 0x08;
   // P2.6 - DBS Pulses
   P2DIR |= 0x40;
   P2OUT &= ~0x40;                    
//**************************************************************   
}

// sets up the transceiver
void setup_cc2500(void)
{
   TI_CC_SPISetup();                            //initialize SPI port
   TI_CC_PowerupResetCCxxxx();                  //reset CCxxxx
   writeRFSettings();                           //write RF settings to config reg
   TI_CC_SPIWriteBurstReg(TI_CCxxx0_PATABLE, paTable, paTableLen);//Write PATABLE - sets the output power level
   TI_CC_SPIStrobe(TI_CCxxx0_SCAL);             // cc2500 calibration
   for(j=0;j<50000;j++);                        // wait a bit to finish calibration
   TI_CC_SPIStrobe(TI_CCxxx0_SPWD);              //initialize CCxxxx in RX mode.
                                                //when a pkt is received, it will
                                                //signal on GDO0 and wake CPU
}

// Sets up the DBS output pin for use with the TIMER_A module
void setupDBS(void)
{
  CCTL0 = ~CCIE;                             // CCR0 interrupt enabled
  TACCR0 = 60800;
  TACTL = TASSEL_2 + MC_1 + TACLR;                  // SMCLK, upmode  
}

// Transmits a byte via bit-banging (see timer interrupt below). Bytes are sent
// via. 8-N-1 protocool to MCU-2

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
}

// This function lets the system know what to do upon reception of a valid transmission burst. It either configures internal settings
// based on the new DBS parameters (if the command is for MCU-1), otherwise it forwards the command to MCU-2.
void receive_packet()
{  
  if (txBuffer[1] >= 0x10)
  {  
    dbsone = txBuffer[1] & 0xF0;    
    // SET PW VALUE
    pw = txBuffer[4] & 0x3F;
    time1 = pw*80;      
    
    // SET FREQ VALUE      
    time2 = txBuffer[2] & 0x3F;
    time2 = 40000/time2;
    l = (time2/80) -1;
    
    b = (txBuffer[5]>>2) & 0x03;    
    count = txBuffer[5] & 0x03;
    for (j=0;j<count;j++) b = b * 10;
    p = b * pw;
    
    // SET FREQ MULTIPLIER
    n = (txBuffer[3]>>2) & 0x03;
    count = txBuffer[3] & 0x03;
    for (j=0;j<count;j++) n = n * 10;    

    // SET positive pulses
    if (dbsone == 0xC0) P1OUT &= ~0x08;
    
    // SET negative pulses
    else if (dbsone == 0x30) P1OUT |= 0x08;

    else if (b == 1)
    {
      b *= 2;
      time1 /= 2;
    }    
  }
  // otherwise command is for MCU-2: raise the UART transmission flag.
  else 
  {
    TXReady = 2;  
    dbstwo = txBuffer[1];
  }  
}   

// Delay used in UART and SPI communication
void wait()
{
  for(j=0;j<4000;j++);         
}

int main (void)
{   
  WDTCTL = WDTPW + WDTHOLD;                     //stop WDT  
  _EINT();				        // Enable interrupts   
  _BIS_SR(GIE);                                //enable interrupts       
  
  // run through the following functions to configure the MCU and the transceiver
   SetupClock();
   SetupIO();
   setup_cc2500();   
   setupDBS();    
//   txBuffer[0] = TX_PAYLOADSIZE + 1;
   txBuffer[0] = DESTIN_ADDR;

//*********************************************************************************************
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
//*********************************************************************************************
////// set initial values for the variables. The DBS is initially set to 25Hz, 100uS pulse-mode

   // change channel 1 state
   txBuffer[1] = 0x60;
   // change channel 1 frequency value
   txBuffer[2] = 0x45;
   // change channel 1 multiplier
   txBuffer[3] = 0xCA;
   // change channel 1 pulse-width value
   txBuffer[4] = 0x81;
   // change channel 1 pulse-width multiplier
   txBuffer[5] = 0xE6;

//*********************************************************************************************
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
//*********************************************************************************************
//////////////////////////////////////////////////////////////////////////   
   receive_packet();
//*********************************************************************************************
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.

   // if channel 1 or channel 1+2 are active, use this code.
   CCTL0 = CCIE;
   P1OUT |= 0x02;   

// if channel 2 is active only, use this code  
//   CCTL0 = ~CCIE;
//   P1OUT |= 0x02;  

// if channel 1 and 2 are off, use this code
   
//   CCTL0 = ~CCIE;
//   P1OUT &= ~0x02;

   
//*********************************************************************************************
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.
// CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE. CHANGE DBS SETTINGS HERE.

   TXReady = 0;   
//   r = 0;   
   check = 0;
   
   for(;;)
   {           
     // configures the transciever for wake-on-radio mode
     TI_CC_SPIWriteReg(TI_CCxxx0_MCSM2,    0x06);
     TI_CC_SPIWriteReg(TI_CCxxx0_WORCTRL,  0x78);
//     // transciever enters wake-on-radio mode
     TI_CC_SPIStrobe(TI_CCxxx0_SIDLE);
     TI_CC_SPIStrobe(TI_CCxxx0_SWOR);
     
     _BIS_SR(LPM0_bits + GIE);

    for(i=0;i<312;i++) wait();
     
     CCTL0 = ~CCIE;
     P2OUT &= ~0x40;
          
     if (TI_CC_SPIReadStatus(TI_CCxxx0_RXBYTES)>=11)              // checks that there's bytes in the RX fifo buffer
     {                      
       TI_CC_SPIReadBurstReg(TI_CCxxx0_RXFIFO, txBuffer, 11);  // reads the stored bytes and puts it into a buffer             
       receive_packet();         
       pcount = p;
       x = 0;    
       setup_cc2500();
     }
     
     // transciever enters wake-on-radio mode
     TI_CC_SPIStrobe(TI_CCxxx0_SIDLE);
     TI_CC_SPIStrobe(TI_CCxxx0_SWOR);           

    if (txBuffer[6] == 0x12) check = check + 1;
    if (txBuffer[7] == 0x34) check = check + 1;
    if (txBuffer[8] == 0x56) check = check + 1;
    if (txBuffer[9] == 0x78) check = check + 1;
    
    if (check == 4) {}
    else
    {
      dbsone = 0x01;
      txBuffer[1] = 0x01;
      dbstwo = 0x01;
    }     
    check = 0;
          
     // If UART transmission flag is raised, transmit commands to MCU_2.
     if (TXReady == 2)
     {
       TACCR0 = Bitime;
       
       for (i=1;i<6;i++)
       {
         TXData = txBuffer[i];
         TX_Byte();
         wait();
         wait();
         wait();
       }
       TXReady = 0;
     }

       
     if (dbsone > 0x20)
     {
       CCTL0 = CCIE;
       P1OUT |= 0x02;
     }
     else if (dbstwo > 0x02) P1OUT |= 0x02;
     else P1OUT &= ~0x02;
   }
}

// This interrupt always arrives from the transceiver upon transmission of a packet, reception of a packet,
// or during 'wake-on-radio' when the transceiver receives a command.
#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR (void)
{
   TI_CC_GDO0_PxIFG &= ~TI_CC_GDO0_PIN;         //clear flag manually
   _BIC_SR_IRQ(LPM0_bits);                      //wake up CPU (clear LPM0 bits from SR) 
}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0 (void)
{
  if (TXReady == 2)
  {
    // TX Routine
    if ( BitCnt == 0)
    {
      TACCTL0 &= ~CCIE;			// All bits transmitted, disable interrupt
      P1OUT |= 0x01;
    }
    else
    {
      if (TXData & 0x01)		// if least significant bit of TXData is high, then set the output bit high correspondingly??
      {
        P1OUT |= 0x01;
      }
      else P1OUT &= ~0x01;
      TXData = TXData >> 1;		// shift the bit to the right by one bit (onto the next bit)
      BitCnt --;				// update the bit counter
    }
  }
  
  else    
  {    
    if (x < n)
    {      
      P2OUT &= ~0x40;
      if (pcount == 0) TACCR0 = time2;      
      
      else if (pcount <= l)
      {
        TACCR0 = time2 - (pcount*80);
        pcount = 0;
      }
      else if (pcount > l)
      {
        TACCR0 = time2 - (l*80);
        pcount -= l;
      }
      x++;
    }
    else if (x < (n+b))
    { 
      if (dbsone == 0x60)
      {
        if (x >= (n+(b/2))) P1OUT |= 0x08;
        else P1OUT &= ~0x08;
      }      
      
      if (dbsone > 0x20) P2OUT |= 0x40;
      TACCR0 = time1;
      x++;
      if (x == (n+b))
      {
        x = 0;
        pcount = p;
      }
    }
  }
}


// PIN ALLOCATION
//
// P1.0 - UART to MCU 2
// P1.1 - on/off switch (DBS Power Control)
// P1.2 - 
// P1.3 - Bipolar/Monopolar Switch Input
// P1.4 - CSn
// P1.5 - SCLK
// P1.6 - MOSI
// P1.7 - MISO
// P2.6 - DBS Channel Pair 1
// P2.7 - Transceiver Interrupt (GDO0)