/*******************************************************************************************************
 *                                                                                                     *
 *        **********                                                                                   *
 *       ************                                                                                  *
 *      ***        ***                                                                                 *
 *      ***   +++   ***                                                                                *
 *      ***   + +   ***     Interrupt handlers                                                         *
 *      ***   +                                                                                        *
 *      ***   + +   ***                                                                                *
 *      ***   +++   ***     tw_interrupt.c                                                             *
 *      ***        ***                                                                                 *
 *       ************                                                                                  *
 *        **********                                                                                   *
 *                                                                                                     *
 *******************************************************************************************************
 * Compiler:                IAR C Compiler for 8051                                                    *
 * Target platform:         Chipcon CC2510                                                             *
 * Author:                  MJB                                                                        *
 * Last Update:             30 Jan 2010 MJB                                                           *
 ******************************************************************************************************/

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

#include "twoway.h"

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

UINT8 audioInindx = 0;
UINT8 audioOutindx = 0;
INT16 pwmsample;
BOOL __xdata audioFrameReady = FALSE;
BOOL sfdDetected;
UINT16 sampleIn;
UINT16 sampleOut;
UINT8 vpp = 0;
UINT8 vppmax = 0;
UINT8 vgagain = 0;
UINT8 adcsamples = 0;
UINT8 k;
UINT8 heartbeat = 0;
UINT8 pwmactbufr = 0;       // indicates which audioOut buffer (0 | 1) is currently being used by the T1 interrupt handler
UINT8 apos = 0;             // audioOutindx value at which buffer A was unavailable
UINT8 bpos = 0;             // audioOutindx value at which buffer B was unavailable

#define AGCSAMPLES 100      // AGC update rate = 12.5 msec

/***********************************************************************************
/// @brief	Interrupt handler for timer T1 (sample rate timer) interrupts.
*/

#pragma vector=T1_VECTOR
__interrupt void T1_IRQ(void){

  INT_GLOBAL_ENABLE(INT_OFF);                 // Make sure no interrupts are served during this interrupt

  T1CC0H = ((timerSampleRate >> 8) & 0xFF);   // re-load the sample rate timer period
  T1CC0L =  (timerSampleRate & 0xFF);

  if (T1CTL & 0x10) {

// Read the ADC and store data into the available audio buffer

    sampleIn = (((INT16) ADCH) << 4);       // Get ADC results - ADCH contains bits 11 - 4
    sampleIn |= ADCL >> 4;                  // bits 7 - 4 of ADCL contain bits 3 - 0 of ADC results
    k = ADCH;                               // save the value of ADCH for use in the AGC code (below)

    ADCCON1 |= 0x40;                        // Start new ADC conversion

#ifdef AGC

    vpp = ((k >> 2) & 0x1F);
    if (vpp < 16)                           // retain magnitude only
      vpp = 15 - vpp;
    else
      vpp = vpp - 16;

    if (vpp > vppmax)
      vppmax = vpp;
    adcsamples++;
    if (adcsamples == AGCSAMPLES) {
      adcsamples = 0;
      if ((vppmax >= 14) && (vgagain > 0))    // Too much gain; reduce if possible
        vgagain--;
      if ((vppmax <= 6) && (vgagain < 3))     // Too little gain; increase if possible
        vgagain++;
      vppmax = 0;
      k = P0 & ~0x60;                         // Set VGA Gain
      k |= (vgagain << 5);
      P0 = k;
    }       // end 'adcsamples' if

#else

    P0 &= ~0x60;                              // set VGA Gain to 0

#endif

    audioIn[activeIn][audioInindx++] = sampleIn;  // copy ADC sample into the active audioIn buffer

    if (audioInindx == AF_LEN) {                  // Make sure sampleCount wraps around
      audioFrameReady = TRUE;                     // Set audio frame ready flag at wraparound
      audioInindx = 0;
      activeIn ^= 0x01;                           // switch buffers
      heartbeat++;
      if (heartbeat == 37) {                      // 37 * 6.75 ms = 249.75 msec
        LED_BLUE_REG ^= LED_BLUE;                 // Toggle the Blue LED
        heartbeat = 0;
      }
    }  // end of 'sampleCount' if

// Output received audio data to PWM
  
    if (pwmactbufr == 0) {                        // Using Buffer A
      if ((rxBufferAvailable & BUFFERA) > 0) 
        sampleOut = audioOut[0][audioOutindx];
      else
        sampleOut = NO_SIGNAL_VALUE;
    }
    else {                                        // Using Buffer B
      if ((rxBufferAvailable & BUFFERB) > 0)
        sampleOut = audioOut[1][audioOutindx];
      else
        sampleOut = NO_SIGNAL_VALUE;
    }

#ifdef LOCALFEEDBACK
    pwmsample = (sampleIn >> 1) + (sampleOut >> 1);
    TIMER1_SET_PWM_PULSE_LENGTH(1, pwmsample << 4);
#else
    TIMER1_SET_PWM_PULSE_LENGTH(1, sampleOut << 4);
#endif

    if (pwmactbufr == 0) {                        // If we are using Buffer A
      if ((rxBufferAvailable & BUFFERA) == 0)     // and Buffer A is marked unavailable
        apos = audioOutindx;                      // mark the 'position'
      if ((rxBufferAvailable & BUFFERB) == 0)     // If we are using Buffer A and Buffer B is unavailable
        bpos = audioOutindx;                      // mark the 'position'
    }

    audioOutindx++;

// When the Master and Slave Timers are in sync, 'apos' will be zero and 'bpos' will be approximately AFLEN/2.
// However, if a packet is lost, Buffer A could be marked as unavialable for the entire packet, in which case 'apos'
// will have a value of AFLEN-1 when audioOutindx = AL_LEN. If 0 < apos < (AFLEN-1), we are using the wrong buffer,
// in which case buffers will not be switched.

    if (audioOutindx == AF_LEN) {                 // Make sure sampleCount wraps around
      audioOutindx = 0;                           // reset the buffer index
      if ((apos == 0) || (apos >= (AF_LEN - 1)))  // if 0 < apos < (AFLEN - 1), buffers will NOT be switched
        pwmactbufr ^= 0x01;                       // switch buffers

// Adjust the period of Timer A to center 'bpos'

      timerSampleRate = NORMAL_SAMPLE_PERIOD;
      if (bpos < SPEEDUP)
        timerSampleRate -= CLOCK_SKEW_STEP_SIZE;
      else
        if (bpos > SLOWDOWN)
          timerSampleRate += CLOCK_SKEW_STEP_SIZE;
      apos = bpos = 0;                            // clear the position markers
    }
  } // end of T1CTL if

  T1CTL &= ~0x10;                                 // Reset T1 interrupt flag
  INT_GLOBAL_ENABLE(INT_ON);                      // Enable other interrupts to be served
}


/***********************************************************************************
  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.
***********************************************************************************/

