/*
 *******************************************************************************************************
 * tw_main.c                                                                                           *
 * Compiler:                IAR C Compiler for 8051                                                    *
 * Target platform:         Chipcon CC2510                                                             *
 * Author:                  MJB                                                                        *
 * Last Update:             15 July 2008                                                                *
 ******************************************************************************************************/

/***********************************************************************************
* INCLUDES
*/

#include "twoway.h"

/***********************************************************************************
* GLOBAL VARIABLES
*/

UINT8 __xdata activeIn = 0;               // Audio In (microphone) active buffer (0 | 1)
BYTE  __xdata audioIn[2][AF_BUF_SIZE];    // Audio In (microphone) data buffer
UINT8 __xdata activeOut = 0;              // Audio Out (playback) active buffer (0 | 1)
BYTE  __xdata audioOut[2][AF_BUF_SIZE];   // Audio Out (playback) data buffer
UINT8 __xdata rxBufferAvailable = 0;      // Bit will be set high when the buffer is available

UINT8  masterstatus = 0;
UINT8  slavestatus = 0;
BOOL   waitingforbeacon = TRUE;
UINT8  lostpkts = 0;
UINT16 packets = 0;

UINT8 __xdata  activeTable[FH_ACTIVE_TABLE_LEN];      // Current active frequency hopping sequence
UINT8 __xdata  ActiveChIdx;



/***********************************************************************************
* LOCAL FUNCTIONS
*/


void initIO(void) {	// Initilizes I/O Ports		

  
  // Port 0
  // P0_0  ADC AI   Analog Input (ADC)
  // P0_1  I/O DO   Test/Debug (JP105 pin 3)
  // P0_2  I/O DO   Test/Debug (JP105 pin 1)
  // P0_3  I/O DO   Test/Debug (JP105 pin 2)
  // P0_4  I/O DI   'Spare' Push Button
  // P0_5  I/O DO   VGA Gain 0
  // P0_6  I/O DO   VGA Gain 1
  // P0_7  I/O DO   BLUE LED (Heartbeat)

  P0SEL = 0x00;
  P0DIR |= 0xEE;
  P0 = 0x00;

  // Port 1
  // P1_0  I/O DO   RED LED
  // P1_1  PER DO   Timer 1 (PWM) Output
  // P1_2  I/O DO   ORANGE LED
  // P1_3  I/O DO   GREEN LED
  // P1_4  I/O DO   JP104-5  (CSN)
  // P1_5  I/O DO   JP104-6  (SCLK/GDO0)
  // P1_6  I/O DO   JP104-8  (SI/GDO1)
  // P1_7  I/O DO   JP104-10 (SO/GDO2)

  P1SEL = 0xA2;
  P1DIR |= 0xFF;
  P1 = 0x00;
  PERCFG = 0x40;          // Timer 1: use Alternate 2 pin locations (P1_0, P1_1, P1_2)

  // Port 2
  // P2_0  I/O DI   PB TALK
  // P2_1  I/O DO   DD
  // P2_2  I/O DO   DC
  // P2_3  I/O DI   Unused
  // P2_4  I/O DI   Unused

  P2SEL = 0x00;
  P2DIR = 0x00;
  P2 = 0x00;

}

/***********************************************************************************
* @fn          main
*
* @brief       Application main
*
* @param       none
*
* @return      0
*/

