/*----------------------------------------------------------------------------
 * Name:    DSP_App.c
 * Purpose: 
 *----------------------------------------------------------------------------
 * This file is part of the uVision/ARM development tools.
 * This software may only be used under the terms of a valid, current,
 * end user licence from KEIL for a compatible version of KEIL software
 * development tools. Nothing else gives you the right to use this software.
 *
 * This software is supplied "AS IS" without warranties of any kind.
 *
 * Copyright (c) 2010 Keil - An ARM Company. All rights reserved.
 *----------------------------------------------------------------------------*/

#include <RTL.h>
#include "arm_math.h"
#include "LPC17xx.h"                    /* LPC17xx definitions                */
#include "LED.h"
#include "Timer.h"
#include "ADC.h"
#include "DAC.h"
#include "DSP_IIR.h"
#include "DSP_FIR.h"


#define LED_CLK    7



/*----------------------------------------------------------------------------
   defines & typedefs for messages
 *----------------------------------------------------------------------------*/
typedef struct _DSP_MsgType {
#ifdef __FLOAT32
  float32_t Sample[DSP_BLOCKSIZE];
#endif
#ifdef __Q31
  q31_t     Sample[DSP_BLOCKSIZE];
#endif
#ifdef __Q15
  q15_t     Sample[DSP_BLOCKSIZE];
#endif
} DSP_MsgType;

_declare_box (DSP_MsgPool, sizeof(DSP_MsgType), 10);      /* declare Message Pool of 10 messages */

os_mbx_declare(mbx_SigMod, 8);                            /* declare SigMod RTX mailbox */
os_mbx_declare(mbx_TimIrq, 2);                            /* declare TimerIRQ RTX mailbox */
DSP_MsgType *pMsgTimIrqOut;
DSP_MsgType *pMsgTimIrqIn;
uint32_t     msgTimIrqOutIdx;
uint32_t     msgTimIrqInIdx;


/*----------------------------------------------------------------------------
   TaskIDs
 *----------------------------------------------------------------------------*/
OS_TID tid_Clock;                                         /* assigned task id of task: clock   */
OS_TID tid_SigMod;                                        /* assigned task id of task: Signal Modify */


#define OutAmpl      511UL                                /* Output Amplitute (Range  0 - 0.99)     */
#define TimerFreq  32000UL                                /* 32KHz Timer Frequency (used for AD/DA) */



/*----------------------------------------------------------------------------
   error Handler
 *----------------------------------------------------------------------------*/
void errHandler (uint32_t errCode) {

  errCode = errCode;
  while (1) ;                                             /* stay here */
}


float32_t tmpFilterIn;           /* 'global'  to display in LogicAnalyzer */
float32_t tmpFilterOut;          /* 'global'  to display in LogicAnalyzer */
/*----------------------------------------------------------------------------
   TIM2 IRQ Handler
 *----------------------------------------------------------------------------*/
void TIMER2_IRQHandler(void) {
  uint32_t  adGdr;
  uint32_t  errCode;

#ifdef __FLOAT32
  float32_t tmp;
#endif
#ifdef __Q31
  q31_t     tmp;
#endif
#ifdef __Q15
  q15_t     tmp;
#endif

  if (LPC_TIM2->IR & (1UL <<  0)) {                       /* check MR0 Interrupt */

    /* -- signal Input Section ------------------------------------------------- */
    adGdr = LPC_ADC->ADGDR;
    if (adGdr & (1UL << 31)) {						      /* Data available ? */
      /* descale value and move it in positive/nagative range.   (12bit Ad = 0xFFF)
         filter in range is -1.0 < value < 1.0                */
      tmpFilterIn =  ((float32_t)((adGdr >> 4) & 0xFFF) / (0xFFF / 2)) - 1;
#ifdef __FLOAT32
	  tmp  = tmpFilterIn; 
      pMsgTimIrqOut->Sample[msgTimIrqOutIdx++] = tmp;
#endif
#ifdef __Q31
      arm_float_to_q31(&tmpFilterIn, &tmp, 1); 
      pMsgTimIrqOut->Sample[msgTimIrqOutIdx++] = tmp;
#endif
#ifdef __Q15
      arm_float_to_q15(&tmpFilterIn, &tmp, 1); 
      pMsgTimIrqOut->Sample[msgTimIrqOutIdx++] = tmp;
#endif

      if (msgTimIrqOutIdx >= DSP_BLOCKSIZE) {
        isr_mbx_send(mbx_SigMod, pMsgTimIrqOut);          /* send the message */
        pMsgTimIrqOut = _alloc_box (DSP_MsgPool);         /* allocate a message */
        msgTimIrqOutIdx = 0;
        if (pMsgTimIrqOut == NULL) {
          errHandler(__LINE__);
        }
      }
    }
    else {
      errHandler(__LINE__);
    } 
    
    /* -- signal Output Section ------------------------------------------------ */
    if (pMsgTimIrqIn == NULL) {
      isr_mbx_receive(mbx_TimIrq, (void **)&pMsgTimIrqIn);    
      msgTimIrqInIdx = 0;
    }
    if (pMsgTimIrqIn != NULL) {

#ifdef __FLOAT32
      tmp = pMsgTimIrqIn->Sample[msgTimIrqInIdx++];
      tmpFilterOut = tmp;
#endif
#ifdef __Q31
      tmp = pMsgTimIrqIn->Sample[msgTimIrqInIdx++];
      arm_q31_to_float(&tmp, &tmpFilterOut, 1);
#endif
#ifdef __Q15
      tmp = pMsgTimIrqIn->Sample[msgTimIrqInIdx++];
      arm_q15_to_float(&tmp, &tmpFilterOut, 1);
#endif
      /* move value in positive range and scale it.   (10bit DA = 0x3FF)
         filter OUT range is -1.0 < value < 1.0                */
      LPC_DAC->DACR = (((uint32_t)((tmpFilterOut + 1) * (0x03FF / 2))) & 0x03FF) <<  6;

      if (msgTimIrqInIdx >= DSP_BLOCKSIZE) {
        errCode = _free_box (DSP_MsgPool, pMsgTimIrqIn);  /* free memory allocated for message */
        if (errCode) {
          errHandler(__LINE__);
        }
        pMsgTimIrqIn = NULL;
      }       
    }


    LPC_TIM2->IR |= (1UL <<  0);                          /* clear MR0 Interrupt  flag   */
  }
}


