/******************************************************************************
 *
 * Freescale Semiconductor Inc.
 * (c) Copyright 2004-2013 Freescale Semiconductor, Inc.
 * ALL RIGHTS RESERVED.
 *
 ******************************************************************************
 *
 * THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
 * IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************//*!
 *
 * @file med_ekg.c
 *
 * @author  
 *
 * @version 1.0
 *
 * @date Sep-01-2013
 *
 * @brief ECG acquisition tasks using the MED-EKG board
 *
 *****************************************************************************/

/*****************************************************************************
 * Header files
 ****************************************************************************/
#include "med_ekg.h"
#include "adc.h"
#include "dac.h"
#include "opamp.h"
#include "triamp.h"
#include "lpb_ui.h"
#include "fsl_types.h"
#include "SwTimer.h"
#include "arm_math.h"
#include "hr_analysis.h"

#if defined (USB_DEBUG)
#include "io.h"
#endif

/****************************************************************************
 * User definitions
 ***************************************************************************/
#define ECG_FILTER_TAPS		50

/****************************************************************************
 * Globals
 ***************************************************************************/
uint8_t u8EcgTaskTimer;

/****************************************************************************
 * Locals
 ***************************************************************************/
//FIR filter implementation

//FIR LPF 8-15Hz
const q15_t ai16Coeffs[] = {
	0,
	0,
	-7,
	-15,
	16,
	0,
	-43,
	118,
	202,
	0,
	279,
	714,
	110,
	0,
	1050,
	0,
	-1700,
	0,
	-477,
	-5221,
	-3543,
	0,
	-9161,
	-11948,
	13307,
	32767,
	13307,
	-11948,
	-9161,
	0,
	-3543,
	-5221,
	-477,
	0,
	-1700,
	0,
	1050,
	0,
	110,
	714,
	279,
	0,
	202,
	118,
	-43,
	0,
	16,
	-15,
	-7,
	0,
	0
};

const arm_fir_instance_q15 EcgFilter;
q15_t FilterState[ECG_FILTER_TAPS+1];

/****************************************************************************
 * Functions
 ***************************************************************************/

/***************************************************************************
 * Function: u8MedEkgInit
 * 
 * Description: Initialise MED-EKG module for EKG acquisition
 * 
 * Input: (none)
 * 
 * Output: uint8_t: Error status
 * 					-MED_EKG_OK: No error occurred
 * 					-MED-EKG_ERR: Error occurred
 * 
 * Warning: (none)
 ***************************************************************************/
uint8_t u8MedEkgInit(void)
{	
	tOPAMP Op0Config;
	tOPAMP Op1Config;
	tDAC   Dac0Config;
	
	//Initialise TRIAMPS
	vfnTriampInit(TRIAMP0, TRIAMP_LOW_POWER);
	vfnTriampInit(TRIAMP1, TRIAMP_LOW_POWER);
	
	//Initialise OpAmps
	Op0Config.OpAmpModule = OPAMP0;
	Op0Config.u8AmppselAmpnsel = OP0_PSEL_OP0_DP0 | OP0_NSEL_OP0_DM0;
	Op0Config.u8LowpowerOpmode = OPAMP_LOWPOWER | OPAMP_GENERAL_PURPOSE;
	
	Op1Config.OpAmpModule = OPAMP1;
	Op1Config.u8AmppselAmpnsel = OP1_PSEL_OP1_DP0 | OP1_NSEL_OP1_DM0;
	Op1Config.u8LowpowerOpmode = OPAMP_LOWPOWER | OPAMP_NON_INVERTING;
	Op1Config.u8Gain = OP_NIGAIN_10;
	
	vfnOpAmpInit(Op0Config);
	vfnOpAmpInit(Op1Config);
	
	//Initialise DAC
	Dac0Config.DacModule = DAC0;
	Dac0Config.u8DacRefvTrigPowermode = DACREF_2 | DAC_SW_TRIGGER | DAC_LOW_POWER;
	Dac0Config.u8DacIntEn = DAC_DISABLE_INT;
	Dac0Config.u8DacDmaBufferenBuffermode = DAC_DMA_DIS | DAC_BUFFER_DIS;
	
	vfnDacInit(Dac0Config);
	
	if(u8DacLoadVal(DAC0,0x07FF,0))
		return MED_EKG_ERR;
	
	//Initialise ADC
	vfnADCInit();
	vfnADCConfigChannel(ADC_EKG_SIGNAL);
	
	//Initialise FIR filter
	if(arm_fir_init_q15(&EcgFilter, ECG_FILTER_TAPS, (q15_t*)&ai16Coeffs[0], (q15_t*)&FilterState[0], 1) != ARM_MATH_SUCCESS)
		return MED_EKG_ERR;
	
	//Turn on the medical connector
	MEDCON_INIT();
	MEDCON_PWRON();
	
	return MED_EKG_OK;
}

/***************************************************************************
 * Function: vfnMedEkgPeriodicTask
 * 
 * Description: Execute periodic task for ECG acquisition and analysis
 * 
 * Input: (none)
 * 
 * Output: (none)
 * 
 * Warning: (none)
 ***************************************************************************/
void vfnMedEkgPeriodicTask (void)
{
	int16_t i16EkgSample;
	int16_t i16EkgFiltered;

	//Restart software timer
	SwTimer_StartTimer(u8EcgTaskTimer, EKG_TASK_TIME_MS);
	
	//Read EKG signal ADC channel
	vfnPollChannel(ADC_EKG_SIGNAL);
	
	//Store sample
	i16EkgSample = sADCControl.gu16LatestResult[0];
	
	//Filter Sample
	arm_fir_q15(&EcgFilter, &i16EkgSample, &i16EkgFiltered, 1);
	
#if defined(USB_DEBUG)
	//Graph
	//printf("%04X,%04X,0000,0000\n",(i16EkgFiltered+0x7FFFu),(i16EkgSample&0x7FFFu));
	//Matlab
//	printf("%i,",i16EkgFiltered);
#endif
	
	//Analyse heart rate
	vfnHrDetector(i16EkgFiltered);
}
