This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2533: IR signal capture for learning

Part Number: CC2533

Hello,

I’m working on ir learning with cc2533. But I don’t succed in capturing anything …

My IR_IN is on Port 1 pin 0.

Here is my initialization code :

void initIR_Reception(void)

{

// Peripheral I/O control

PERCFG |= 0x40;//P1.1 Timer1 alternative 2

 

//1st priority: Timer 1 channels 0-1

P2DIR != 0x80;

P2DIR &= ~0x40;

  

// Port 1 function select

P1SEL |= BV(0);//peripheral

// Port 1 direction register

P1DIR &= ~(0x01);

// Set up timer 1 channel 1 to capture mode 4

T1CCTL1 |= BV(6);//enable interrupt at timer 1 channel 1

T1CCTL1 &= ~BV(2);//Capture mode

T1CCTL1 |= BV(1)|BV(0);//Capture on all edges

P1IEN |= BV(0); // enable interrupt at P1_1

T1IE =1;

// Clear timer

// this will activate the output pin so start timer immediately.

T1CNTL = 0;

// Prevent sleep

osal_pwrmgr_task_state(Hal_TaskID, 1);

//(void)osal_set_event(Hal_TaskID, HAL_PWRMGR_HOLD_EVENT);

//(void)osal_set_event(Hal_TaskID, HAL_PWRMGR_CONSERVE_EVENT);

}

I call this function just before getting into osal_start_system().

When an interrupt appears the halProcessIrInterrupt() is supposed to be called.

HAL_ISR_FUNCTION( halKeyPort1Isr, P1INT_VECTOR )

{

HAL_ENTER_ISR();

disableKeypadInt();

if ((P1IFG & HAL_KEY_P1_INTERRUPT_PINS ) != 0x00)

{

      halProcessKeyInterrupt();

 

   #if HAL_KEY

     //Clear Interrupt flag

     P1IFG=(uint8) (~HAL_KEY_P1_INTERRUPT_PINS); //clear interrupt flag

     P1IF=0x00;

   #endif

}

else if ((P1IFG & HAL_IR_P1_INTERRUPT_PINS ) != 0x00)

{

      halProcessIrInterrupt();

 

   #if HAL_IR

     P1IFG = (uint8) (~HAL_IR_P1_INTERRUPT_PINS);

     P1IF = 0;

   #endif  

    

   //T1STAT = ~0x02;//clear timer 1 channel 1

}

     //Clear Interrupt flag

     P1IFG=0x00;

     P1IF=0x00;

 

HAL_EXIT_ISR();

}

But It doesn’t work at all.

Anybody could help me please ?

