/******************************************************************************
 *
 * 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 hr_analysis.c
 *
 * @author  
 *
 * @version 1.0
 *
 * @date Sep-09-2013
 *
 * @brief HR analysis functions
 * 
 *****************************************************************************/

/*****************************************************************************
 * Header files
 ****************************************************************************/
#include "hr_analysis.h"
#include "fsl_types.h"
#include "derivative.h"

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

/*****************************************************************************
 * Globals
 ****************************************************************************/
uint8_t gu8HrValue = 0;

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

/***************************************************************************
 * Function: vfnHrDetector
 * 
 * Description: Calculates HR based on the detection of the QRS complex and
 * 				stores the result in the global variable gu8HrValue
 * 
 * Input: 
 * 			i16EcgSample: ECG sample taken with a sampling period equal to
 * 			HR_SAMPLIG_PERIOD_MS defined in hr_analysis.h
 * 
 * Output: (none)
 * 
 * Warning: This function must be executed every time a sample is taken or
 * 			N times when a sample array is given where N is equal to the 
 * 			number of samples in the array
 ***************************************************************************/
void vfnHrDetector (int16_t i16EcgSample)
{
	static uint16_t u16HrSamples = 0;
	static int16_t i16PreviousSample = 0;
	static int16_t i16PreviousDerivative = 0;
	static int16_t i16HrMaxPoint, i16HrMinPoint;
	static uint8_t u8HrState = HR_FIND_MAX;
	static uint8_t au8HrAverage[HR_AVERAGE];
	int16_t i16Derivative;
	
	//Count the samples number
	u16HrSamples++;
	
	//Calculate first derivative
	i16Derivative = i16EcgSample - i16PreviousSample;
	i16PreviousSample = i16EcgSample;
	
#if defined(USB_DEBUG)
	//Graph
	printf("%04X,%04X,0000,0000\n",(i16Derivative+0x7FFFu),(i16EcgSample+0x3FFF));
	//Matlab
//	printf("%i,",i16Derivative);
#endif
	
	switch(u8HrState)
	{
	case HR_FIND_MAX:
		if(i16Derivative > i16PreviousDerivative)
			i16HrMaxPoint = i16Derivative;
		else
		{
			i16HrMinPoint = i16Derivative;
			u8HrState = HR_FIND_MIN;
		}
		break;
		
	case HR_FIND_MIN:
		if(i16Derivative < i16PreviousDerivative)
		{
			i16HrMinPoint = i16Derivative;
			break;
		}

		//Determine if a QRS complex was detected
		if(i16HrMaxPoint >= HR_THRESHOLD_HIGH &&  i16HrMinPoint <= HR_THRESHOLD_LOW)
			u8HrState = HR_QRS_DETECTED;
		
		i16HrMaxPoint = i16Derivative;
		
		if(u8HrState != HR_QRS_DETECTED)
		{
			u8HrState = HR_FIND_MAX;
			break;
		}
		
	case HR_QRS_DETECTED:
		if(u16HrSamples)
		{
			static uint8_t u8AverageSamples = 0;
			uint16_t u16Accumulator = 0;
			uint8_t u8Counter;
			
			//Calculate inmediate HR
			au8HrAverage[u8AverageSamples] = (uint8_t)(60000/(u16HrSamples*HR_SAMPLING_PERIOD_MS));
			
			u8AverageSamples = (uint8_t)((u8AverageSamples + 1) % HR_AVERAGE);

			for(u8Counter = 0; u8Counter < HR_AVERAGE; u8Counter++)
			{
				u16Accumulator += au8HrAverage[u8Counter];
			}
			
			gu8HrValue = (uint8_t)(u16Accumulator/HR_AVERAGE);

			u16HrSamples = 0;
		}
		
		u8HrState = HR_FIND_MAX;
		break;
	}
	i16PreviousDerivative = i16Derivative;
	
	//HR watchdog
	if((u16HrSamples*HR_SAMPLING_PERIOD_MS) >= HR_TIMEOUT_MS)
	{
		gu8HrValue = 0;
		u16HrSamples = 0;
	}
}