void main(void) {

UINT8 i;        // general use loop counter

// Initializations
  CLKCON = 0x80;                          // Select Xosc as clock source running at the highest speed
  while( CLKCON != 0x80 );                // Wait for Xosc stable
  SLEEP |= 0x04;                          // Power down HSRC osc.

  initIO();                      	  // Init I/O Ports
  initDsm();                              // Configures timer1 for DSM
  I2SCFG0 = 0x00;                         // Reset ENAB
  initAdc();
  initDma();                              // Initialize the DMA administrator (reset DMA ch 1-4)

  for (i = 0; i < AF_BUF_SIZE; i++)
  {
    audioIn[0][i] = audioIn[1][i] = 0;
    audioOut[0][i] = audioOut[1][i] = 0;
  }

  // Configure radio and reserve DMA channels for RX/TX buffers
  initRf(RADIO_BASE_FREQ);

  macTimer3Init();

  activeTable[0] = CHANNEL_1;
  activeTable[1] = CHANNEL_2;
  activeTable[2] = CHANNEL_3;
  activeTable[3] = CHANNEL_4;

  INT_GLOBAL_ENABLE(INT_ON);

  VGA_GAIN_REG |= 0x60;
  LED_BLUE_REG |= LED_BLUE;           // Turn on the Blue LED

#ifdef MEASFREQ

  SCAL();                           // Start PLL calibration at new channel

  PKTCTRL0 = 0x02;                  // Enable infinite length packets; disable CRC
  MDMCFG2 = 0x02;

  while (MARCSTATE != MARCSTATE_IDLE);        // Wait for calibration to complete

  STX();

  while (1)  {        // main program loop
    for (i = 0; i < 61; i += 20) {
      setChannel((UINT8) i);
      
      SCAL();                                     // Start PLL calibration at new channel
      while (MARCSTATE != MARCSTATE_IDLE);        // Wait for calibration to complete

      while ((LED_BLUE_REG & LED_BLUE) == 0);     // leave off for 250 msec
      
      STX();
      
      while ((LED_BLUE_REG & LED_BLUE) > 0);     // leave on for 250 msec
    }
  }   // end of 'while (1)' loop
}

#else   // not in 'measfreq' mode

#ifdef MASTER

// Master Code

  MAStxData.macPayloadLen = TX_PAYLOAD_LEN;
  MAStxData.macField = MAC_ADDR;
 
  while (1)  {        // main program loop

    setChannel(activeTable[ActiveChIdx]);     // SetChannel will set the MARCSTATE to IDLE
    ActiveChIdx++;
    if (ActiveChIdx == FH_ACTIVE_TABLE_LEN)
      ActiveChIdx = 0;

    SCAL();           // Start PLL calibration at new channel

    while (audioFrameReady == FALSE) {        // Wait until an audioframe is ready to be transmitted
    }

    audioFrameReady = FALSE;
    MAStxData.statusField = masterstatus;
    MAStxData.channel[0] = activeTable[0];
    MAStxData.channel[1] = activeTable[1];
    MAStxData.channel[2] = activeTable[2];
    MAStxData.channel[3] = activeTable[3];

    for (i = 0; i < AF_BUF_SIZE; i++) {
      if (activeIn == 1)
        MAStxData.payload[i] = audioIn[0][i];
      else
        MAStxData.payload[i] = audioIn[1][i];
    }

    while (MARCSTATE != MARCSTATE_IDLE);            // Wait for calibration to complete

#ifdef SKIPAPACKET
    packets++;

    if (packets == HOWOFTEN) {
      packets = 0;
      P0 |= 0x02;           // set P0_1 (JP105 pin 3) *Test/Debug
      continue;
    }
    else
      P0 &= ~0x02;          // reset P0_1 (JP105 pin 3) *Test/Debug
#endif

    P0 |= 0x08;             // set P0_3 (JP105 pin 2) *Test/Debug
    rfSendPacket(MASTER_TX_TIMEOUT_WO_CALIB);
    P0 &= ~0x08;            // reset P0_3 (JP105 pin 2) *Test/Debug

// Listen for data from Slave

    P1 |= 0x10;                     // set P1_4 (JP104 pin 5) *Test/Debug
    rfReceivePacket(&MASrxData, MASTER_RX_TIMEOUT_WO_CALIB, RX_PAYLOAD_LEN);
    P1 &= ~0x10;                    // reset P1_4 (JP104 pin 5) *Test/Debug

    if (rxPacketStatus == TIMEOUT_ERROR) {
      P0 |= 0x04;                   // set P0_2 (JP105 pin 1) *Test/Debug
      LED_RED_REG |= LED_RED;       // Lite the Red LED

      if (activeOut == 0)
        rxBufferAvailable &= ~BUFFERA;      // Mark Buffer A as unavailable
      else
        rxBufferAvailable &= ~BUFFERB;      // Mark Buffer B as unavailable
    }
    else {                                  // A packet was received
      LED_RED_REG &= ~LED_RED;              // Extingusih the Red LED
      P0 &= ~0x04;                          // Reset P0_2 (JP105 pin 1) *Test/Debug
// Temporarily mark the active RX buffer as unavailable

      if (activeOut == 0)
        rxBufferAvailable &= ~BUFFERA;      // Mark Buffer A as unavailable
      else
        rxBufferAvailable &= ~BUFFERB;      // Mark Buffer B as unavailable

// Move data into audio buffer

      for (i = 0; i < AF_BUF_SIZE; i++)
        audioOut[activeOut][i] = MASrxData.payload[i];

// Now mark the active RX buffer as available

      if (activeOut == 0)
        rxBufferAvailable |= BUFFERA;       // Mark Buffer A as available
      else
        rxBufferAvailable |= BUFFERB;       // Mark Buffer B as unavailable
    }     // end of TIMEOUT_ERROR 'else' (i.e., packet received)

    activeOut ^= 0x01;            // In any event, toggle activeOut

  }   // end of 'while (1)' loop
}
#endif