Thanks you in advance !

  • Hi Emmanuelle,

    We're looking into this. Response may take longer than usual due to vacation season.
  • Hi Emmanuelle,

    Sorry for the delayed response. 

    You can use the attached files to develop your project. (You can add them to the RemoTI-CC253xDK-1.3.1/Components/hal/target/CC2533ARC_RTM/ folder).

    Here are some code snippets to help you:

    1) Initialize:

    //“…
    HIL_Init()
    HIT_Init()
    //…”
    

    2) Transmit (from memory):

    //“…
        // Check if we have IR signal stored for this key
        if (osal_snv_read(nvItemId, sizeof(irSignalCompressed_t), (uint8*)irSignal) == RTI_SUCCESS)
        {
          uint8 fullLength = HIL_SizeOfCompressedSignal(irSignal);
          // Now we have the length, read it with proper length
          if (osal_snv_read(nvItemId, fullLength, (uint8*)irSignal) == RTI_SUCCESS)
          {
            // Uncompress signal
            if (HIL_UncompressSignal(irSignal) == TRUE)
            {
              // Transmit this signal.
              HIT_Transmit((irSignal_t *)irSignal, state);
            }
          }
        }
    //…”

    3) Learn IR signal, and store it:

    //“…
      // Calls to HIL_ block.
      HIL_GetSignalFromCarrier(irSignal, MAXIMUM_NUMBER_OF_TIMING_PAIRS_TO_COLLECT);
    
      HIL_ConsolidateSignal(irSignal);
    
      // Compress signal. Type will change from irSignal_t to irSignalCompressed_t
      uint8 retVal = HIL_CompressSignal(irSignal);
    
      if (retVal == TRUE)
      {
        uint8 fullLength = HIL_SizeOfCompressedSignal((irSignalCompressed_t  *)irSignal);
    
        // Store signal if it is valid.
        if (fullLength > 0)
        {
          osal_snv_write(nvItemId, sizeof(irSignal_t) + fullLength, (uint8*)irSignal);
        }
      }
      else
      {
        // Unsuccessful, try again.
        asm("NOP");
      }
    #if (defined HAL_IR_LEARNER) && (defined HAL_IR_TRANSMIT) && (HAL_IR_TRANSMIT == TRUE)
      /* (Re-)Initialize hardware for IR generation*/
      HIT_Init();
    #endif //(defined HAL_IR_LEARNER) && (defined HAL_IR_TRANSMIT)
    //…”
    

    hal_ir_learner.c
    /**************************************************************************************************
        Filename:       hal_ir_learner.c
        Revised:        $Date: 2016-05-19 15:01:47 -0700 (Thu, 19 May 2016) $
        Revision:       $Revision: NA $
    
        Description:
    
       This file contains the IR learner feature
    
      Copyright 2008-2016 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.
    **************************************************************************************************/
    
    /* ------------------------------------------------------------------------------------------------
     *                                          Includes
     * ------------------------------------------------------------------------------------------------
     */
    
    // Module includes
    #include "hal_ir_learner.h"
    #include "hal_drivers.h"
    #include "OSAL.h"
    
    #ifdef HAL_IR_LEARNER
    
    /* ------------------------------------------------------------------------------------------------
     *                                           Typedefs
     * ------------------------------------------------------------------------------------------------
     */
    #define HIL_STATE_START         0
    #define HIL_STATE_REPEAT        1
    #define HIL_STATE_RELEASE       2
    
    /* ------------------------------------------------------------------------------------------------
     *                                           Local Functions
     * ------------------------------------------------------------------------------------------------
     */
    void hil_setupForCarrier( void );
    void hil_setupForSignal( void );
    void hil_getSignal( void );
    void hil_findSilence( void );
    uint8 hil_relaxed_memcmp(uint16 *pA, uint16 *pB, uint8 len);
    
    /* ------------------------------------------------------------------------------------------------
     *                                           Local Variables
     * ------------------------------------------------------------------------------------------------
     */
    //static uint8 carrierEdges[MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT] = {0};
    uint8 *carrierEdges = NULL;
    
    /* ------------------------------------------------------------------------------------------------
     *                                           Global Variables
     * ------------------------------------------------------------------------------------------------
     */
    
    /* ------------------------------------------------------------------------------------------------*/
    void hil_setupForCarrier( void )
    {
      SET_ALTERNATIVE_OPTION_TIMER3();
    
      SETUP_P1_6_PFIO();
    
      INIT_TIMER3_CHANNEL_0();
    }
    
    void hil_setupForSignal( void )
    {
      SET_ALTERNATIVE_OPTION_TIMER3();
    
      SETUP_P1_7_PFIO();
    
      INIT_TIMER3_CHANNEL_1();
    }
    
    void HIL_Init()
    {
      // Disable IR learning circuit by default
      INIT_IR_LEARNER_PIN();
    }
    
    #pragma optimize=speed
    uint8 hil_carrierAndSignalTimeCritical(irSignal_t *irSignal, uint8 maxLength)
    {
      uint8 signalIndex = 0, detectedRepeat = FALSE;
      uint16 overflowCount = 0;
      uint16 releaseLastSpace = 0;
      uint8 detectedState = HIL_STATE_START;
      uint8 carrierCount = MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT;
      uint8 isMark = TRUE;
      irLearningTimingType_t *irLearnedSignal = (irLearningTimingType_t *)&irSignal->signal[0];
      irLearnedSignal[signalIndex].mark = 0;
      irLearnedSignal[signalIndex].spaceRemainder = 0;
      irLearnedSignal[signalIndex].spaceOverflow = 0;
    
      HIL_DEBUG_SET(2, 4, 0);
      // Make sure we start detecting start signal, so look for silence
      while (1)
      {
        if (TIMER3_CHANNEL_0_INTERRUPT())
        {
          // Reset timer for every edge, so that overflow happens for a
          // TRUE end of signal
          overflowCount = 0;
          CLEAR_TIMER3_VALUE();
          CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
        }
        if (TIMER3_OVERFLOW_INTERRUPT())
        {
          overflowCount++;
          CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
          if (overflowCount > MAXIMUM_NUMBER_OF_CARRIER_OVERFLOWS_TO_COLLECT_FOR_REPEAT_PERIOD)
          {
            HIL_DEBUG_SET(2, 4, 1);
            // We got enough overflow. We have found silence.
            break;
          }
        }
      }
    
      CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
      // Wait for first edge before we begin to count carrier pulses
      while (!(TIMER3_CHANNEL_0_INTERRUPT())) {}
      HIL_DEBUG_SET(2, 3, 0);
      /*********************************************************
       * The following is time critical
       ********************************************************/
      // Clear counter so that we get a count from 0
      CLEAR_TIMER3_VALUE();
      CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
      CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
      while (signalIndex < maxLength) {
        // Now count edges
        while (!(TIMER3_CHANNEL_0_AND_OVERFLOW_INTERRUPT())) {}
        // Clear counter so that next count is from 0
        CLEAR_TIMER3_VALUE();
    //    HIL_DEBUG_TOGGLE(2, 3);
        // Check if this is a valid edge. It is a valid edge
        if (TIMER3_OVERFLOW_INTERRUPT()) {
          if (isMark == TRUE)
          {
            HIL_DEBUG_SET(2, 4, 1);
            // Change to Space
            isMark = FALSE;
            irLearnedSignal[signalIndex].spaceRemainder = 0;
            irLearnedSignal[signalIndex].spaceOverflow = 0;
          }
          // Overflows are counted as space
          irLearnedSignal[signalIndex].spaceOverflow++;
          if (irLearnedSignal[signalIndex].spaceOverflow > MAXIMUM_NUMBER_OF_CARRIER_OVERFLOWS_TO_COLLECT_FOR_NORMAL_SIGNAL)
          {
            detectedRepeat = TRUE;
            // Now we are in the repeat part of the signal.
            if (irLearnedSignal[signalIndex].spaceOverflow > MAXIMUM_NUMBER_OF_CARRIER_OVERFLOWS_TO_COLLECT_FOR_REPEAT_PERIOD)
            {
              // When we have found both start and repeat, there may not be a release
              if (detectedState >= HIL_STATE_RELEASE)
              {
                // Release will now not have a correct last space. Use the last correctly recorded
                irLearnedSignal[signalIndex++].spaceOverflow = releaseLastSpace;
                irSignal->releaseLength = signalIndex - (irSignal->startLength + irSignal->repeatLength);
                break;
              }
            }
          }
          CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
        } else {
          // Detected a good edge
          CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
          if (isMark == FALSE)
          {
            HIL_DEBUG_SET(2, 4, 0);
    //        // Add last part of space
            irLearnedSignal[signalIndex].spaceRemainder = TIMER3_CHANNEL_0_TICK_VALUE();
            // Change to Mark
            isMark = TRUE;
            signalIndex++;
            irLearnedSignal[signalIndex].mark = 0;
    
            if (detectedRepeat == TRUE)
            {
              if (detectedState < HIL_STATE_RELEASE)
              {
                if (detectedState == HIL_STATE_START)
                {
                  HIL_DEBUG_SET(2, 3, 1);
                  // We can now store Start signal
                  irSignal->startLength = signalIndex;
                }
                else
                {
                  HIL_DEBUG_SET(2, 3, 0);
                  // We can now store Repeat signal
                  irSignal->repeatLength = signalIndex - irSignal->startLength;
                }
              }
              else
              {
                HIL_DEBUG_TOGGLE(2, 3);
                signalIndex = (irSignal->startLength + irSignal->repeatLength);
                irLearnedSignal[signalIndex].mark = 0;
                irLearnedSignal[signalIndex].spaceRemainder = 0;
                irLearnedSignal[signalIndex].spaceOverflow = 0;
                releaseLastSpace = irLearnedSignal[signalIndex - 1].spaceOverflow;
              }
              // Change state
              detectedState++;
              detectedRepeat = FALSE;
            }
          }
          else
          {
            if (carrierCount > 0)
            {
              // Store counter value in array
              carrierCount--;
              carrierEdges[carrierCount] = TIMER3_CHANNEL_0_TICK_VALUE();
            }
            else
            {
              asm("NOP");
            }
            // Count carrier pulses in mark
            irLearnedSignal[signalIndex].mark++;
          }
        }
      }
      /*********************************************************
       * End of time critical part
       ********************************************************/
    
      return signalIndex;
    }
    
    #pragma optimize=speed
    uint8 hil_carrierTimeCritical()
    {
      uint8 carrierCount = MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT;
    
      // Wait for first edge before we begin to count carrier pulses
      while (!(TIMER3_CHANNEL_0_INTERRUPT())) {}
      HIL_DEBUG_SET(2, 4, 1);
      /*********************************************************
       * The following is time critical
       ********************************************************/
      // Clear counter so that we get a count from 0
      CLEAR_TIMER3_VALUE();
      CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
      CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
      while (carrierCount > 0) {
        // Now count edges
        while (!(TIMER3_CHANNEL_0_AND_OVERFLOW_INTERRUPT())) {}
        HIL_DEBUG_TOGGLE(2, 3);
        // Check if this is a valid edge. It is a valid edge
        if (TIMER3_OVERFLOW_INTERRUPT()) {
          // We do not accept overflow counts
          break;
        } else {
          // Detected a good edge
          // Clear counter so that next count is from 0
          CLEAR_TIMER3_VALUE();
          HIL_DEBUG_TOGGLE(2, 4);
          CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
    
          // Store counter value in array
          carrierCount--;
          carrierEdges[carrierCount] = TIMER3_CHANNEL_0_TICK_VALUE();
        }
      }
      /*********************************************************
       * End of time critical part
       ********************************************************/
    
      return carrierCount;
    }
    
    uint8 HIL_GetCarrier( void )
    {
      uint8 x;
      uint8 carrierCount = MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT;
    
      // Enable IR learning circuit
      ENABLE_IR_LEARNER_CIRCUIT();
    
      HIL_DEBUG_SETUP();
      HIL_DEBUG_SET(2, 4, 1);
      HIL_DEBUG_SET(2, 3, 1);
      hil_setupForCarrier();
    
      // Get buffer to collect and calculate Carrier
      carrierEdges = (uint8*)osal_mem_alloc(MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT);
      if (carrierEdges != NULL)
      {
        // We do not accept any interrupts during signal detection.
        HAL_ENTER_CRITICAL_SECTION(x);
    
        CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
        CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
        START_TIMER3_CARRIER();
        HIL_DEBUG_SET(2, 4, 0);
    
        carrierCount = hil_carrierTimeCritical();
    
        CLEAR_TIMER3();
        CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
        CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
    
        HAL_EXIT_CRITICAL_SECTION(x);
    
        // If we have collected enough carrier pulses, calculate the average
        if (carrierCount < (MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT - MINIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT))
        {
          uint16 carrierAcc = 0;
          uint8 i;
          for (i = carrierCount; i < MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT; i++)
          {
            carrierAcc += carrierEdges[i];
          }
          carrierAcc /= (MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT - carrierCount);
          carrierCount = CARRIER_ADJUSTMENT(carrierAcc);
        } else {
          carrierCount = 0;
        }
    
        osal_mem_free(carrierEdges);
      }
    
      // Disable IR learning circuit
      DISABLE_IR_LEARNER_CIRCUIT();
    
      return carrierCount;
    }
    
    void HIL_GetSignalFromCarrier( irSignal_t *irSignal, uint8 maxLength )
    {
      uint8 x, carrierCount = 0;
    
      // Enable IR learning circuit
      ENABLE_IR_LEARNER_CIRCUIT();
    
      HIL_DEBUG_SETUP();
      HIL_DEBUG_SET(2, 4, 1);
      HIL_DEBUG_SET(2, 3, 1);
      hil_setupForCarrier();
    
      // Get buffer to collect and calculate Carrier
      carrierEdges = (uint8*)osal_mem_alloc(MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT);
      if (carrierEdges != NULL)
      {
        // We do not accept any interrupts during signal detection.
        HAL_ENTER_CRITICAL_SECTION(x);
    
        CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
        CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
        START_TIMER3_CARRIER();
        TIMER3_CAPTURE_ON_RISING_EDGE(0);
    
        hil_carrierAndSignalTimeCritical(irSignal, maxLength);
    
        CLEAR_TIMER3();
        CLEAR_TIMER3_CHANNEL_0_INTERRUPT_FLAG();
        CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
    
        HAL_EXIT_CRITICAL_SECTION(x);
    
        /*********************************************************
        * Calculate carrier from mean of multiple carriers
        ********************************************************/
        // If we have collected enough carrier pulses, calculate the average
        if (carrierCount < (MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT - MINIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT))
        {
          uint16 carrierAcc = 0;
          uint8 i;
          for (i = carrierCount; i < MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT; i++)
          {
            carrierAcc += carrierEdges[i];
          }
          carrierAcc /= (MAXIMUM_NUMBER_OF_CARRIER_PULSES_TO_COLLECT - carrierCount);
          irSignal->carrier = CARRIER_ADJUSTMENT(carrierAcc);
    
          /*********************************************************
          * Convert to only carrier pulse count (mark is already ok)
          ********************************************************/
          // Convert mark and spaces to number of carrier pulses
          uint8 fullLength = irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength;
          // Temporary buffer to change from 32us ticks to number of carrier pulses
          // Carrier is given in 0.125us ticks. This is a factor of 256 difference.
          // Since spaceLo already is on this basis we can simply read spaceLo and spaceHi as a 24 bit value
          irLearningTimingType_t *irLearnedSignal = (irLearningTimingType_t *)&irSignal->signal[0];
          uint32 convertedTime = 0;
          for (i = 0; i < fullLength; i++)
          {
            // Shift Mark since it's been aligned 5 bytes
            irSignal->signal[i<<1] = irLearnedSignal[i].mark;
            // Copy to uint32 variable so we don't overwrite information
            convertedTime = *((uint32*)(&irLearnedSignal[i].spaceRemainder)) & 0x00FFFFFF;
            convertedTime /= irSignal->carrier;
            irSignal->signal[(i<<1) + 1] = (uint16)convertedTime;
          }
          /*********************************************************
          * End of conversion
          ********************************************************/
        } else {
          irSignal->carrier = 0;
        }
    
        osal_mem_free(carrierEdges);
      }
    }
    
    uint8 HIL_GetSignal( irSignal_t *irSignal, uint8 maxLength )
    {
      uint8 x, signalIndex = 0, detectedRepeat = FALSE, overflowCount = 0;
      uint16 releaseLastSpace = 0;
      uint8 detectedState = HIL_STATE_START;
      uint8 *signalLo = (uint8 *)&irSignal->signal[0];
      uint8 *signalHi = ((uint8 *)&irSignal->signal[0]) + 1;
    
      // Enable IR learning circuit
      ENABLE_IR_LEARNER_CIRCUIT();
    
      HIL_DEBUG_SETUP();
      hil_setupForSignal();
    
      // We do not accept any interrupts during signal detection.
      HAL_ENTER_CRITICAL_SECTION(x);
    
    //  uint8 i, tempBufIdx = 0;
    //  uint8 *pSigBuf[3] = {0}, tempSigBufLength[3] = {0};
    //  // Try to get both start and repeat
    //  while (tempBufIdx < 2)
    //  {
    //    if (signalLength > 0)
    //    {
    //      // Dynamically allocate memory to store this temporary signal
    //      tempSigBufLength[tempBufIdx] = signalLength * sizeof(uint16);
    //      pSigBuf[tempBufIdx] = osal_mem_alloc(tempSigBufLength[tempBufIdx]);
    //      tempBufIdx++;
    //    }
    //  }
    
      HIL_DEBUG_SET(2, 4, 0);
      HIL_DEBUG_SET(2, 3, 0);
    
      // Make sure we detect start signal first
      hil_findSilence();
    
      // Start timer ready for signal
      START_TIMER3_SIGNAL();
      CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
      // Wait for first edge before we begin to measure pulses
      TIMER3_CAPTURE_ON_RISING_EDGE(1);
      while (!(TIMER3_CHANNEL_1_INTERRUPT())) {}
      HIL_DEBUG_SET(2, 4, 0);
      HIL_DEBUG_SET(2, 3, 0);
      /*********************************************************
       * The following is time critical
       ********************************************************/
      // Clear counter so that we get a count from 0
      CLEAR_TIMER3_VALUE();
      CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
      CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
      // We want to measure both edges from here on
      TIMER3_CAPTURE_ON_BOTH_EDGES(1);
      while (signalIndex < maxLength)
      {
        // Now count edges
        while (!(TIMER3_CHANNEL_1_AND_OVERFLOW_INTERRUPT())) {}
        // Check if this is a valid edge. It is a valid edge
        if (TIMER3_OVERFLOW_INTERRUPT())
        {
          HIL_DEBUG_TOGGLE(2, 3);
          // We count overflow interrupts, up to a predefined maximum
          overflowCount++;
          if (overflowCount > MAXIMUM_NUMBER_OF_OVERFLOWS_TO_COLLECT_FOR_NORMAL_SIGNAL)
          {
            detectedRepeat = TRUE;
            // Now we are in the repeat part of the signal.
            if (overflowCount > MAXIMUM_NUMBER_OF_OVERFLOWS_TO_COLLECT_FOR_REPEAT_PERIOD)
            {
              // When we have found both start and repeat, there may not be a release
              if (detectedState >= HIL_STATE_RELEASE)
              {
                // Release will now not have a correct last space. Use the last correctly recorded
                irSignal->signal[signalIndex++] = releaseLastSpace;
                irSignal->releaseLength = signalIndex - (irSignal->startLength + irSignal->repeatLength);
                break;
              }
            }
          }
          CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
        }
        if (TIMER3_CHANNEL_1_INTERRUPT())
        {
          HIL_DEBUG_TOGGLE(2, 4);
          HIL_DEBUG_SET(2, 3, HIL_DEBUG_GET(2, 4));
          // Detected a good edge
          // Clear counter so that next count is from 0
          CLEAR_TIMER3_VALUE();
          CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
          // We should normally not have to clear the overflow flag here, but if
          // signal length is a single tick below overflow, then there is a good
          // chance the overflow will happen while we are storing the value.
          // This is ok. There will be jitter from capture until timer is cleared,
          // but this is much smaller than a single tick.
          CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
    
          // Store counter value in array
          *signalLo = TIMER3_CHANNEL_1_TICK_VALUE();
          *signalHi = overflowCount;
          overflowCount = 0;
    
          // Increment and store pointers and counter
          signalLo += 2;
          *signalLo = 0;
          signalHi += 2;
          *signalHi = 0;
          signalIndex++;
    
          if (detectedRepeat == TRUE)
          {
            if (detectedState < HIL_STATE_RELEASE)
            {
              if (detectedState == HIL_STATE_START)
              {
                // We can now store Start signal
                irSignal->startLength = signalIndex;
              }
              else
              {
                // We can now store Repeat signal
                irSignal->repeatLength = signalIndex - irSignal->startLength;
              }
            }
            else
            {
              uint8 lengthToRewind = signalIndex - (irSignal->startLength + irSignal->repeatLength);
              // Rewind pointers and counters
              signalLo -= (lengthToRewind * sizeof(uint16));
              signalHi -= (lengthToRewind * sizeof(uint16));
              releaseLastSpace = irSignal->signal[signalIndex - 1];
              signalIndex -= lengthToRewind;
            }
            // Change state
            detectedState++;
            detectedRepeat = FALSE;
          }
        }
      }
      /*********************************************************
       * End of time critical part
       ********************************************************/
      CLEAR_TIMER3();
      CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
      CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
    
      HIL_DEBUG_SET(2, 4, 1);
      HIL_DEBUG_SET(2, 3, 1);
    
      HAL_EXIT_CRITICAL_SECTION(x);
    
      // Disable IR learning circuit
      DISABLE_IR_LEARNER_CIRCUIT();
    
      return signalIndex;
    }
    
    void HIL_ConvertSignal( irSignal_t *irSignal )
    {
      // Convert mark and spaces to number of carrier pulses
      uint8 i = 0, fullLength = irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength;
      // Temporary buffer to change from 4us ticks to number of carrier pulses
      // Carrier is given in 0.125us ticks. This is a factor of 32 difference.
      // 32 --> 2^5
      uint32 convertedTime = 0;
      for (i = 0; i < fullLength; i++)
      {
        convertedTime = irSignal->signal[i];
        irSignal->signal[i] = (convertedTime << 5) / irSignal->carrier;
    //    // We need Mark + Period, so combine Mark+Space=Period. Place it in Space
    //    // so that we don't have to recalculate Mark
    //    if (i & 1)
    //    {
    //      irSignal->signal[i] += irSignal->signal[i - 1];
    //    }
      }
    }
    
    void HIL_ConsolidateSignal( irSignal_t *irSignal )
    {
      uint8 originalStartLength = irSignal->startLength;
      // Start, repeat and release could all be the same signal after detection.
      // To minimize memory usage try to consolidate signals.
      // Start by comparing lengths
      if ( (irSignal->startLength == irSignal->repeatLength) &&
           (hil_relaxed_memcmp(&irSignal->signal[0],
                        &irSignal->signal[(irSignal->startLength << 1)],
                        (irSignal->startLength << 1)) == 0) )
      {
        // They are identical
        // Truncate start simply by setting start length to zero
        irSignal->startLength = 0;
      }
      // Now compare repeat and release
      if ( (irSignal->repeatLength == irSignal->releaseLength) &&
          (hil_relaxed_memcmp(&irSignal->signal[(originalStartLength << 1)],
                       &irSignal->signal[(originalStartLength << 1) + (irSignal->repeatLength << 1)],
                       (irSignal->repeatLength << 1)) == 0) )
      {
        // They are identical
        // Truncate start simply by setting start length to zero
        irSignal->releaseLength = 0;
      }
      // In case there were any changes, move release to correct location
      if (irSignal->startLength == 0)
      {
        osal_memcpy(&irSignal->signal[(irSignal->repeatLength << 1)],
               &irSignal->signal[(originalStartLength << 1) + (irSignal->repeatLength << 1)],
               (irSignal->releaseLength << 1));
      }
    }
    
    // Buffer to store up to 16 timingTypes
    static irTimingType_t timingTypes[16];
    static uint8 numberOfTypes = 0;
    void hil_clearTimingType()
    {
      osal_memset((uint8*)&timingTypes[0], 0, sizeof(timingTypes) * sizeof(irTimingType_t));
      numberOfTypes = 0;
    }
    void hil_copyTimingTypes(irSignalCompressed_t *pCompressed)
    {
      pCompressed->numberOfTypes = numberOfTypes;
      osal_memcpy((uint8*)pCompressed->signal, (uint8*)&timingTypes[0], pCompressed->numberOfTypes * sizeof(irTimingType_t));
    }
    int8 hil_getTimingTypeIndex(uint16 mark, uint16 space)
    {
      short diff = 0;
      int8 index = 0;
      // Search for timing type, add it to list if it's not there
      for (index = 0; index < numberOfTypes; index++)
      {
        // Calculate difference. We accept up to 2 carrier pulses error
        diff = MARK_ADJUSTMENT(mark) - timingTypes[index].mark;
        // Check absolute difference
        diff = (diff < 0) ? -diff : diff;
        if (diff <= MAXIMUM_CARRIER_TICK_ERROR)
        {
          // Mark match, check space
          diff = SPACE_ADJUSTMENT(space) - timingTypes[index].space;
          // Check absolute difference
          diff = (diff < 0) ? -diff : diff;
          if (diff <= MAXIMUM_CARRIER_TICK_ERROR)
          {
            // Space also match, return this index
            return index;
          }
        }
      }
      if (index == numberOfTypes)
      {
        if (index < MAXIMUM_NUMBER_OF_TIMING_TYPES)
        {
          // Add it to list
          timingTypes[index].mark = MARK_ADJUSTMENT(mark);
          timingTypes[index].space = SPACE_ADJUSTMENT(space);
          numberOfTypes = index + 1;
        }
        else
        {
          // We cannot handle this signal. Capture again
          return -1;
        }
      }
    
      return index;
    }
    uint8 HIL_SizeOfCompressedSignal(irSignalCompressed_t *irSignalCompressed)
    {
      uint8 size = 0;
      // Add timing type
      size += irSignalCompressed->numberOfTypes * sizeof(irTimingType_t);
      if (size)
      {
        // Add signal, length is number of bits, each bit consume one nibble.
        size += (irSignalCompressed->startLength + irSignalCompressed->repeatLength + irSignalCompressed->releaseLength) >> 1;
        // Add header
        size += IR_SIGNAL_COMPRESSED_HEADER_SIZE;
      }
      return size;
    }
    
    uint8 HIL_UncompressSignal( irSignalCompressed_t *irSignalCompressed )
    {
      irSignal_t *irSignal = (irSignal_t *)irSignalCompressed;
      // Copy timing types so that we can reuse RAM
      osal_memcpy((uint8*)&timingTypes[0], (uint8*)irSignalCompressed->signal, irSignalCompressed->numberOfTypes * sizeof(irTimingType_t));
      // Then copy signal to a buffer, again to reuse RAM
      uint8 *pSignal = (uint8*)osal_mem_alloc((irSignalCompressed->startLength + irSignalCompressed->repeatLength + irSignalCompressed->releaseLength) >> 1);
      if (pSignal == NULL)
      {
        return FALSE;
      }
      else
      {
        // Copy signal
        osal_memcpy(pSignal,
                    &irSignalCompressed->signal[irSignalCompressed->numberOfTypes * sizeof(irTimingType_t)],
                    (irSignalCompressed->startLength + irSignalCompressed->repeatLength + irSignalCompressed->releaseLength) >> 1);
      }
      // Now uncompress signal
      uint8 i = 0, nibbleIndex = 0, index = 0;
      for (nibbleIndex = 0; nibbleIndex < irSignal->startLength; nibbleIndex++)
      {
        if (nibbleIndex & 1)
        {
          index = (pSignal[nibbleIndex>>1] & 0x0F);
        }
        else
        {
          index = (((pSignal[nibbleIndex>>1] & 0xF0) >> 4) & 0x0F);
        }
        // First mark
        irSignal->signal[i++] = timingTypes[index].mark;
        // Then period (mark + space)
        irSignal->signal[i++] = timingTypes[index].mark + timingTypes[index].space;
      }
      for (nibbleIndex = irSignal->startLength; nibbleIndex < (irSignal->startLength + irSignal->repeatLength); nibbleIndex++)
      {
        if (nibbleIndex & 1)
        {
          index = (pSignal[nibbleIndex>>1] & 0x0F);
        }
        else
        {
          index = (((pSignal[nibbleIndex>>1] & 0xF0) >> 4) & 0x0F);
        }
        // First mark
        irSignal->signal[i++] = timingTypes[index].mark;
        // Then period (mark + space)
        irSignal->signal[i++] = timingTypes[index].mark + timingTypes[index].space;
      }
      for (nibbleIndex = (irSignal->startLength + irSignal->repeatLength); nibbleIndex < (irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength); nibbleIndex++)
      {
        if (nibbleIndex & 1)
        {
          index = (pSignal[nibbleIndex>>1] & 0x0F);
        }
        else
        {
          index = (((pSignal[nibbleIndex>>1] & 0xF0) >> 4) & 0x0F);
        }
        // First mark
        irSignal->signal[i++] = timingTypes[index].mark;
        // Then period (mark + space)
        irSignal->signal[i++] = timingTypes[index].mark + timingTypes[index].space;
      }
      // We count mark and period separately in the IR generator driver, so shift them here
      irSignal->startLength <<=1;
      irSignal->repeatLength <<=1;
      irSignal->releaseLength <<=1;
    
      osal_mem_free(pSignal);
    
      return TRUE;
    }
    
    uint8 HIL_CompressSignal( irSignal_t *irSignal )
    {
      irSignalCompressed_t *pCompressed = (irSignalCompressed_t *)irSignal;
      irTimingType_t *pTimingTypes = (irTimingType_t *)&irSignal->signal[0];
      uint8 i, index;
    
      // Clear buffers before processing
      hil_clearTimingType();
    
      // Find timing types, ignore index for now
      // TODO: Can increase speed by using index immediately. This would require
      // separate buffer to avoid overwriting, or copying later
      for (i = 0; i < irSignal->startLength; i++)
      {
        if (hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space) < 0)
        {
          // Too many timing types discovered. Exit now, with error
          return FALSE;
        }
      }
      for (i = irSignal->startLength; i < (irSignal->startLength + irSignal->repeatLength); i++)
      {
        if (hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space) < 0)
        {
          // Too many timing types discovered. Exit now, with error
          return FALSE;
        }
      }
      for (i = (irSignal->startLength + irSignal->repeatLength); i < (irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength); i += 2)
      {
        if (hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space) < 0)
        {
          // Too many timing types discovered. Exit now, with error
          return FALSE;
        }
      }
      // Allocate memory for bitstream
      uint8 *pSignal = (uint8*)osal_mem_alloc((irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength) >> 1);
      osal_memset(pSignal, 0, (irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength) >> 1);
      uint8 nibbleIndex = 0, startLength, repeatLength;
      // Then fill signal
      for (i = 0; i < irSignal->startLength; i++)
      {
        index = hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space);
        if (nibbleIndex & 1)
        {
          pSignal[nibbleIndex>>1] |= (index & 0x0F);
          nibbleIndex++;
        }
        else
        {
          pSignal[nibbleIndex>>1] |= (((index & 0x0F) << 4) & 0xF0);
          nibbleIndex++;
        }
      }
      startLength = nibbleIndex;
      for (i = irSignal->startLength; i < (irSignal->startLength + irSignal->repeatLength); i++)
      {
        index = hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space);
        if (nibbleIndex & 1)
        {
          pSignal[nibbleIndex>>1] |= (index & 0x0F);
          nibbleIndex++;
        }
        else
        {
          pSignal[nibbleIndex>>1] |= (((index & 0x0F) << 4) & 0xF0);
          nibbleIndex++;
        }
      }
      repeatLength = nibbleIndex - startLength;
      for (i = (irSignal->startLength + irSignal->repeatLength); i < (irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength); i++)
      {
        index = hil_getTimingTypeIndex(pTimingTypes[i].mark, pTimingTypes[i].space);
        if (nibbleIndex & 1)
        {
          pSignal[nibbleIndex>>1] |= (index & 0x0F);
          nibbleIndex++;
        }
        else
        {
          pSignal[nibbleIndex>>1] |= (((index & 0x0F) << 4) & 0xF0);
          nibbleIndex++;
        }
      }
      irSignal->startLength = startLength;
      irSignal->repeatLength = repeatLength;
      irSignal->releaseLength = nibbleIndex - startLength - repeatLength;
      // Now copy timing types to buffer
      hil_copyTimingTypes(pCompressed);
      // Then copy signal
      osal_memcpy(&pCompressed->signal[pCompressed->numberOfTypes * sizeof(irTimingType_t)],
                  pSignal,
                  (irSignal->startLength + irSignal->repeatLength + irSignal->releaseLength) >> 1);
      osal_mem_free(pSignal);
    
      return TRUE;
    }
    
    uint8 hil_relaxed_memcmp(uint16 *pA, uint16 *pB, uint8 len)
    {
      uint8 i;
      short diff;
    
      for (i = 0; i < len; i++)
      {
        // Calculate difference. We accept up to 2 carrier pulses error
        diff = pA[i] - pB[i];
        // Check absolute difference
        diff = (diff < 0) ? -diff : diff;
        if (diff > MAXIMUM_CARRIER_TICK_ERROR)
        {
          return (uint8) diff;
        }
      }
    
      return 0;
    }
    
    void hil_findSilence()
    {
      uint8 overflowCount = 0;
    
      START_TIMER3_FIND_START();
      // Measure only falling edges, to get time between active parts of signal
      TIMER3_CAPTURE_ON_RISING_EDGE(1);
      CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
      CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
    
      // Wait for first period of silence exceeding 32ms
      // We are running a timer @8MHz which gives overflow after 32ms
      while (1)
      {
        if (TIMER3_CHANNEL_1_INTERRUPT())
        {
          // Reset timer for every edge, so that overflow happens for a
          // TRUE end of signal
          overflowCount = 0;
          HIL_DEBUG_TOGGLE(2, 3);
          CLEAR_TIMER3_VALUE();
          CLEAR_TIMER3_CHANNEL_1_INTERRUPT_FLAG();
        }
        if (TIMER3_OVERFLOW_INTERRUPT())
        {
          overflowCount++;
          CLEAR_TIMER3_OVERFLOW_INTERRUPT_FLAG();
          if (overflowCount > MAXIMUM_NUMBER_OF_OVERFLOWS_TO_COLLECT_FOR_NORMAL_SIGNAL)
          {
            HIL_DEBUG_SET(2, 4, 1);
            HIL_DEBUG_SET(2, 3, 1);
            // We got enough overflow. We have found silence.
            break;
          }
        }
      }
    }
    #endif //HAL_IR_LEARNER
    
    /**************************************************************************************************
    **************************************************************************************************/
    
    hal_ir_learner.h
    hal_ir_transmit.c
    /**************************************************************************************************
      Filename:       hal_ir_transmit.c
      Revised:        $Date: 2016-05-20 17:32:20 -0700 (Fri, 20 May 2016) $
      Revision:       $Revision: NA $
    
      Description:    This file contains an implementation of an IR signal generation
                      driver
    
                      The module requires HAL_IR_TRANSMIT compile flag to be set to TRUE to be built in.
    
                      The distinct feature of this driver is that it minimizes interaction with CPU
                      by relying on DMA to reprogram a timer to generate signals.
    
                      The output signal will be generated onto Port 1 Pin 1.
                      The driver will use two DMA channels, Timer 1 and Timer 3,
                      and hence it will have conflict with any other drivers that uses the same
                      resources. (Note that AES driver must not be configured to use DMA).
    
                      Timer 3 is used to generate carrier pulse signals while
                      Timer 1 is used to generate bit signals on top of the carrier signals.
    
    
      Copyright 2013 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.
    **************************************************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    
    #include "hal_ir_transmit.h"
    #include "hal_ir_common.h"
    #include "hal_drivers.h"
    #include "hal_dma.h"
    #include "OSAL.h"
    
    #if (defined HAL_IR_TRANSMIT) && (HAL_IR_TRANSMIT == TRUE)
    /******************************************************************************
     * CONSTANTS
     */
    
    enum {
      FIRST_FRAME,
      REPEAT_FRAME,
      RELEASE_FRAME
    };
    
    /******************************************************************************
     * TYPEDEFS
     */
    typedef struct {
      uint8 carrier;
      uint8 length;
      uint16 *signal;
      irSignal_t *originalSignal;
    } hitIrSignal_t;
    
    /******************************************************************************
     * LOCAL VARIABLES
     */
    
    static enum {
      HIT_STATE_IDLE,
      HIT_STATE_TX,
      HIT_STATE_TX_RELEASE
    } halIrTransmitState;
    
    halDMADesc_t *pDmaDescCc0;
    halDMADesc_t *pDmaDescCc1;
    static enum {
      HIT_RELEASE_NOT_PENDING,
      HIT_RELEASE_PENDING,
      HIT_RELEASE_EMPTY_PENDING,
    } pendingRelease;
    
    static hitIrSignal_t currentIrSignal = {0};
    
    /******************************************************************************
     * LOCAL FUNCTIONS
     */
    static void startIrGen( void );
    static void HalIrGenT1Isr( void );
    
    uint8 HIT_Transmit(irSignal_t *irSignal, rcKeyState_t state)
    {
      HIL_DEBUG_SETUP();
    
      uint8 returnVal = FALSE;
      if (state == RC_KEY_STATE_PRESSED)
      {
        // Press
        if ( halIrTransmitState == HIT_STATE_IDLE )
        {
          // Cannot allow sleep during IR
          halDriverBlockPM(HAL_LED_IR_ENGINE_BLOCK_PM);
    
          halIrTransmitState = HIT_STATE_TX;
    
          currentIrSignal.carrier = irSignal->carrier;
          currentIrSignal.length = (irSignal->startLength) ? irSignal->startLength : irSignal->repeatLength;
          currentIrSignal.signal = &irSignal->signal[0];
          currentIrSignal.originalSignal = irSignal;
          startIrGen();
    
          returnVal = TRUE;
        }
      }
      else if (state == RC_KEY_STATE_NOT_PRESSED)
      {
        // Release
        if ( halIrTransmitState == HIT_STATE_TX )
        {
          // Check if release exist
          if ( currentIrSignal.originalSignal->releaseLength )
          {
            pendingRelease = HIT_RELEASE_PENDING;
          }
          else
          {
            pendingRelease = HIT_RELEASE_EMPTY_PENDING;
          }
    
          returnVal = TRUE;
        }
      }
    
      return returnVal;
    }
    
    /******************************************************************************
     * @fn      startIrGen
     *
     * @brief   Generate repeat IR signal
     *
     * input parameters
     *
     * @param   irBufSize - Size of the command containing the IR signal
     *
     * output parameters
     *
     * None.
     *
     * @return  None.
     *
     */
    static void startIrGen()
    {
      halIntState_t intState;
    
      // Setup carrier
      T3CC0 = currentIrSignal.carrier;
      // 75% active
      T3CC1 = (currentIrSignal.carrier >> 1) + (currentIrSignal.carrier >> 2);
      // Setup initial bit
      T1CC0L = LO_UINT16(currentIrSignal.signal[1]);  // Period
      T1CC0H = HI_UINT16(currentIrSignal.signal[1]);
      T1CC1L = LO_UINT16(currentIrSignal.signal[0]);  // Mark
      T1CC1H = HI_UINT16(currentIrSignal.signal[0]);
    
      // Set data length. Divide length by two since it denotes Mark and Period combined
      HAL_DMA_SET_LEN(pDmaDescCc0, (currentIrSignal.length >> 1) - 1);
      HAL_DMA_SET_LEN(pDmaDescCc1, (currentIrSignal.length >> 1) - 1);
    
      // Set source data stream.
      HAL_DMA_SET_SOURCE( pDmaDescCc0, &currentIrSignal.signal[3] );  // Period
      HAL_DMA_SET_SOURCE( pDmaDescCc1, &currentIrSignal.signal[2] );  // Mark
    
      // ARM both DMA channels
      HAL_DMA_CLEAR_IRQ(HAL_IRGEN_DMA_CH_CC0);
      HAL_DMA_ARM_CH(HAL_IRGEN_DMA_CH_CC0);
    
      HAL_DMA_CLEAR_IRQ(HAL_IRGEN_DMA_CH_CC1);
      HAL_DMA_ARM_CH(HAL_IRGEN_DMA_CH_CC1);
    
      // Give DMA interrupt highest priority
      IP0 |= BV(0);
      IP1 |= BV(0);
    
      // Can't be interrupted when clearing and starting the timer(s)
      HAL_ENTER_CRITICAL_SECTION(intState);
    
    //#ifdef HAL_IRGEN_CARRIER
    
      HIL_DEBUG_SET(2, 4, 0);
    
      // Select port function to peripheral
      P1SEL |= HAL_IRGEN_P1SEL_PORT;
    
      // Only enable carrier if carrier is non-zero
      if (currentIrSignal.carrier)
      {
        // Buzzer may be used, so disable T3 interupts
        T3IE = FALSE;
    
        // Enable AND gate
        IRCTL |= BV(0);
    
        // Clear timer counter.  Execution of this command will activate the output pin
        // so important to start timer immediately afterwards
        T1CNTL = 0;
    
        // Start timers. Note the order of the timer start sequence
        T1CTL = HAL_IRGEN_DEFAULT_BIT_TIMING_PRESCALER | HAL_IRGEN_T1CTL_MODE_MODULO;
    
        T3CTL = HAL_IRGEN_T3CTL_START | HAL_IRGEN_T3CTL_CLR | HAL_IRGEN_T3CTL_MODE_MODULO;
      }
      else
      {
        // Disable AND gate
        IRCTL &= ~(BV(0));
    
        // Clear timer counter.  Execution of this command will activate the output pin
        // so important to start timer immediately afterwards
        T1CNTL = 0;
    
        // Start timers. Setup Timer 1 tick speed @250kHz, i.e. DIV 1/32 on 8MHz
        T1CTL = HAL_IRGEN_DEFAULT_PRESCALER_NO_CARRIER | HAL_IRGEN_T1CTL_MODE_MODULO;
      }
    //#endif //HAL_IRGEN_CARRIER
    
      HAL_EXIT_CRITICAL_SECTION(intState);
    }
    
    /******************************************************************************
     * @fn      HIT_DmaIsr
     *
     * @brief   Handles DMA interrupt that comes upon completion of transmission.
     *          This function has to be called from DMA interrupt service routine.
     *
     * input parameters
     *
     * None.
     *
     * output parameters
     *
     * None.
     *
     * @return  None.
     *
     */
    void HIT_DmaIsr(void)
    {
    //  P2DIR |= BV(0);
    //  P2_0 = 0;
    
      halIntState_t intState;
    
      HAL_ENTER_CRITICAL_SECTION(intState);
    
      HIL_DEBUG_SET(2, 3, 0);
    
      // If we have received a release at this point, when the packet itself is
      // finished, and there is no release frame to be sent, cause T1 to
      // timeout immediatly so that IR can be considered finished.
      if ( pendingRelease == HIT_RELEASE_EMPTY_PENDING )
      {
        // Change state so that end-logic knows we are "transmitting" release.
        halIrTransmitState = HIT_STATE_TX_RELEASE;
    //    // Set up timer 1 ch2 with a value that will cause imediate timeout after
    //    // the last mark is finished.
    //    T1CC2L = LO_UINT16(currentIrSignal.signal[currentIrSignal.length - 2]) + 1; // Add one to time out one carrier after last Mark
    //    T1CC2H = HI_UINT16(currentIrSignal.signal[currentIrSignal.length - 2]);
      }
    //  else
      {
        // load the last space value into ch2 of timer 1 so that we know when the end of the current frame is, to prepare the next frame
        T1CC2L = LO_UINT16(currentIrSignal.signal[currentIrSignal.length - 1]) - 1; // Subtract one otherwise it will never hit
        T1CC2H = HI_UINT16(currentIrSignal.signal[currentIrSignal.length - 1]);
      }
    
      // Enable Timer 1 interrupt
      IEN1 |= HAL_IRGEN_IEN1_T1IF;
      T1STAT = 0;
    
      // Clear CC0 DMA interrupt flag, CC1 is cleared in hal_dma isr.
      HAL_DMA_CLEAR_IRQ( HAL_IRGEN_DMA_CH_CC0 );
    
      // Set up timer channel to compare mode to signal beginning of last Mark
      T1CCTL0 |= HAL_IRGEN_TxCCTLx_IM_ENABLE;
      // Set up timer channel to compare mode to signal end of last period and therefore end of frame
      T1CCTL2 |= HAL_IRGEN_TxCCTLx_MODE_COMPARE | HAL_IRGEN_TxCCTLx_IM_ENABLE;
    
      HAL_EXIT_CRITICAL_SECTION(intState);
    //  P1_6 = 0;
    //  P2_0 = 1;
    }
    
    /******************************************************************************
     * @fn      HalIrGenT1Isr
     *
     * @brief   Handles Timer 1 interrupt that comes upon completion of transmission.
     *          This function has to be called from Timer 1 interrupt service routine.
     *
     * input parameters
     *
     * None.
     *
     * output parameters
     *
     * None.
     *
     * @return  None.
     *
     */
    HAL_ISR_FUNCTION( halT1Isr, T1_VECTOR )
    {
    //  P2DIR |= BV(0);
    //  P2_0 = 0;
      HAL_ENTER_ISR();
    
      static uint8 flag;
      flag = T1STAT;
      T1STAT = 0;
      if (flag & BV(2))
      {
        // Here marks the end of the last space or the end of transmission at key release
        // To avoid pin assert as we hit timeout for last space we disable IO here
        // TODO: Adjust this to avoid spike at end of last space.
        P1SEL &= ~(HAL_IRGEN_P1SEL_PORT);
    	
        HIL_DEBUG_SET(2, 4, 1);
    
        // Disable Timer 1 interrupt
        IEN1 &= ~(HAL_IRGEN_IEN1_T1IF);
        HalIrGenT1Isr();
      }
      else if (flag & BV(0))
      {
        // This marks the beginning of last Mark.
    
        HIL_DEBUG_SET(2, 3, 1);
      }
    
      HAL_EXIT_ISR();
    //  P2_0 = 1;
    }
    
    /******************************************************************************
     * @fn      HalIrGenT1Isr
     *
     * @brief   Handles Timer 1 interrupt that comes upon completion of transmission.
     *          This function has to be called from Timer 1 interrupt service routine.
     *
     * input parameters
     *
     * None.
     *
     * output parameters
     *
     * None.
     *
     * @return  None.
     *
     */
    
    static void HalIrGenT1Isr( void )
    {
    //  halIntState_t intState;
    
        // Give back interrupt priority to default
      IP0 &= ~(BV(0));
      IP1 &= ~(BV(0));
    
      // Stop timers
    #ifdef HAL_IRGEN_CARRIER
      T3CTL = HAL_IRGEN_T3CTL_MODE_SUSPEND;
    #endif //HAL_IRGEN_CARRIER
    
      T1CTL = HAL_IRGEN_T1CTL_MODE_SUSPEND;
    
      // Set up timer channel to turn off compare mode to signal end of last period and therefore end of frame
      T1CCTL2 &= ~(HAL_IRGEN_TxCCTLx_MODE_COMPARE);
    
      // Disable interupt for CC0
      T1CCTL0 &= ~HAL_IRGEN_TxCCTLx_IM_ENABLE;
    
      // Disable Timer 1 interrupt
      IEN1 &= ~HAL_IRGEN_IEN1_T1IF;
    
      // Clear interrupt flag
      IRCON &= ~HAL_IRGEN_IRCON_T1IF;
      T1STAT &= ~0x04;
    
      // Check if we just finished transmitting release
      if (halIrTransmitState == HIT_STATE_TX_RELEASE)
      {
        pendingRelease = HIT_RELEASE_NOT_PENDING;
        halIrTransmitState = HIT_STATE_IDLE;
    
        osal_clear_event( Hal_TaskID, HIT_POLL);
    
        // Then call application to indicate end of transmission
        //  osal_set_event( RSA_TaskId, XR2_APP_EVT_IR_GEN_DONE);
    
        //    P0_4 = 0;
    
        // Done with transmission so can now allow sleep again.
        halDriverUnblockPM(HAL_LED_IR_ENGINE_BLOCK_PM);
      }
      else
      {
        // Prepare repeat frame.
        currentIrSignal.length = currentIrSignal.originalSignal->repeatLength;
        currentIrSignal.signal = &currentIrSignal.originalSignal->signal[currentIrSignal.originalSignal->startLength];
    
        if ( pendingRelease == HIT_RELEASE_PENDING )
        {
          // Change to release frame, if there is one
          if (currentIrSignal.originalSignal->releaseLength)
          {
            currentIrSignal.length = currentIrSignal.originalSignal->releaseLength;
            currentIrSignal.signal = &currentIrSignal.originalSignal->signal[currentIrSignal.originalSignal->startLength + currentIrSignal.originalSignal->repeatLength];
          }
    
          // Change state so that we can finish next time
          halIrTransmitState = HIT_STATE_TX_RELEASE;
        }
        startIrGen();
      }
    }
    
    
    /**************************************************
     * @fn      HalIrGenInit
     *
     * @brief   Initialize driver
     *
     * input parameters
     *
     * None.
     *
     * output parameters
     *
     * None.
     *
     * @return  None.
     *
     **************************************************/
    void HIT_Init(void)
    {
      // Set TICKSPD
      CLKCONCMD &= ~HAL_IRGEN_CLKCON_TICKSPD_MASK;
      CLKCONCMD |= HAL_IRGEN_TICKSPD_8MHZ;
    
      // Clear all Timer 1 interrupt flags
      T1STAT = 0;
    
      // -- Set up carrier pulse width modulation and output port pin --
    
      // Clear counter and halt the timer
      T3CTL = HAL_IRGEN_DEFAULT_CARRIER_PRESCALER | HAL_IRGEN_T3CTL_CLR | HAL_IRGEN_T3CTL_MODE_MODULO;
    
      // Select port direction to output
      P1DIR |= HAL_IRGEN_P1SEL_PORT;
    
      // Initially clear the port so that there will be no conflict
      P1 &= ~HAL_IRGEN_P1SEL_PORT;
    
      // Select alternative 2 location for T1 output so that T1 CH1 is output to P1.1
      // And also select alternative 2 location for T4 output to avoid conflict
      PERCFG |= HAL_IRGEN_PERCFG_T1CFG; // | HAL_IRGEN_PERCFG_T4CFG;
    
      // Combine carrier signal (Timer 1 CH 1 and Timer 3 CH 1 output)
      IRCTL |= 1;
    
      // Set up timer channel
      // Modulo mode is to be used with T3CC0 comparator spanning over
      // pulse duty cycle period
      T3CCTL0 = HAL_IRGEN_TxCCTLx_CMP_SET | HAL_IRGEN_TxCCTLx_MODE_COMPARE;
    
      // It seems that in modulo mode, counter is reset to 0 one tick after
      // counter value reaches comparator value hence comparator has to be
      // set up with one tick smaller than intended duty cycle.
      T3CC0 = ( HAL_IRGEN_DEFAULT_CARRIER_CMP_VALUE - 1 );
    
      // Carrier pulse duty ratio
      T3CC1 = HAL_IRGEN_DEFAULT_CARRIER_DUTY_CYCLE;
    
      // Timer 3 Channel 1 shall be used to control pulse width within
      // the duty cycle period.
      // Note that IR generation hardware only supports active high
    #ifdef HAL_IRGEN_ACTIVE_HIGH
      T3CCTL1 = HAL_IRGEN_TxCCTLx_CMP_SET_CLR | HAL_IRGEN_TxCCTLx_MODE_COMPARE;
    #else
      T3CCTL1 = HAL_IRGEN_TxCCTLx_CMP_CLR_SET | HAL_IRGEN_TxCCTLx_MODE_COMPARE;
    #endif //HAL_IRGEN_ACTIVE_HIGH
    
      // -- set up bit signal generation timer --
    
      // Halt the timer and set up modulo mode
      T1CTL = HAL_IRGEN_DEFAULT_BIT_TIMING_PRESCALER | HAL_IRGEN_T1CTL_MODE_SUSPEND;
    
      // Clear timer counter
      T1CNTL = 0x00;
    
      // Set up timer channel to compare mode
      T1CCTL0 = HAL_IRGEN_TxCCTLx_CMP_SET | HAL_IRGEN_TxCCTLx_MODE_COMPARE;
    
      // Set up timer channel to compare mode to generate signal and trigger DMA
      T1CCTL1 = HAL_IRGEN_TxCCTLx_CMP_CLR_SET | HAL_IRGEN_TxCCTLx_MODE_COMPARE;
    
    //  // Run one timer 1 cycle
    //  // This is necessary since the timer 1 output will not be set
    //  // initially when T1CNTL is 0 but rather will be set next time
    //  // it wraps around to 0.
    //  T1CNTL = 0; // Set up timer comparators for single carrier pulse output
    //  T1CC0L = 2;
    //  T1CC0H = 0;
    //  T1CC1L = 1;
    //  T1CC1H = 0;
    //  T1CTL = HAL_IRGEN_DEFAULT_BIT_TIMING_PRESCALER | HAL_IRGEN_T1CTL_MODE_MODULO; // start timer 1
    //  T3CTL = HAL_IRGEN_DEFAULT_CARRIER_PRESCALER | HAL_IRGEN_T3CTL_START | HAL_IRGEN_T3CTL_CLR |
    //    HAL_IRGEN_T3CTL_MODE_MODULO; // start timer 3
    //  while (T1CNTL == 0); // wait till the single bit is cleared
    //  T3CTL = HAL_IRGEN_DEFAULT_CARRIER_PRESCALER | HAL_IRGEN_T3CTL_CLR |
    //    HAL_IRGEN_T3CTL_MODE_MODULO; // stop timer 3
    //  T1CTL = HAL_IRGEN_DEFAULT_BIT_TIMING_PRESCALER | HAL_IRGEN_T1CTL_MODE_SUSPEND; // stop timer 1
    
    
      // -- Configure DMA --
      // Select proper DMA channel descriptor structure
    #if HAL_IRGEN_DMA_CH_CC0 == 0
      pDmaDescCc0 = HAL_DMA_GET_DESC0();
    #else
      pDmaDescCc0 = HAL_DMA_GET_DESC1234(HAL_IRGEN_DMA_CH_CC0);
    #endif
    
      // Set up DMA channel for CC0
    
      // The start address of the destination.
      HAL_DMA_SET_DEST( pDmaDescCc0, HAL_IRGEN_T1CC0L_ADDR );
    
      // Using the length field to determine how many bytes to transfer.
      HAL_DMA_SET_VLEN( pDmaDescCc0, HAL_DMA_VLEN_USE_LEN );
    
      // Two bytes are transferred each time.
      HAL_DMA_SET_WORD_SIZE( pDmaDescCc0, HAL_DMA_WORDSIZE_WORD );
    
      // One word is transferred each time on timer 1 channel 1 trigger.
      HAL_DMA_SET_TRIG_MODE( pDmaDescCc0, HAL_DMA_TMODE_SINGLE );
      HAL_DMA_SET_TRIG_SRC( pDmaDescCc0, HAL_DMA_TRIG_T1_CH1 );
    
      // The source address is incremented by 1 word after each transfer.
      HAL_DMA_SET_SRC_INC( pDmaDescCc0, HAL_DMA_SRCINC_2 );
    
      // The destination address is constant - T1CC0.
      HAL_DMA_SET_DST_INC( pDmaDescCc0, HAL_DMA_DSTINC_0 );
    
      // IRQ handler is set up to tigger on CC1
      HAL_DMA_SET_IRQ(pDmaDescCc0, HAL_DMA_IRQMASK_DISABLE);
    
      // Xfer all 8 bits of a byte xfer.
      HAL_DMA_SET_M8( pDmaDescCc0, HAL_DMA_M8_USE_8_BITS );
    
      // Set highest priority
      HAL_DMA_SET_PRIORITY( pDmaDescCc0, HAL_DMA_PRI_HIGH );
    
    #if HAL_IRGEN_DMA_CH_CC1 == 0
      pDmaDescCc1 = HAL_DMA_GET_DESC0();
    #else
      pDmaDescCc1 = HAL_DMA_GET_DESC1234(HAL_IRGEN_DMA_CH_CC1);
    #endif
    
      // Set up DMA channel for CC1
    
      // The start address of the destination.
      HAL_DMA_SET_DEST( pDmaDescCc1, HAL_IRGEN_T1CC1L_ADDR );
    
      // Using the length field to determine how many bytes to transfer.
      HAL_DMA_SET_VLEN( pDmaDescCc1, HAL_DMA_VLEN_USE_LEN );
    
      // Two bytes are transferred each time.
      HAL_DMA_SET_WORD_SIZE( pDmaDescCc1, HAL_DMA_WORDSIZE_WORD );
    
      // One word is transferred each time on timer 1 channel 1 trigger.
      HAL_DMA_SET_TRIG_MODE( pDmaDescCc1, HAL_DMA_TMODE_SINGLE );
      HAL_DMA_SET_TRIG_SRC( pDmaDescCc1, HAL_DMA_TRIG_T1_CH1 );
    
      // The source address is incremented by 1 word after each transfer.
      HAL_DMA_SET_SRC_INC( pDmaDescCc1, HAL_DMA_SRCINC_2 );
    
      // The destination address is constant - T1CC1.
      HAL_DMA_SET_DST_INC( pDmaDescCc1, HAL_DMA_DSTINC_0 );
    
      // IRQ handler is set up so that sleep enable/disable can be determined.
      HAL_DMA_SET_IRQ( pDmaDescCc1, HAL_DMA_IRQMASK_ENABLE );
    
      // Xfer all 8 bits of a byte xfer.
      HAL_DMA_SET_M8( pDmaDescCc1, HAL_DMA_M8_USE_8_BITS );
    
      // Set highest priority
      HAL_DMA_SET_PRIORITY( pDmaDescCc1, HAL_DMA_PRI_HIGH );
    
    
      // Clear interrupt flag
      IRCON &= ~HAL_IRGEN_IRCON_DMAIF;
    
      // Enable DMA interrupt
      IEN1 |= HAL_IRGEN_IEN1_DMAIE;
    
      // Begin in IDLE state.
      halIrTransmitState = HIT_STATE_IDLE;
    }
    
    #endif //HAL_IRGEN
    
    hal_ir_transmit.hhal_ir_common.h