/*---------------------------------------------------------------------------
   Task 'Signal Modify'
 *---------------------------------------------------------------------------*/
__task void SigMod (void) {
  uint32_t errCode;
  DSP_MsgType *pMsgIn;                                    /* IN  message  */
  DSP_MsgType *pMsgOut;                                   /* OUT message */

  for (;;) {
    os_mbx_wait (mbx_SigMod, (void **)&pMsgIn, 0xFFFF);   /* Wait for a message */

    pMsgOut = _alloc_box (DSP_MsgPool);                   /* allocate a message */
    if (pMsgOut == NULL) {
      errHandler(__LINE__);
    }

#ifdef __IIR
  #ifdef __FLOAT32
    iirExec_f32 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
  #ifdef __Q31
    iirExec_q31 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
  #ifdef __Q15
    iirExec_q15 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
#endif
#ifdef __FIR
  #ifdef __FLOAT32
    firExec_f32 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
  #ifdef __Q31
    firExec_q31 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
  #ifdef __Q15
    firExec_q15 (pMsgIn->Sample, pMsgOut->Sample);
  #endif
#endif

    errCode = os_mbx_send (mbx_TimIrq, pMsgOut, 0xffff);  /* send message to TimIrq */
    if (errCode != OS_R_OK) {
      errHandler(__LINE__);
    }

    errCode =  _free_box (DSP_MsgPool, pMsgIn);           /* free memory allocated for message */
    if (errCode == 1) {
      errHandler(__LINE__);
    }
  }
}

/*----------------------------------------------------------------------------
   Task 'clock': Signal Clock
 *---------------------------------------------------------------------------*/
__task void Clock (void) {

  for (;;) {
    os_dly_wait (60);                                     /* delay 60 clock ticks */
    LED_On (LED_CLK);
    os_dly_wait (40);                                     /* delay 40 clock ticks */
    LED_Off(LED_CLK);
  }
}

/*----------------------------------------------------------------------------
   Task 'init': Initialize
 *---------------------------------------------------------------------------*/
__task void init (void) {
  uint32_t errCode;


  _init_box (DSP_MsgPool, sizeof(DSP_MsgPool), sizeof(DSP_MsgType));
  if (errCode == 1) {
    errHandler(__LINE__);
  }

  os_mbx_init (mbx_TimIrq, sizeof(mbx_TimIrq));           /* initialize TimerIRQ mailbox */
  os_mbx_init (mbx_SigMod, sizeof(mbx_SigMod));           /* initialize SigMod mailbox */

  tid_Clock  = os_tsk_create (Clock, 0);                  /* start task clock */
  tid_SigMod = os_tsk_create (SigMod, 0);                 /* start task Signal Modify */ 

  pMsgTimIrqOut = _alloc_box (DSP_MsgPool);               /* allocate a message */
  pMsgTimIrqIn  = NULL;
  msgTimIrqOutIdx = 0;
  msgTimIrqInIdx  = 0;

  TIM2_Start ();                                          /* start Timer 2 (used for Signal IN/OUT) */

  os_tsk_delete_self ();
}


/*----------------------------------------------------------------------------
 *        Main: Initialize and start RTX Kernel
 *---------------------------------------------------------------------------*/
int main (void) {

  LED_Init ();                                            /* initialize the LEDs */
  TIM2_Init (TimerFreq);                                  /* initialize Timer 2 (used for DAC) */
  ADC_Init ();                                            /* initialize ADC Controller */
  DAC_Init ();                                            /* initialize DAC Controller */

#ifdef __IIR
  #ifdef __FLOAT32
    iirInit_f32 ();
  #endif
  #ifdef __Q31
    iirInit_q31 ();
  #endif
  #ifdef __Q15
    iirInit_q15 ();
  #endif
#endif
#ifdef __FIR
  #ifdef __FLOAT32
    firInit_f32 ();
  #endif
  #ifdef __Q31
    firInit_q31 ();
  #endif
  #ifdef __Q15
    firInit_q15 ();
  #endif
#endif

  os_sys_init(init);                                      /* initialize RTX and start init */
}

/*----------------------------------------------------------------------------
 * end of file
 *---------------------------------------------------------------------------*/