#ifdef SLAVE

// Slave Code

// Initilize Timer 2 (Frame Timer)
// Notes: Timer 2 consists of an 8 bit 'down' counter with a 18 bit prescaler
// The Timer tic period is T = T2PR * Val(T2CTL.TIP) clock cycles, where
// Val = 64 if T2CTL bits 1:0 = 0
// Val = 128 if T2CTL bits 1:0 = 1
// Val = 256 if T2CTL bits 1:0 = 2
// Val = 1024 if T2CTL bits 1:0 = 3

  T2CT = 0;         // Stop the Timer
  T2PR = 6;         // Timer Prescale Multipler
  T2CTL = 0x01;     // Set Tick period to 128*T2PR clock cycles (128*6/26.000 MHz = 29.538 usec)
                    // Interrupts Disabled

  SLVtxData.macPayloadLen = TX_PAYLOAD_LEN;
  SLVtxData.macField = MAC_ADDR;

  while (1)  {                              // main program loop
    if (waitingforbeacon) {
      LED_GREEN_REG &= ~LED_GREEN;          // Extinguish the Green (paired) LED
      LED_ORANGE_REG |= LED_ORANGE;         // Light the Orange LED
      setChannel(activeTable[0]);           // Listen on channel activeTable[0] for the beacon
      SCAL();                               // Start PLL calibration at new channel
      while (MARCSTATE != MARCSTATE_IDLE);  // Wait for calibration to complete

      rxPacketStatus == PKT_STATUS_UNKNOWN;

      while (rxPacketStatus != PKT_OK) {    // Stay in this loop until the Beacon is heard (i.e., a packet is received)
        P1 |= 0x10;                         // set P1_4 (JP104 pin 5) *Test/Debug
        ListenforMaster(&SLVrxData, LISTEN_FOR_BEACON_TIMEOUT, RX_PAYLOAD_LEN);
        P1 &= ~0x10;                        // reset P1_4 (JP104 pin 5) *Test/Debug
      }   // end of 'while (1)' loop
      
      LED_ORANGE_REG &= ~LED_ORANGE;        // Extinguish the Orange LED
      LED_GREEN_REG |= LED_GREEN;           // Light the Green ('Paired') LED
      lostpkts = 0;
      ActiveChIdx = 1;                      // set Active Channel Index to next channel (1)
      waitingforbeacon = FALSE;             // Exit 'waitingforbeacon' mode
      T2CT = FRAME_TIMEOUT_DEFAULT;         // Reset the Frame Timer
    }     // end of 'waitingforbeacon' if

    else {                                  // We are 'Paired'

// Listen for packet from Master

      while (MARCSTATE != MARCSTATE_IDLE) {      // Wait for calibration to complete (Machine State = Idle)
      }

      while (T2CT > LISTENFORMASTER) { // Wait until it's time to listen for the Maste
      }

      P1 |= 0x10;                     // set P1_4 ( JP104 pin 5) *Test/Debug
      rfReceivePacket(&SLVrxData, SLAVE_RX_TIMEOUT_WO_CALIB, RX_PAYLOAD_LEN);
      P1 &= ~0x10;                    // reset P1_4 (JP104 pin 5) *Test/Debug

      if (rxPacketStatus == TIMEOUT_ERROR)
        while (T2CT > 0) {             // let the frame timer run down to zero
        }

      T2CT = FRAME_TIMEOUT_DEFAULT;   // Reset the Frame Timer
    }     // end of waitingforbeacon 'else' loop

// Send Data to Master

    SLVtxData.statusField = slavestatus;

    for (i = 0; i < AF_BUF_SIZE; i++) {
      if (activeIn == 1) {
        SLVtxData.payload[i] = audioIn[0][i];
      }
      else {
        SLVtxData.payload[i] = audioIn[1][i];
      }
    }

    P0 |= 0x08;                       // set P0_3 (JP105 pin 2) *Test/Debug
    rfSendPacket(SLAVE_TX_TIMEOUT_WO_CALIB);
    P0 &= ~0x08;                      // reset P0_3 (JP105 pin 2) *Test/Debug
    
    SIDLE();          // Force the Receiver into the Idle state

// Set the next channel and initiate calibration

    setChannel(activeTable[ActiveChIdx]);     // SetChannel will set the MARCSTATE to IDLE
    ActiveChIdx++;
    if (ActiveChIdx == FH_ACTIVE_TABLE_LEN)
      ActiveChIdx = 0;
    SCAL();                         // Start PLL calibration at new channel

    if (rxPacketStatus == TIMEOUT_ERROR) {
      P0 |= 0x04;                   // set P0_2 (JP105 pin 1)  *Test/Debug
      LED_RED_REG |= LED_RED;       // Lite the Red LED

      if (activeOut == 0)
        rxBufferAvailable &= ~BUFFERA;      // Mark Buffer A as unavailable
      else
        rxBufferAvailable &= ~BUFFERB;      // Mark Buffer B as unavailable

      lostpkts++;
      if (lostpkts > 4) {           // if 4 consecutive packets have been lost
        lostpkts = 0;
        waitingforbeacon = TRUE;    // enter 'waiting for beacon' (resync) mode
      }
    }
    else {                          // A packet was received
      LED_RED_REG &= ~LED_RED;      // Extingusih the Red LED
      P0 &= ~0x04;                  // Reset P0_2 (JP105 pin 1)  *Test/Debug
      lostpkts = 0;

// Temporarily mark the active RX buffer as unavailable

      if (activeOut == 0)
        rxBufferAvailable &= ~BUFFERA;      // Mark Buffer A as unavailable
      else
        rxBufferAvailable &= ~BUFFERB;      // Mark Buffer B as unavailable

// Move data into audio buffer

      for (i = 0; i < AF_BUF_SIZE; i++)
        audioOut[activeOut][i] = SLVrxData.payload[i];

// Now mark the active RX buffer as available

      if (activeOut == 0)
        rxBufferAvailable |= BUFFERA;       // Mark Buffer A as available
      else
        rxBufferAvailable |= BUFFERB;       // Mark Buffer B as unavailable
    }     // end of TIMEOUT_ERROR 'else' (i.e., packet received)

    activeOut ^= 0x01;            // In any event, toggle activeOut
  }       // end of 'while (1)' (main program) loop
}
#endif
#endif

/***********************************************************************************
  Copyright 2008 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
***********************************************************************************/
