//#include <stdio.h>
//#include "math.h"
#include "tc_vars.h"
#include "hardware_t.h"
#include "flash_t.h"
#include "display_t.h"
//#include "floatstr_t.h"
#include "signal_t.h"
#include "userif_t.h"

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 							Class Signal
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


 int Signal::_SinTab[2048];
 int Signal::_CosTab[2048];
 int Signal::_RevTab[2048];
 int Signal::_WinTab[2048];


//##########################################################################################################################################################
/* !Level 1 routine for Signal processing -> DSP unit
    only for normal TB. USTB is calculated directly in USTB ADC handler */

void Signal::processSignal(void)
{
	if(!ACQ_NewData) return;

//printf("DSP Unit \n\r");

//---------------------------------------------------------------------------------------
//			Calculate drawing parameters
//---------------------------------------------------------------------------------------
	if (((MainTimebase + VirtualTimebase) < 4) && FFT_Mode == FFT_OFF) 		// BF 20ns + 10ns + 5ns + 2ns main mode - interpolated signal
	{
		draw_start = 0;
		draw_factor = 1;
	}
	else if (USTB_Mode != USTB_OFF)							// USTB active?
	{ 
		draw_start = MemWinStart;						// set drawing parameters 
		draw_factor = 1;
		return;									// and leave...
	}
	else 										// BF >= 50ns main mode - true signal and FFT
	{
		draw_start = (short) MemWinStart + PreTrigComp;				// must be calculated new after every acquisition
		draw_factor = (short)ZoomFactor;
	}


	if (MenuStatus[MENU_TIMEBASE][1] == BTN_ON)					// Delayed
	{
		if (ZoomFactorDel < 1) 							// 20ns + 10ns delayed mode  - interpolated signal
		{
			draw_dm_ixstart  = 0;						// set to zero because whole interpolation buffer must be drawn
			draw_dm_ixfactor = (short) ZoomFactorDel;	
		}
		else									// >= 50ns delayed mode - true signal
		{
			draw_dm_ixstart  = MemWinStart + PreTrigComp + (short)((float)Cursor_Delayed_1 * ZoomFactor);	//BF #003
			draw_dm_ixfactor = (short) ZoomFactorDel;	
		}
	}	

	unsigned char *lPtr_S1 = NULL;							//pointer to signal 1
	unsigned char *lPtr_S2 = NULL;							//pointer to signal 2
	unsigned char *lPtr_SM = NULL;							//pointer to math signal 

	int lCalcStart = MemWinStart + PreTrigComp;					// determine calculation range 
	int lCalcStop  = lCalcStart + (GRID_WIDTH * draw_factor) + draw_factor;		// determine calculation range 
	int lix;


	//---------------------------------------------------------------------------------------
	//				Invert Signal
	//---------------------------------------------------------------------------------------
	if (Run || SingleShot)
	{
		SingleShot = 0;

		int lSignalEnd;

		if (MainTimebase < 11) lSignalEnd = 16384;
		else lSignalEnd = 4096;

		if (Channel_1_Active && MenuStatus[MENU_CHANNEL1][2] - BTN_OFF)		// Channel 1 inversion on?
		{
			//for (int i=lCalcStart; i<lCalcStop;i++)
			for (int i=0; i<lSignalEnd;i++)
			{ SIGNAL1[i] = (ADC_VirtualZero_CH1<<1) - SIGNAL1[i]; }
		}
	
		if (Channel_2_Active && MenuStatus[MENU_CHANNEL2][2] - BTN_OFF)		// Channel 2 inversion on?
		{
			//for (int i=lCalcStart-draw_factor; i<lCalcStop;i++)
			for (int i=0; i<lSignalEnd;i++)
			{ SIGNAL2[i] = (ADC_VirtualZero_CH2<<1) - SIGNAL2[i]; }
		}
	
		if (Channel_3_Active && MenuStatus[MENU_CHANNEL3][2] - BTN_OFF)		// Channel 3 inversion on?
		{
			//for (int i=lCalcStart-draw_factor; i<lCalcStop;i++)
			for (int i=0; i<lSignalEnd;i++)
			{ SIGNAL3[i] = (ADC_VirtualZero_CH3<<1) - SIGNAL3[i]; }
		}
	
		if (Channel_4_Active && MenuStatus[MENU_CHANNEL4][2] - BTN_OFF)		// Channel 4 inversion on?
		{
			//for (int i=lCalcStart-draw_factor; i<lCalcStop;i++)
			for (int i=0; i<lSignalEnd;i++)
			{ SIGNAL4[i] = (ADC_VirtualZero_CH4<<1) - SIGNAL4[i]; }
		}
	
	}



	//---------------------------------------------------------------------------------------
	//				Average
	//---------------------------------------------------------------------------------------
	
	if (MenuStatus[MENU_ACQUIRE][1] > AVRG_OFF)		//Average not off?
	{
		char lmode = (char)(MenuStatus[MENU_ACQUIRE][1] - AVRG_OFF);

		if (lmode == 1)	//infinity mode
		{
			if (Channel_1_Active)
			for (int i=lCalcStart; i<lCalcStop;i++)
			{ Filter1_Buffer[i] = (unsigned char)(((int)Filter1_Buffer[i] + (int)SIGNAL1[i])>>1); 
			SIGNAL1[i] = Filter1_Buffer[i]; }

			if (Channel_2_Active)
			for (int i=lCalcStart; i<lCalcStop;i++)
			{ Filter2_Buffer[i] = (unsigned char)(((int)Filter2_Buffer[i] + (int)SIGNAL2[i])>>1); 
			SIGNAL2[i] = Filter2_Buffer[i]; }

			if (Channel_3_Active)
			for (int i=lCalcStart; i<lCalcStop;i++)
			{ Filter3_Buffer[i] = (unsigned char)(((int)Filter3_Buffer[i] + (int)SIGNAL3[i])>>1); 
			SIGNAL3[i] = Filter3_Buffer[i]; }

			if (Channel_4_Active)
			for (int i=lCalcStart; i<lCalcStop;i++)
			{ Filter4_Buffer[i] = (unsigned char)(((int)Filter4_Buffer[i] + (int)SIGNAL4[i])>>1); 
			SIGNAL4[i] = Filter4_Buffer[i]; }
		}
		else
		{
	//printf("average cnt = %d\n\r", ACQ_Average );
			if (ACQ_Average == lmode<<1)		// new cycle
			{
				if (Channel_1_Active) { for (int i=lCalcStart; i<lCalcStop;i++)	{ Filter1_Buffer[i] = SIGNAL1[i]; } }
				if (Channel_2_Active) { for (int i=lCalcStart; i<lCalcStop;i++)	{ Filter2_Buffer[i] = SIGNAL2[i]; } }
				if (Channel_3_Active) { for (int i=lCalcStart; i<lCalcStop;i++)	{ Filter3_Buffer[i] = SIGNAL3[i]; } }
				if (Channel_4_Active) { for (int i=lCalcStart; i<lCalcStop;i++)	{ Filter4_Buffer[i] = SIGNAL4[i]; } }
				
				ACQ_NewData = 0;
				ACQ_Average--;
				return;
			}
			else			// calculate average
			{ 
				for (int i=lCalcStart; i<lCalcStop;i++)
				{ Filter1_Buffer[i] =  (unsigned char)(((int)Filter1_Buffer[i] + (int)SIGNAL1[i])>>1); }
			}
			
	
			if (ACQ_Average == 0)	//cycle end
			{
				if (Channel_1_Active) { for (int i=lCalcStart; i<lCalcStop;i++) {  SIGNAL1[i] = Filter1_Buffer[i]; } }
				if (Channel_2_Active) { for (int i=lCalcStart; i<lCalcStop;i++) {  SIGNAL2[i] = Filter2_Buffer[i]; } }
				if (Channel_3_Active) { for (int i=lCalcStart; i<lCalcStop;i++) {  SIGNAL3[i] = Filter3_Buffer[i]; } }
				if (Channel_4_Active) { for (int i=lCalcStart; i<lCalcStop;i++) {  SIGNAL4[i] = Filter4_Buffer[i]; } }
	
				ACQ_Average = lmode<<1; // continous or steps
			}
			else
			{ ACQ_Average--; ACQ_NewData = 0; return;}	
		}

	}



	//---------------------------------------------------------------------------------------
	//				Noise Filter (low pass filter)
	//---------------------------------------------------------------------------------------
	
	if (MenuStatus[MENU_ACQUIRE][2] != FILT_OFF)			//Noise Filter not off?
	{

		//noise filter -> stage 1 nearly lossless, stage 2 with losing bandwidth
		if (FilterType == PRO)
		{
			char lStage = (char)(MenuStatus[MENU_ACQUIRE][2] - FILT_OFF);
//printf("Noise Filter \n\r");
			if (Channel_1_Active)
			{ LowPassFilter(lCalcStart, lCalcStop, lStage, SIGNAL1, Filter1_Buffer); }
			
			if (Channel_2_Active)
			{ LowPassFilter(lCalcStart, lCalcStop, lStage, SIGNAL2, Filter2_Buffer); }
			
			if (Channel_3_Active)
			{ LowPassFilter(lCalcStart, lCalcStop, lStage, SIGNAL3, Filter3_Buffer); }
			
			if (Channel_4_Active)
			{ LowPassFilter(lCalcStart, lCalcStop, lStage, SIGNAL4, Filter4_Buffer); }
		}
		//IIR low pass filter with 1 - 3 stages
		else if (FilterType == IIR)	
		{ 
			char lStage = (char)(MenuStatus[MENU_ACQUIRE][2] - (FILT_OFF+2));

			if (Channel_1_Active)
			{ IIR_Filter(lCalcStart, lCalcStop, lStage, SIGNAL1, Filter1_Buffer); }
			
			if (Channel_2_Active)
			{ IIR_Filter(lCalcStart, lCalcStop, lStage, SIGNAL2, Filter2_Buffer); }
			
			if (Channel_3_Active)
			{ IIR_Filter(lCalcStart, lCalcStop, lStage, SIGNAL3, Filter3_Buffer); }
			
			if (Channel_4_Active)
			{ IIR_Filter(lCalcStart, lCalcStop, lStage, SIGNAL4, Filter4_Buffer); }
		}
		//FIR low pass filter
		else if (FilterType == FIR)	
		{
			if (Channel_1_Active)
			{ FIR_NoiseFilter(lCalcStart, lCalcStop, SIGNAL1, Filter1_Buffer); }
			
			if (Channel_2_Active)
			{ FIR_NoiseFilter(lCalcStart, lCalcStop, SIGNAL2, Filter2_Buffer); }
			
			if (Channel_3_Active)
			{ FIR_NoiseFilter(lCalcStart, lCalcStop, SIGNAL3, Filter3_Buffer); }
			
			if (Channel_4_Active)
			{ FIR_NoiseFilter(lCalcStart, lCalcStop, SIGNAL4, Filter4_Buffer); }

		}	


		//set signal pointers to filter buffer
		S1Ptr = Filter1_Buffer;
		S2Ptr = Filter2_Buffer;
		S3Ptr = Filter3_Buffer;
		S4Ptr = Filter4_Buffer;

//		printf("DSP filtering \n\r");

	}
	else		//no filtering
	{
		//set signal pointers to unfiltered signal
		S1Ptr = SIGNAL1;
		S2Ptr = SIGNAL2;
		S3Ptr = SIGNAL3;
		S4Ptr = SIGNAL4;
		//SMPtr = SIGNALM;
	}


        //--------------------------------------------------------------------------------------
	//        	 Interpolation (time stretch) for timebase 20ns, 10ns 5ns 2ns
	//--------------------------------------------------------------------------------------
	if(FFT_Mode == FFT_OFF)	
	{ 
		short lDel_IntPol_Offs = MemWinStart + PreTrigComp + (short)((float)Cursor_Delayed_1 * ZoomFactor);	//BF #003 Interpolation offset for delayed signal

		if (Channel_1_Active)
		{	
			if ((MainTimebase + VirtualTimebase) < 4)
			{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S1Ptr, SIGNAL1_Intpolate); }
			
			if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1)) //delayed mode
			{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S1Ptr, SIGNAL1_Intpolate_delayed); }
		}
		
		if (Channel_2_Active)
		{	
			if ((MainTimebase + VirtualTimebase) < 4)
			{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S2Ptr, SIGNAL2_Intpolate); }
			
			if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
			{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S2Ptr, SIGNAL2_Intpolate_delayed); }
		}	
		//4-Channel Version
		if (NumberOfChannels == 4)
		{	
			if (Channel_3_Active)
			{	
				if ((MainTimebase + VirtualTimebase) < 4)
				{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S3Ptr, SIGNAL3_Intpolate); }
				
				if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
				{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S3Ptr, SIGNAL3_Intpolate_delayed); }
			}	
			
			if (Channel_4_Active)
			{		   	
				if ((MainTimebase + VirtualTimebase) < 4)
				{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S4Ptr, SIGNAL4_Intpolate); }
				
				if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
				{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S4Ptr, SIGNAL4_Intpolate_delayed); }
			}
		}	

	}
	//---------------------------------------------
	//         	FFT
	//---------------------------------------------
	else
	{
		//if(FFT_NewData || !Run)	// BF calculate spectrum
		if(FFT_NewData)		
		{ 
			//if(Channel_1_Active) FFT_CalcSpectrum(S1Ptr+draw_start,SPECTRUM);
			if(Channel_1_Active) FFT_calcSpectrum(SIGNAL1,SPECTRUM);
			else if(Channel_2_Active) FFT_calcSpectrum(S2Ptr+draw_start,SPECTRUM);
			else if(Channel_3_Active) FFT_calcSpectrum(S3Ptr+draw_start,SPECTRUM);
			else if(Channel_4_Active) FFT_calcSpectrum(S4Ptr+draw_start,SPECTRUM);
		}	
		
		return;
	}	



	//---------------------------------------------------------------------------------------
	//				MATH functions
	//---------------------------------------------------------------------------------------
	
	if (Channel_Math_Active) 
	{
		int lfactor;

		//width of calculating for math functions
//		lcalcstop = draw_start + ((GRID_WIDTH + 30) * draw_factor);	//BF ????? can be optimized!!
//		if (lcalcstop > 16280){lcalcstop = 16280;}
	
	
		//set pointers to signals
		if ((MainTimebase + VirtualTimebase) < 4) 	//BF 20ns + 10ns + 5ns + 2ns main mode - interpolated signal
		{
			lPtr_S1 = SIGNAL1_Intpolate;
			lPtr_S2 = SIGNAL2_Intpolate;
			lPtr_SM = SIGNALM_Intpolate;
		}
		else
		{
			lPtr_S1 = S1Ptr;
			lPtr_S2 = S2Ptr;
			lPtr_SM = SIGNALM;
		}
		SMPtr = SIGNALM;	// global math pointer to signal math	

		if (MenuStatus[MENU_TIMEBASE][1] == BTN_ON)	//Delayed
		{ lfactor = 1;	}				// 1 -> calculate all math values
		else 						//Main Mode
		{ lfactor = draw_factor; } 			// only calc the displayed values

		if (Channel_1_Active && Channel_2_Active)
		{

			//---------------------------------------------
			//         MATH function multiply
			//---------------------------------------------
			if (MenuStatus[MENU_MATH][2] == BTN_ON)      		// multiply 
			{	
				//set global math scaling and offset for drawing routine
				math_scale = math_mul_scale - 166;
				Math_Offset = Math_Mul_Offset;
				
				//calculate main math signal
				calcMathMul(draw_start, lCalcStop, lfactor, lPtr_S1, lPtr_S2, lPtr_SM);
				
				//calculate delayed math signal
				if ((MenuStatus[MENU_TIMEBASE][1] == 241) && ((MainTimebase - DelayedTimebase -1) < 4))	//BF #003
				{ calcMathMul(0, GRID_WIDTH+1, 1, SIGNAL1_Intpolate_delayed, SIGNAL2_Intpolate_delayed, SIGNALM_Intpolate_delayed); }
			}	//multiply end
	
			//---------------------------------------------
			//         MATH function subtract
			//---------------------------------------------
	
			else if (MenuStatus[MENU_MATH][3] == BTN_ON)            	// subtract
			{	
				//set global math scaling and offset for drawing routine
				math_scale = math_sub_scale - 150;
				Math_Offset = Math_Sub_Offset;
				
				//calculate main math signal
				calcMathSub(draw_start, lCalcStop, lfactor, lPtr_S1, lPtr_S2, lPtr_SM);
	
				//calculate delayed math signal
				if ((MenuStatus[MENU_TIMEBASE][1] == 241) && ((MainTimebase - DelayedTimebase -1) < 4))	//BF #003
				{ calcMathSub(0, GRID_WIDTH+1, 1, SIGNAL1_Intpolate_delayed, SIGNAL2_Intpolate_delayed, SIGNALM_Intpolate_delayed); }
			}	//subtract end
	
			//---------------------------------------------
			//         MATH function add
			//---------------------------------------------
			else if (MenuStatus[MENU_MATH][4] == BTN_ON)            	// add
			{
				//set global math scaling and offset for drawing routine
				math_scale = math_add_scale - 150;
				Math_Offset = Math_Add_Offset;
				
				//calculate main math signal
				calcMathAdd(draw_start, lCalcStop, lfactor, lPtr_S1, lPtr_S2, lPtr_SM);
	
				//calculate delayed math signal
				if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && ((MainTimebase - DelayedTimebase -1) < 4))	//BF #003
				{ calcMathAdd(0, GRID_WIDTH+1, 1, SIGNAL1_Intpolate_delayed, SIGNAL2_Intpolate_delayed, SIGNALM_Intpolate_delayed); }
			}	//add end
		}
		else if ((!Channel_1_Active && Channel_2_Active) || (!Channel_2_Active && Channel_1_Active))
		{
			for(int i=0;i<16280;i++) SIGNALM[i] = ADC_ZERO;		
			for(int i=0;i<1199;i++) SIGNALM_Intpolate[i] = ADC_ZERO;
		}
		

	}//Math End


} //Signal processing end 

//##########################################################################################################################################################
/* delete all USTB buffers and reset the pointers */
void Signal::USTB_clearBuffer(void)
{
	int lVirtual_Zero=0;

//printf("\nclearing signal buffers...\r\n");

	if (USTB_Mode == USTB_ROLL)
	{
		// reset time pointer (memory index)
		if (USTB_Dir == USTB_FORWARD)		// direction = forward
		{ USTB_idx = MemStartOffs; MemWinStart = MemStartOffs+1; }
		else					// direction = reverse
		{ USTB_idx = MemoryEnd; MemWinStart = MemoryEnd - GRID_WIDTH;}

		// adjust signal pointers to 32k buffers
		S1Ptr = ROLL_OFFS1;
		S2Ptr = ROLL_OFFS2;
		S3Ptr = ROLL_OFFS3;
		S4Ptr = ROLL_OFFS4;
		SMPtr = ROLL_OFFSM;
	}
	else		// shift mode
	{
		if (USTB_Dir == USTB_FORWARD)		// direction = forward
		{
			USTB_idx = MemStartOffs;
			USTB_EOSignal = MemStartOffs;
			MemWinStart = MemStartOffs+1;

			S1Ptr = SIGNAL1;		// adjust signal pointers to 16k buffers with 80k shift space down
			S2Ptr = SIGNAL2;
			S3Ptr = SIGNAL3;
			S4Ptr = SIGNAL4;
			SMPtr = SIGNALM;
		}
		else					// direction = reverse
		{
			USTB_idx = MemoryEnd;
			USTB_EOSignal = MemoryEnd;
			MemWinStart = MemoryEnd - GRID_WIDTH;
			
			S1Ptr = SHIFT_OFFS1;		// adjust signal pointers to 16k buffers with 80k shift space up
			S2Ptr = SHIFT_OFFS2;
			S3Ptr = SHIFT_OFFS3;
			S4Ptr = SHIFT_OFFS4;
			SMPtr = SHIFT_OFFSM;
		}

	}

	Trig_Pos_Mem = USTB_idx;
	Trig_Pos_Display = (int) ((float)(Trig_Pos_Mem - MemWinStart) / ZoomFactor);
	//Trig_Pos_Display_dmode = (int) (((float)(Trig_Pos_Mem - MemWinStart) / ZoomFactorDel) - ((float) Cursor_Delayed_1 * (ZoomFactor / ZoomFactorDel)));


	//Channel 1
	lVirtual_Zero = ADC_VirtualZero_CH1;
	if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
	if (lVirtual_Zero < 0) lVirtual_Zero = 0;
	
	for(int i=MemStartOffs;i<MemoryEnd;i++) S1Ptr[i] = (char)lVirtual_Zero;
	
	//Channel 2
	lVirtual_Zero = ADC_VirtualZero_CH2;
	if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
	if (lVirtual_Zero < 0) lVirtual_Zero = 0;
	
	for(int i=MemStartOffs;i<MemoryEnd;i++) S2Ptr[i] = (char)lVirtual_Zero;

	//Channel 3
	lVirtual_Zero = ADC_VirtualZero_CH3;
	if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
	if (lVirtual_Zero < 0) lVirtual_Zero = 0;
	
	for(int i=MemStartOffs;i<MemoryEnd;i++) S3Ptr[i] = (char)lVirtual_Zero;


	//Channel 4
	lVirtual_Zero = ADC_VirtualZero_CH4;
	if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
	if (lVirtual_Zero < 0) lVirtual_Zero = 0;
	
	for(int i=MemStartOffs;i<MemoryEnd;i++) S4Ptr[i] = (char)lVirtual_Zero;


	//Channel math
	for(int i=MemStartOffs;i<MemoryEnd;i++) SMPtr[i] = ADC_ZERO;


}
//##########################################################################################################################################################
// BF reset all pointers and indices. Copy 16k buffers from end to start position
void Signal::USTB_resetShiftBuffer(void)
{
	//printf("reset shift buffers\r\n");

	Hardware::Stop_Timer2();
	Hardware::Stop_Record();

	if (USTB_Dir == USTB_FORWARD)		// direction = forward
	{
		USTB_idx = MemStartOffs;
		USTB_EOSignal = MemStartOffs;
		//MemWinStart = MemStartOffs;

		S1Ptr = SIGNAL1;		// adjust signal pointers to 16k buffers with 80k shift space down
		S2Ptr = SIGNAL2;
		S3Ptr = SIGNAL3;
		S4Ptr = SIGNAL4;
		SMPtr = SIGNALM;

		for(int i=MemStartOffs;i<MemoryEnd;i++)
		{
			SIGNAL1[i] = SHIFT_OFFS1[i];
			SIGNAL2[i] = SHIFT_OFFS2[i];
			SIGNAL3[i] = SHIFT_OFFS3[i];
			SIGNAL4[i] = SHIFT_OFFS4[i];
			SIGNALM[i] = SHIFT_OFFSM[i];
		}

	}
	else					// direction = reverse
	{
		USTB_idx = MemoryEnd;
		USTB_EOSignal = MemoryEnd;
		//MemWinStart = MemoryEnd - GRID_WIDTH;
		
		S1Ptr = SHIFT_OFFS1;		// adjust signal pointers to 16k buffers with 80k shift space up
		S2Ptr = SHIFT_OFFS2;
		S3Ptr = SHIFT_OFFS3;
		S4Ptr = SHIFT_OFFS4;
		SMPtr = SHIFT_OFFSM;

		for(int i=MemStartOffs;i<MemoryEnd;i++)
		{
			SHIFT_OFFS1[i] = SIGNAL1[i];
			SHIFT_OFFS2[i] = SIGNAL2[i];
			SHIFT_OFFS3[i] = SIGNAL3[i];
			SHIFT_OFFS4[i] = SIGNAL4[i];
			SHIFT_OFFSM[i] = SIGNALM[i];
		}

	}

	Hardware::Reset_Timer2();

	Trig_Pos_Mem = USTB_idx;
	Trig_Pos_Display = (int) ((float)(Trig_Pos_Mem - MemWinStart) / ZoomFactor);
	//Trig_Pos_Display_dmode = (int) (((float)(Trig_Pos_Mem - MemWinStart) / ZoomFactorDel) - ((float) Cursor_Delayed_1 * (ZoomFactor / ZoomFactorDel)));

}
//##########################################################################################################################################################
// BF USTB mode: insert new sample to actual buffer (time) position.
void Signal::USTB_insertSample(short invert, unsigned char ADC_VirtualZero, unsigned char *USTB_buff ,unsigned char *Signal)
{

	int lNew_Value=0;
	int lix;

/*
	if (USTB_Mode == USTB_SHIFT)		// shift mode active?
	{
		// shift all values to the left or right if buffer end/start is reached
		if (USTB_Dir == USTB_FORWARD)
		{
//printf("Shift forward...");
			for (lix = MemoryEnd; lix > MemStartOffs; lix--)
			{ Signal[lix] = Signal[lix-1]; }
//printf("ready\r\n");
		}
		else if(USTB_Dir == USTB_REVERSE)
		{
//printf("Shift reverse...\r\n");
			for (lix = MemStartOffs; lix < MemoryEnd; lix++)
			{ Signal[lix] = Signal[lix+1]; }
//printf("ready\r\n");
		}

	}
*/
	// calculate average value of ADC data array
	for (lix = 0; lix < 128; lix++)
	{ lNew_Value += USTB_buff[lix]; }

	// divide by number of samples
	lNew_Value = lNew_Value >> 7;		

	// signal inverted??
	if (invert)
	{ lNew_Value = (ADC_VirtualZero<<1) - lNew_Value; }
	
	// write new value to the current time position
	Signal[USTB_idx] = (unsigned char)lNew_Value;
}
//##########################################################################################################################################################
// BF USTB mode: invert signal buffer
// calculation must be done in two steps to avoid spikes caused by double inversion
void Signal::USTB_invertSignal(unsigned char ADC_VirtualZero ,unsigned char *Signal)
{
	int idx_buff = USTB_idx;

	if (USTB_Dir == USTB_FORWARD)			// direction = forward
	{
		for (int i = idx_buff ;i < MemoryEnd;i++)
		{ Signal[i] = (ADC_VirtualZero<<1) - Signal[i];}

		for (int i = MemStartOffs;i < idx_buff;i++)
		{ Signal[i] = (ADC_VirtualZero<<1) - Signal[i];}

	}
	else						// direction = reverse
	{
		for (int i = idx_buff ;i > MemStartOffs;i--)
		{ Signal[i] = (ADC_VirtualZero<<1) - Signal[i];}

		for (int i = MemoryEnd ;i > idx_buff;i--)
		{ Signal[i] = (ADC_VirtualZero<<1) - Signal[i];}
	}

}
//##########################################################################################################################################################

void Signal::USTB_recalcMath(void)
{

	//---------------------------------------------
	//         MATH function multiply
	//---------------------------------------------
	if (MenuStatus[MENU_MATH][2] == BTN_ON)      		// multiply 
	{	
		//set global math scaling and offset for drawing routine
		math_scale = math_mul_scale - 166;
		Math_Offset = Math_Mul_Offset;
		
		//calculate main math signal
		calcMathMul(MemStartOffs, MemoryEnd, draw_factor, S1Ptr, S2Ptr, SMPtr);

	}	//multiply end

	//---------------------------------------------
	//         MATH function subtract
	//---------------------------------------------
	else if (MenuStatus[MENU_MATH][3] == BTN_ON)           	// subtract
	{	
		//set global math scaling and offset for drawing routine
		math_scale = math_sub_scale - 150;
		Math_Offset = Math_Sub_Offset;

		//calculate main math signal
		calcMathSub(MemStartOffs, MemoryEnd, draw_factor, S1Ptr, S2Ptr, SMPtr);
	}	//subtract end

	//---------------------------------------------
	//         MATH function add
	//---------------------------------------------
	else if (MenuStatus[MENU_MATH][4] == BTN_ON)           	// add
	{
		//set global math scaling and offset for drawing routine
		math_scale = math_add_scale - 150;
		Math_Offset = Math_Add_Offset;
		
		//calculate main math signal
		calcMathAdd(MemStartOffs, MemoryEnd, draw_factor, S1Ptr, S2Ptr, SMPtr);
	}	//add end



}
//##########################################################################################################################################################
/* BF */
// Build trigonometric tables for FFT
void Signal::FFT_buildTrigoTables(void)
{
	int l,buff; 	//,ar,v, la;
	int d[FFT_Level];	//Number of butterfly levels

	//Struktur vom Typ div_t erzeugen
	div_t s_div;

/*
	// create sin() and cos() table as integer values
	for(i=0;i < FFT_Length;i++)  			
	{
		sin_tab[i] = (int)(FFT_INTFACT * sin(i*2*PI/FFT_Length));
		cos_tab[i] = (int)(FFT_INTFACT * cos(i*2*PI/FFT_Length));
	}
*/	
	// create window and trigonometric tables
	for(short i=0,r=0 ;i < FFT_Length; i++)
	{
		_SinTab[i] = iSin1024[r];
		_CosTab[i] = iCos1024[r];

		_WinTab[i] = FFT_Window[FFT_Windex][r];
	
		if (FFT_Length == FFT_512)
		r+=2;
		else
		r++;	
	}

	
	//Bit-Reversal- Tabelle bit_rev[0..] anlegen
	for(int i=0, z, r;i < FFT_Length; i++)
	{
		z=i;
		//Dezimal-Index in Dualzahl umwandeln
		for(short ct=0 ;ct < FFT_Level; ct++)
		{
			s_div = div(z,2);
			d[ct] = (int)s_div.rem;		// den Rest ins Feld
			z     = (int)s_div.quot;	// den Quotienten nach z
		}
		//Bit-Revers anordnen
		s_div = div(FFT_Level,2);
		for(int ct=0 ;ct < (int)s_div.quot; ct++)
		{
			buff  = d[ct];
			d[ct] = d[FFT_Level-ct-1];
			d[FFT_Level-ct-1] = buff;
		}
		
		//Bit-Revers anordnen Zeitoptimiert mit Festwert
//		for(int buff,j=0;j<5;j++) 	        // 5 = FFT_LEVEL/radix  => x=div(FFT_LEVEL,2) => x.quot=5
//		{
//			buff 	     = d[j];
//			d[j] 	     = d[FFT_LEVEL-j-1];
//			d[FFT_LEVEL-j-1] = buff;
//		}

		//Umsortierten Index zurückwandeln in Dezimalzahl
		r=0;
		for(int ct=0;ct < FFT_Level; ct++)
		{
			r = r + (1<<ct) * d[ct];
		}
		//umsortierter Index
		_RevTab[i] = r;

	}//Ende Bit-Reversal-Tabelle

}
//##########################################################################################################################################################
/* BF */
// Calculate fast fourier transformation to get spectral analyzis of time signal. Trigonometric tables have to be build first.
// To get a periodic approximation, the time signal has to be processed with a window function. The simplest case is a 
// rectangle window, which has no side line suppression.
void Signal::FFT_calcSpectrum(unsigned char *Signal, int *Spectrum)
{
	// buffer for real and imaginary part of spectrum - sharing the memory with the signal interpolation
	int *freq_re = (int *)SIGNAL1_Intpolate;
	int *freq_im = (int *)SIGNAL1_Intpolate_delayed; 


	//Speicher auf dem Stack reservieren
	int l=0,i=0,j=0,r=0,ar=0,v=0;
	int Fz1=0,Fz2=0,Fz3=0,Fz4=0,Fxr=0,Fxi=0,Fyr=0,Fyi=0;
	int ScaleShiftFactor;  
	

	double logval;
//printf("starting fft\r\n");
//printf("starting FFT");	
	// set variable scaling
	if (FFT_Mode == FFT_PWSP || FFT_Mode == FFT_PWDN)
	ScaleShiftFactor = FFT_Level - 3;
	else
	ScaleShiftFactor = FFT_Level - 2;

//printf(" ->  level %d  shift factor %d",FFT_Level, ScaleShiftFactor);	

	//-----------------------------------------------
	// get time signal and make a window overlay
	//-----------------------------------------------

	//sort timevalues bitreversal
	for(i=0;i<FFT_Length;i++)
	{
		if(FFT_Windex == -1)
		freq_re[i] = (int)(Signal[_RevTab[i]] - ADC_ZERO);					// no window overlay -> rectangle
		else
		freq_re[i] =  (_WinTab[_RevTab[i]] * (int)(Signal[_RevTab[i]] - ADC_ZERO)) >> 13;	// window overlay

		freq_im[i] = 0;

		//printf("freq_re[%d] = ",i);floatprintf(freq_re[i]);
		//printf("     freq_im[%d] = ",i);floatprintf(freq_im[i]);printf("\r\n");
	}

	//-----------------------------------------------
	//             calculate FFT
	//-----------------------------------------------
//printf(" -> calculate butterflies");
	//calculate complex spectral values (butterflies)
	for(l=1;(l<=FFT_Level) && !UI_request;l++)	// level loop
	{
		for(i=0;i<=((1<<(FFT_Level-l))-1) && !UI_request;i++)
		{
			for(j=0;j<=((1<<(l-1))-1);j++)
			{
				r = j + i* (1 << l);
				ar= j * (FFT_Length >> l);
				v = 1 << (l-1);
				
				Fz1 = (_CosTab[ar] * freq_re[r+v]) >> 10;	//rescale from integer conversion
				Fz2 = (_CosTab[ar] * freq_im[r+v]) >> 10;	//rescale from integer conversion
				Fz3 = (_SinTab[ar] * freq_re[r+v]) >> 10;	//rescale from integer conversion
				Fz4 = (_SinTab[ar] * freq_im[r+v]) >> 10;	//rescale from integer conversion
				Fxr = freq_re[r] + Fz1 + Fz4;
				Fxi = freq_im[r] - Fz3 + Fz2;
				Fyr = freq_re[r] - Fz1 - Fz4;
				Fyi = freq_im[r] + Fz3 - Fz2;
				freq_re[r] = Fxr;
				freq_im[r] = Fxi;
				freq_re[r+v] = Fyr;
				freq_im[r+v] = Fyi;
			}
		}
	}


//printf("FFT mode = %d  length = %d\r\n",FFT_Mode,FFT_Length);
//printf(" - FFT mode = %d  length = %d",FFT_Mode,FFT_Length);
	switch(FFT_Mode)
	{
		case FFT_MAGN: 	// linear magnitude
		{
//printf(" -> FFT %d magnitude calculation...",FFT_Length);

			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2)  && !UI_request;i++)
			{
				//downscale depending on FFT length
				freq_re[i] = freq_re[i] >> ScaleShiftFactor;
				freq_im[i] = freq_im[i] >> ScaleShiftFactor;

				//calc total value via power of two
				v = (freq_re[i]*freq_re[i]) + (freq_im[i]*freq_im[i]);	// v = Re² + IM²

				// and square root
				//r = iSqrt(v);
				r = Math_Sqrt(v);

				//printf("freq_re[%d] = %d    ",i,freq_re[i]);
				//printf("freq_im[%d] = %d    ",i,freq_im[i]);	
				//printf("v = Re² + IM² = %d    ",v);
				//printf("r = sqrt(v) = %d",r);
				// scale to display size
				//r = r << 2;
				//printf("scale r = %d\r\n",r);	
				
				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = r;
				else
				{ 
					Spectrum[j]   = r;
					Spectrum[j+1] = r;
					j+=2;
				}	
				
			}
//printf("done");
			break;
		}
		
		case FFT_PHAS: 	// linear phase
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2)  && !UI_request;i++)
			{
				//downscale depending on FFT length
				freq_re[i] = freq_re[i] >> ScaleShiftFactor;
				freq_im[i] = freq_im[i] >> ScaleShiftFactor;


				r = 10;		//BF to be done!!!!!
				//phase = arctan(imag / real)


				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = r;
				else
				{ 
					Spectrum[j]   = r;
					Spectrum[j+1] = r;
					j+=2;
				}	

			}
			break;
		}

		case FFT_REAL: 	// linear real part
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2) && !UI_request;i++)
			{
				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = freq_re[i] >> ScaleShiftFactor;	//downscale depending on FFT length
					if (Spectrum[i] < 0)				//absolute value
					Spectrum[i] = -Spectrum[i];
			else
				{ 
					Spectrum[j]   = freq_re[i] >> ScaleShiftFactor;
					if (Spectrum[j] < 0)				//absolute value
					Spectrum[j] = -Spectrum[j];

					Spectrum[j+1] = Spectrum[j];
					j+=2;
				}	

			}
			break;
		}

		case FFT_IMAG: 	// linear imaginary part
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2) && !UI_request;i++)
			{
				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = freq_im[i] >> ScaleShiftFactor;	//downscale depending on FFT length
					if (Spectrum[i] < 0)				//absolute value
					Spectrum[i] = -Spectrum[i];

				else
				{ 
					Spectrum[j]   = freq_im[i] >> ScaleShiftFactor;
					if (Spectrum[j] < 0)				//absolute value
					Spectrum[j] = -Spectrum[j];

					Spectrum[j+1] = Spectrum[j];
					j+=2;
				}	

			}
			
			break;
		}

		case FFT_REIM: 	// linear real + imaginary
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2) && !UI_request;i++)
			{
				//downscale depending on FFT length
				freq_re[i] = freq_re[i] >> ScaleShiftFactor;
				freq_im[i] = freq_im[i] >> ScaleShiftFactor;
				//downscale depending on FFT length

				if (freq_re[i] < 0)				//absolute value
				freq_re[i] = -freq_re[i];
				if (freq_im[i] < 0)				//absolute value
				freq_im[i] = -freq_im[i];

				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = freq_re[i] + freq_im[i];		//add real and imaginary part
				else
				{ 
					Spectrum[j]   = freq_re[i] + freq_im[i];
					Spectrum[j+1] = Spectrum[j];
					j+=2;
				}	

			}

			
			break;
		}

		case FFT_PWSP: 	// power spectrum in dBm
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2)  && !UI_request;i++)
			{
				//downscale depending on FFT length
				freq_re[i] = freq_re[i] >> ScaleShiftFactor;
				freq_im[i] = freq_im[i] >> ScaleShiftFactor;

				//calc total value via power of two
				v = (freq_re[i]*freq_re[i]) + (freq_im[i]*freq_im[i]);	// v = Re² + IM²
	
				// and square root
				//r = iSqrt(v);
				r = Math_Sqrt(v);			//magnitude

				// calculate power spectrum
				// ps = 20 * log10(magn / ref)		ref = 0.316 V = 323/1024
				
				r = (r * 323) >> 10;			// magn/ref
				
				r = (int)iLog10[r];			//log10(magn/ref)
			
				r = r>>1;				//downscaling

				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = r;
				else
				{ 
					Spectrum[j]   = r;
					Spectrum[j+1] = r;
					j+=2;
				}	
				
			}
			break;
		}
		case FFT_PWDN: 	// power density spectrum in dBm
		{
			//get half of the spectrum because spectrum is mirrored at the middle and calculate output
			for (i=0,j=0;i < (FFT_Length/2)  && !UI_request;i++)
			{
				//downscale depending on FFT length
				freq_re[i] = freq_re[i] >> ScaleShiftFactor;
				freq_im[i] = freq_im[i] >> ScaleShiftFactor;

				//calc total value via power of two
				v = (freq_re[i]*freq_re[i]) + (freq_im[i]*freq_im[i]);	// v = Re² + IM²
	
				// and square root
				//r = iSqrt(v);
				r = Math_Sqrt(v);			//magnitude

				// calculate power spectrum
				// ps = 20 * log10(magn / ref)		ref = 0.316 V = 323/1024
				
				r = (r * 323) >> 10;			// magn/ref
				
				r = (int)iLog10[r];			//log10(magn/ref)

				// calculate power density spectrum
				// pd = ps - 10 * log10(ENBW * df)
				r -= FFT_NormENBW; 
				
			
				//r = r>>1;				//downscaling??

				//map to 512 or 1024 values
				if(FFT_Length == FFT_1024 )
					Spectrum[i] = r;
				else
				{ 
					Spectrum[j]   = r;
					Spectrum[j+1] = r;
					j+=2;
				}	
			}
			break;
		}

	}


    	//printf(" -> finished FFT\r\n");
}
//##########################################################################################################################################################
//multiply signals
void Signal::calcMathMul(int start, int stop, int stepwidth ,unsigned char *SignalData1, unsigned char *SignalData2, unsigned char *MathData)
{

	int lix,liy;
	int lbuffer, lvalue1,lvalue2;

	int lgain = 0; 

	int lzero1 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH1 / ScaleFactor[Selected_Voltage_CH1][GainIdx]));
	int lzero2 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH2 / ScaleFactor[Selected_Voltage_CH2][GainIdx]));;

	if (GainIdx!=0) lgain = 1;

	int lfactor = ((math_voltage_factor[lgain][Selected_Voltage_CH1] * predivisor[MenuStatus[1][3] - 104]) * (math_voltage_factor[lgain][Selected_Voltage_CH2] * predivisor[MenuStatus[2][3] - 104]));

	lfactor = lfactor << 8;
	lfactor /= math_voltage_factor[lgain][math_scale];
	lfactor = lfactor << 8;
	//lfactor /= math_voltage_factor[lgain][math_scale];
	lfactor /= math_rescale[lgain][math_scale];

	for (lix=start, liy=start; lix < stop  && !UI_request; lix++)
	{
		if (lix != liy)		// interpolate points between step width
		{ MathData[lix] = MathData[lix-1]; continue; }

		liy += stepwidth;

		//convert to signed integer and shift to zero
		lvalue1 = (int)SignalData1[lix] - lzero1;
		lvalue2 = (int)SignalData2[lix] - lzero2;

		lbuffer = (-((lvalue1 * lvalue2 * lfactor) >> 16 ) + ADC_ZERO);

		if (lbuffer > 255) lbuffer = 255;		//limiter
		else if(lbuffer < 0) lbuffer = 0;

		MathData[lix] = (unsigned char)lbuffer;
	}


}
//##########################################################################################################################################################
//subtract signals
void Signal::calcMathSub(int start, int stop, int stepwidth ,unsigned char *SignalData1, unsigned char *SignalData2, unsigned char *MathData)
{

	int lix,liy;
	int lbuffer, lvalue1,lvalue2;

	int lgain = 0; 

	int lzero1 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH1 / ScaleFactor[Selected_Voltage_CH1][GainIdx]));
	int lzero2 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH2 / ScaleFactor[Selected_Voltage_CH2][GainIdx]));;

	if (GainIdx!=0) lgain = 1;

	int lfactor1 = ((math_voltage_factor[lgain][Selected_Voltage_CH1] * predivisor[MenuStatus[1][3] - 104])<<12) / math_voltage_factor[lgain][math_scale];
	int lfactor2 = ((math_voltage_factor[lgain][Selected_Voltage_CH2] * predivisor[MenuStatus[2][3] - 104])<<12) / math_voltage_factor[lgain][math_scale];

	for (lix=start, liy=start; lix < stop  && !UI_request; lix++)
	{
		if (lix != liy)		// interpolate points between step width
		{ MathData[lix] = MathData[lix-1]; continue; }

		liy += stepwidth;

		//convert to signed integer and shift to zero
		lvalue1 = (int)SignalData1[lix] - lzero1;
		lvalue2 = (int)SignalData2[lix] - lzero2;

		//scale signals
		lvalue1 *= lfactor1;
		lvalue2 *= lfactor2;

		MathData[lix] = (unsigned char)(((lvalue1 - lvalue2)>>12) + ADC_ZERO);
	}

}
//##########################################################################################################################################################
//add signals
void Signal::calcMathAdd(int start, int stop, int stepwidth ,unsigned char *SignalData1, unsigned char *SignalData2, unsigned char *MathData)
{
	int lix,liy;
	int lbuffer, lvalue1,lvalue2;

	int lgain = 0; 

	int lzero1 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH1 / ScaleFactor[Selected_Voltage_CH1][GainIdx]));
	int lzero2 = (ADC_ZERO + int((float)Virtual_ZeroLevelCH2 / ScaleFactor[Selected_Voltage_CH2][GainIdx]));;

	if (GainIdx!=0) lgain = 1;

	//printf("\r\nCalcMathAdd\r\n");
	//printf("zero corr1 : %d   zero corr2 : %d\r\n",lzero1,lzero2);

	int lfactor1 = ((math_voltage_factor[lgain][Selected_Voltage_CH1] * predivisor[MenuStatus[1][3] - 104])<<12) / math_voltage_factor[lgain][math_scale];
	int lfactor2 = ((math_voltage_factor[lgain][Selected_Voltage_CH2] * predivisor[MenuStatus[2][3] - 104])<<12) / math_voltage_factor[lgain][math_scale];

	//printf("factor 1 : %d   factor 2 : %d\r\n",lfactor1,lfactor2);

	for (lix=start, liy=start; lix < stop  && !UI_request; lix++)
	{
		if (lix != liy)		// interpolate points between step width
		{ MathData[lix] = MathData[lix-1]; continue; }

		liy += stepwidth;

		//convert to signed integer and shift to zero
		lvalue1 = (int)SignalData1[lix] - lzero1;
		lvalue2 = (int)SignalData2[lix] - lzero2;

		//printf("S1 - zero = %d - %d = %d   S2 - zero = %d - %d = %d\r\n",SignalData1[lix], lzero1, lvalue1, SignalData2[lix], lzero2, lvalue2);

		//scale signals
		lvalue1 *= lfactor1;
		lvalue2 *= lfactor2;

		//printf("val1 * factor1 = %d   val2 * factor =  %d\r\n",lvalue1, lvalue2);

		MathData[lix] = (unsigned char)(((lvalue1 + lvalue2)>>12) + ADC_ZERO);

		//printf("val1 + val2 + 127 =  %d\r\n",MathData[lix]);
		//printf("----------------------------------------------------\r\n");

	}

}
//##########################################################################################################################################################
/*! Timebase 50ns is the fastest real timebase. For timebase 20nS, 10nS, 5nS and 2nS the additional samples must be interpolated. 
    Linear interpolation is faster, sin(x)/x is more accurate and depends on upsampling combined with FIR filtering.
    Interpolation is also needed for some delayed TB */

void Signal::interpolate(int timebase, int start, unsigned char *SignalData, unsigned char *InterpolateResult)
{
    int ix,iy,incr;
	
	if (UI_request) return;	

	//printf("\r\ninterpolation start %d\r\n", start);	

	if(MenuStatus[MENU_ACQUIRE][3] == 42)	// linear
	{
		//printf("Linear interpolation on TB %d\r\n", timebase);

		if (timebase == 0)		// 2ns 
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 25);ix+=25,iy++)
			interpolateLinear(ix, (int)SignalData[iy], ix + 25, (int)SignalData[iy+1], InterpolateResult);
		}
		else if (timebase == 1)		// 5ns 
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 10);ix+=10,iy++)
			interpolateLinear(ix, (int)SignalData[iy], ix + 10, (int)SignalData[iy+1], InterpolateResult);
		}
		else if (timebase == 2)		// 10ns 
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 5);ix+=5,iy++)
			interpolateLinear(ix, (int)SignalData[iy], ix + 5, (int)SignalData[iy+1], InterpolateResult);
		}
		else if (timebase == 3)		// 20ns 
		{
			for(ix=0,iy=start,incr=2;ix < (GRID_WIDTH + 25);ix+=incr,iy++)
			{
				//toggle increment
				if(incr == 2){incr = 3;}
				else{incr = 2;}

				interpolateLinear(ix, (int)SignalData[iy], ix + incr, (int)SignalData[iy+1], InterpolateResult);
			}

		}
		else
		{ printf("\r\nUnsupported timebase %d\r\n", timebase); }
	
	}
	else if(MenuStatus[MENU_ACQUIRE][3] == 43)	//sin(x)/x interpolation
	{
	
		// upsampling via zero stuffing (zero padding)
		if (timebase == 0)		// 2ns ->25GSa/s
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 25);ix+=25,iy++)
			{
				FIR_Buffer[ix] = SignalData[iy];		//upsampling
				for(int i=1;i<25;i++)
				FIR_Buffer[ix+i] = ADC_ZERO;			//fill up with zero
			}
			FIR_SincFilter(0, GRID_WIDTH + 25, FIR_Buffer, InterpolateResult);
		}
		else if (timebase == 1)		// 5ns -> 10GSa/s
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 10);ix+=10,iy++)
			{
				FIR_Buffer[ix] = SignalData[iy];		//upsampling
				for(int i=1;i<10;i++)
				FIR_Buffer[ix+i] = ADC_ZERO;			//fill up with zero
			}
			FIR_SincFilter(0, GRID_WIDTH + 10, FIR_Buffer, InterpolateResult);
		}
		else if (timebase == 2)		// 10ns -> 5GSa/s
		{
			for(ix=0,iy=start;ix < (GRID_WIDTH + 5);ix+=5,iy++)
			{	
				FIR_Buffer[ix] = SignalData[iy];		//upsampling
				FIR_Buffer[ix+1] = ADC_ZERO;			//fill up with zero
				FIR_Buffer[ix+2] = ADC_ZERO;
				FIR_Buffer[ix+3] = ADC_ZERO;
				FIR_Buffer[ix+4] = ADC_ZERO;
			}
			FIR_SincFilter(0, GRID_WIDTH + 5, FIR_Buffer, InterpolateResult);
		}
		else if (timebase == 3)		// 20ns -> 2.5GSa/s
		{
			for(ix=0,iy=start,incr=2;ix < (GRID_WIDTH + 5);ix+=incr,iy++)
			{
				FIR_Buffer[ix] = SignalData[iy];		//upsampling
				FIR_Buffer[ix+1] = ADC_ZERO;			//fill up with zero
				
				if(incr == 2){incr = 3;}			//toggle increment to simulate 2.5
				else{incr = 2; FIR_Buffer[ix+2] = ADC_ZERO;}	//fill up with additional zero
			}
			FIR_SincFilter(0, GRID_WIDTH + 5, FIR_Buffer, InterpolateResult);
		}
		else
		{ printf("\r\nUnsupported timebase %d\r\n", timebase); }



		// sinc interpolation with ideal FIR low pass filter

		//for(ix=0;ix<(GRID_WIDTH + 25);ix++)
		//InterpolateResult[ix] = FIR_Buffer[ix];

		//FIR_Filter(0, GRID_WIDTH + 25, FIR_Buffer, InterpolateResult);
		//FIR_sinc(unsigned char length, short bit_width, int start, int stop, unsigned char *input, unsigned char *output)
	}



}
//##########################################################################################################################################################
/*! linear interpolation with Bresenham algorithm */
inline void Signal::interpolateLinear(int x1, int y1, int x2, int y2, unsigned char *interpolation)
{
	
	//--------------------------------------------
	//special case horizontal line
	//--------------------------------------------
	if(y1 == y2)
	{
		if(x1 < x2)
		for(; x1 != x2; x1++)	{ interpolation[x1] = (char)y1; }
		else
		for(; x2 != x1; x2++)	{ interpolation[x2] = (char)y1; }
		return;
	}	

	//--------------------------------------------
	//special case vertical line
	//--------------------------------------------
	else if(x1 == x2)
	{
		if(y1 < y2)
		for(; y1 != y2; y1++)	{ interpolation[x1] = (char)y1; }
		else
		for(; y2 != y1; y2++)	{ interpolation[x1] = (char)y2; }
		return;
	}	

	//-------------------------------------------------------------
	// Bresenham algorithm for drawing diagonal lines
	//-------------------------------------------------------------
	int dy = y2 - y1;
        int dx = x2 - x1;
        int stepx, stepy;

	//check if delta is positive or negative
	if (dy < 0) { dy = -dy;  stepy = -1; } else { stepy = 1; }
        if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }

	//special case exact 45 degrees delta x / delta y = 1
	if (dx == dy)
	{
		//horizontal and vertical component increment constant with 1 
		if(x1 < x2) 
		{
			if(y1 < y2)
			{ 
				for(; x1 != x2; x1++, y1++)
				{ interpolation[x1] = (char)y1; }
				return;
			}
			else if(y1 > y2)
			{
				for(; x1 != x2; x1++, y1--)
				{ interpolation[x1] = (char)y1; }
				return;
			}
			
		}
		else if(x1 > x2)
		{
			if(y1 < y2) 
			{
				for(; x1 != x2; x1--, y1++)
				{ interpolation[x1] = (char)y1; }
				return;
			}
			else if(y1 > y2)
			{
				for(; x1 != x2; x1--, y1--)
				{ interpolation[x1] = (char)y1; }
				return;
			}
		}
	}

	
        dy <<= 1;                              		// dy is now 2*dy
        dx <<= 1;                              		// dx is now 2*dx
	
	//set starting point
	interpolation[x1] = (char)y1;
	
	//---------------------------------------------
	//between horizontal and 45 degrees
	//---------------------------------------------
	if (dx > dy)
	{
		int fraction = dy - (dx >> 1);   	// same as 2*dy - dx
		while (x1 != x2) {
			if (fraction >= 0) {
			y1 += stepy;
			fraction -= dx;              	// same as fraction -= 2*dx
			}
			x1 += stepx;
			fraction += dy;          	// same as fraction -= 2*dy
			interpolation[x1] = (char)y1;
		}
        	return;
	}

	//---------------------------------------------
	//between vertical and 45 degrees
	//---------------------------------------------
	if (dx < dy)
	{
		int fraction = dx - (dy >> 1);
		while (y1 != y2) {
			if (fraction >= 0) {
			x1 += stepx;
			fraction -= dy;
			}
			y1 += stepy;
			fraction += dx;
			interpolation[x1] = (char)y1;
		}
		return;
        }

}
//##########################################################################################################################################################
// BF -> generate test signals on all channels
void Signal::generateTestSignal(void)
{
	int ix, iy, tog, pw;
	int  lVirtual_Zero = 0;
	char lDCOffset     = 0;

	if (Channel_1_Active)	// draw rectangle signal
	{
		lVirtual_Zero = ADC_ZERO + (int)((float)Virtual_ZeroLevelCH1 / ScaleFactor[Selected_Voltage_CH1][GainIdx]);
		if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
		if (lVirtual_Zero < 0) lVirtual_Zero = 0;
	
		// Signal 1 (Yellow)
		tog = 0;
		iy = lVirtual_Zero + 100;		//Amplitude

		if ( MenuStatus[MENU_CHANNEL1][0] == 8) 	//AC
		lDCOffset = 0;//-20;
		else if ( MenuStatus[MENU_CHANNEL1][0] == 7)	//DC
		lDCOffset = 0;
		else						//GND
		{
			for (ix = 0; (ix < 16384) && !UI_request; ix++)
			SIGNAL1[ix] = lVirtual_Zero;
		}
		
		if ( MenuStatus[MENU_CHANNEL1][0] != 6)
		for (ix = 0, pw = 0; (ix < 16384) && !UI_request; ix++, pw++)
		{	
			//if (ix %200 == 0) 		//Pulswidth
			//if (ix %50 == 0) 		//Pulswidth
			if(pw==50)			//Pulswidth
			{
				pw = 0;
				if (tog == 0) tog = 1;
				else tog = 0;
			}
			
			if (tog == 0)
			{ iy = lVirtual_Zero - 73; }	//Amplitude
			else
			{ iy = lVirtual_Zero + 72;}	//Amplitude
	
			if (iy > 255) iy = 255;	//Limiter
			if (iy < 0) iy = 0;
		
			SIGNAL1[ix] = (char)iy + lDCOffset;
		}	
	
	}

	if (Channel_2_Active)
	{
		lVirtual_Zero = ADC_ZERO + int((float)Virtual_ZeroLevelCH2 / ScaleFactor[Selected_Voltage_CH2][GainIdx]);
		if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
		if (lVirtual_Zero < 0) lVirtual_Zero = 0;

		// Signal 2 (Green)
		tog = 0;	
		iy = lVirtual_Zero;
	
		if ( MenuStatus[MENU_CHANNEL2][0] == 8) 	//AC
		lDCOffset = 0;
		else if ( MenuStatus[MENU_CHANNEL2][0] == 7)	//DC
		lDCOffset = 20;
		else						//GND
		{
			for (ix = 0; (ix < 16384) && !UI_request; ix++)
			SIGNAL2[ix] = lVirtual_Zero;
		}

		if ( MenuStatus[MENU_CHANNEL2][0] != 6)
		// calculate sinus signal
		for (ix = 0, iy = 0; (ix < 16384) && !UI_request; ix++, iy+=4)
		{
			if(iy >= 1024)
			iy = 0;

			SIGNAL2[ix] = lVirtual_Zero + (iSin1024[iy] >> 4);
		}
		
/*
		// calculate triangle signal
		for (ix = 0; (ix < 16384) && !UI_request; ix++)
		{
			if (ix %80 == 0)
			{
				if (tog == 0) tog = 1;
				else tog = 0;
			}
			
			if (ix %2 == 0)
			{
				if (tog == 0) iy++;
				else iy--;
			}
			if (iy > 255) iy = 255;	//Limiter
			if (iy < 0) iy = 0;

			SIGNAL2[ix] = (char)iy + lDCOffset;
		}	
*/	
	}

	if (NumberOfChannels == 2)
	return;

	if (Channel_3_Active)
	{
		lVirtual_Zero = ADC_ZERO + int((float)Virtual_ZeroLevelCH3 / ScaleFactor[Selected_Voltage_CH3][GainIdx]);
		if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
		if (lVirtual_Zero < 0) lVirtual_Zero = 0;

		// Signal 3 (Purple)
		tog = 0;	
		iy = lVirtual_Zero + 25;
		
		if ( MenuStatus[MENU_CHANNEL3][0] == 8) 	//AC
		lDCOffset = -30;
		else if ( MenuStatus[MENU_CHANNEL3][0] == 7)	//DC
		lDCOffset = 0;
		else						//GND
		{
			for (ix = 0; (ix < 16384) && !UI_request; ix++)
			SIGNAL3[ix] = lVirtual_Zero;
		}

		
		if ( MenuStatus[MENU_CHANNEL3][0] != 6)
		for (ix = 0, pw = 0; (ix < 16384) && !UI_request; ix++,pw++)
		{	
			//if (ix %150 == 0) 		//Pulswidth
			if (pw == 150) 			//Pulswidth
			{
				pw = 0;
				if (tog == 0) tog = 1;
				else tog = 0;
			}
			
			if (tog == 0)
			{ iy = lVirtual_Zero - 25; }	//Amplitude
			else
			{ iy = lVirtual_Zero + 25;}	//Amplitude
	
			if (iy > 255) iy = 255;	//Limiter
			if (iy < 0) iy = 0;
		
			SIGNAL3[ix] = (char)iy + lDCOffset;
		}	
	}

	if (Channel_4_Active)
	{
		lVirtual_Zero = ADC_ZERO + int((float)Virtual_ZeroLevelCH4 / ScaleFactor[Selected_Voltage_CH4][GainIdx]);
		if (lVirtual_Zero > 255) lVirtual_Zero = 255;	//Limiter
		if (lVirtual_Zero < 0) lVirtual_Zero = 0;

		// Signal 4 (Red)
		tog = 0;	
		iy = lVirtual_Zero;
		
		
		if ( MenuStatus[MENU_CHANNEL4][0] == 8) 	//AC
		lDCOffset = 0;
		else if ( MenuStatus[MENU_CHANNEL4][0] == 7)	//DC
		lDCOffset = 25;
		else						//GND
		{
			for (ix = 0; (ix < 16384) && !UI_request; ix++)
			SIGNAL4[ix] = lVirtual_Zero;
		}
	
		if ( MenuStatus[MENU_CHANNEL4][0] != 6)
		for (ix = 0; (ix < 16384) && !UI_request; ix++)
		{
			if (ix %100 == 0)			//period
			{
				if (tog == 0) tog = 1;
				else tog = 0;
			}
			
			if (ix %2 == 0)	 			//Amplitude
			{
				if (tog == 0) iy++;
				else iy--;
			}
			if (iy > 255) iy = 255;	//Limiter
			if (iy < 0) iy = 0;

			SIGNAL4[ix] = (char)iy + lDCOffset;
		}	
	}
	if(FFT_Mode != FFT_OFF)
	FFT_NewData = 1;


}
//##########################################################################################################################################################
//BF for combi-trigger
void Signal::calcMinMax(int start, int stop, int stepwidth ,unsigned char *SignalData1,  unsigned char *min, unsigned char *max){
  	int lix;
	int lbuffer, lvalue1,lvalue2;
	
	*min=255;
	*max=0;

	for (lix = start; lix < stop; lix+=stepwidth)
	{
		//convert to signed integer
		if (SignalData1[lix]>*max)
			*max=SignalData1[lix];
		if (SignalData1[lix]<*min)
			*min=SignalData1[lix];
	}
}
//##########################################################################################################################################################
//BF lookup tables for drawing routines
void Signal::buildScaleLookupTable(void)
{

	for (int i=0;i<256;i++)
	{
		ScaleLookupTable[i][0] = (short)((float)(i-ADC_ZERO) * ScaleFactor[0][GainIdx]);	//1er + 2er ranges
		ScaleLookupTable[i][1] = (short)((float)(i-ADC_ZERO) * ScaleFactor[2][GainIdx]);	//5er ranges
	}


	switch(MenuStatus[MENU_ACQUIRE][0])
	{
/*
		case LOGA_OFF:	// analog mode
		{
			for (int i=0;i<256;i++)
			{
				ScaleLookupTable[i][0] = (short)((float)(i-ADC_ZERO) * ScaleFactor[0][GainIdx]);	//1er + 2er ranges
				ScaleLookupTable[i][1] = (short)((float)(i-ADC_ZERO) * ScaleFactor[2][GainIdx]);	//5er ranges
			}

			break;
		}
*/		case LOGA_TTL:	// fall through
		case LOGA_LVTTL:
		{
			/* 1V = 14 steps, high > 2V => 128 - 28 = 100, low < 0.8V => 115, middle is ca 107*/

			for (int i=0;i<107;i++)										// logic high
			{ ScaleLookupTable[i][2] = -50; }

			for (int i=107;i<256;i++)									// logic low
			{ ScaleLookupTable[i][2] = 0; }

			break;
		}
		case LOGA_CMOS:
		{
			/* 1V = 14 steps, high > 3.5V => 128 - 50 = 78, low < 1.5V => 106, middle is 92*/

			// logic high
			for (int i=0;i<92;i++)
			{ ScaleLookupTable[i][2] = -50; }


			// logic low
			for (int i=92;i<256;i++)
			{ ScaleLookupTable[i][2] = 0; }

			break;
		}
		case LOGA_CM25:
		{
			/* 1V = 44 steps, high > 1.7V => 128 - 53 = 75, low < 0.7V => 33, middle is 54*/
			/* 1V = 44 steps, high > 1.7V => 53, low < 0.7V => 95, middle is 74*/

			// logic high
			for (int i=0;i<74;i++)
			{ ScaleLookupTable[i][2] = -50; }


			// logic low
			for (int i=74;i<256;i++)
			{ ScaleLookupTable[i][2] = 0; }

			break;
		}
		case LOGA_CM18:
		{
			/* 1V = 44 steps, high > 1.17V => 128 - 75 = 53, low < 0.7V => 33, middle is 43*/
			/* 1V = 44 steps, high > 1.17V => 75, low < 0.7V => 95, middle is 85*/

			// logic high
			for (int i=0;i<85;i++)
			{ ScaleLookupTable[i][2] = -50; }


			// logic low
			for (int i=85;i<256;i++)
			{ ScaleLookupTable[i][2] = 0; }

			break;
		}
		case LOGA_RS232:	// negative logic
		{
			// logic low => 0 at +3V..15V
			for (int i=0;i<ADC_ZERO;i++)
			//{ ScaleLookupTable[i][2] = -50; }
			{ ScaleLookupTable[i][2] = 0; }

			// logic high => 1 at -3V..-15V
			for (int i=ADC_ZERO;i<256;i++)
			//{ ScaleLookupTable[i][2] = 0; }
			{ ScaleLookupTable[i][2] = -50; }

			break;
		}


	}







}
//##########################################################################################################################################################
//BF FFT lookup table for drawing routines
void Signal::FFT_buildScaleLookupTable(void)
{
	
	//get scaling index of active channel
	if(MenuStatus[MENU_FFT][0] == 137)	//FFT source channel 1
	{ 
		for (int i=0;i<256;i++)
		{ FFT_ScaleLookupTable[i] = (short)((float)i * ScaleFactor[0][GainIdx] * FFT_ScaleCorrection[Selected_Voltage_CH1][MenuStatus[MENU_FFT][2] - 66]); }
	}
	else if(MenuStatus[MENU_FFT][0] == 138)	//FFT source channel 2
	{ 
		for (int i=0;i<256;i++)
		{ FFT_ScaleLookupTable[i] = (short)((float)i * ScaleFactor[0][GainIdx] * FFT_ScaleCorrection[Selected_Voltage_CH2][MenuStatus[MENU_FFT][2] - 66]); }
	}
	else if(MenuStatus[MENU_FFT][0] == 139)	//FFT source channel 3
	{ 
		for (int i=0;i<256;i++)
		{ FFT_ScaleLookupTable[i] = (short)((float)i * ScaleFactor[0][GainIdx] * FFT_ScaleCorrection[Selected_Voltage_CH3][MenuStatus[MENU_FFT][2] - 66]); }
	}
	else if(MenuStatus[MENU_FFT][0] == 140)	//FFT source channel 4
	{ 
		for (int i=0;i<256;i++)
		{ FFT_ScaleLookupTable[i] = (short)((float)i * ScaleFactor[0][GainIdx] * FFT_ScaleCorrection[Selected_Voltage_CH4][MenuStatus[MENU_FFT][2] - 66]); }
	}



}
//##########################################################################################################################################################
//BF Noise Filter with proprietary algorithm
void Signal::LowPassFilter(int start, int stop, char strength, unsigned char *input, unsigned char *output)
{

	int lmin;					//values to the left side
	int lmax;					//values to the right side
	int lsum;					//totals
	

	// the samples between the undelayed samples are needed so we have to copy the complete signal window to output
	if (MenuStatus[MENU_TIMEBASE][1] == BTN_ON)
	{
		for(int i=start;i < stop ;i++)
		{ output[i] = input[i]; }
	}


	if (strength == 1)	// nearly lossless filtering -> corner frequency at 1GSa/s ca. 80 - 90Mhz
	{
		if (draw_factor < 4)
		{
			lmin = -1;
			lmax =  2;	

			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
			
				output[i] = (unsigned char)(lsum>>2);		// calculate average
			}

		}
		else if (draw_factor == 4 || draw_factor == 5)
		{
			lmin = -3;
			lmax = 4;
	
			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
				
				output[i] = (unsigned char)(lsum>>3);		// calculate average
			}
		}
		else if (draw_factor >= 10)	
 		{
			lmin = -7;
			lmax = 8;
	
			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
				
				output[i] = (unsigned char)(lsum>>4);		// calculate average
			}	
		}
	}
	else if (strength == 2)		// strong filtering with loss of bandwidth -> corner frequency at 1GSa/s ca. 30Mhz
	{

		if (draw_factor < 4)
		{
			lmin = -3;
			lmax =  4;	

			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
			
				output[i] = (unsigned char)(lsum>>3);		// calculate average
			}

		}
		else if (draw_factor == 4 || draw_factor == 5)
		{
			lmin = -7;
			lmax = 8;
	
			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
				
				output[i] = (unsigned char)(lsum>>4);		// calculate average
			}
		}
		else if (draw_factor >= 10)	
 		{
			lmin = -15;
			lmax = 16;
	
			for(int i=start;i < stop ;i+=draw_factor)		// go to next value
			{
				lsum = 0;
				for(int f=lmin;f<=lmax;f++)			// add the values from the left and the right
				lsum += input[i+f];
				
				output[i] = (unsigned char)(lsum>>5);		// calculate average
			}	
		}


	}


}
//##########################################################################################################################################################
//BF Noise Filter (low pass)	
// IIR algorithm  filterOutput(next) = filterOutput + k * (signal - filterOutput) (k = 0.0....1.0)
//  => y[i+1] = y[i] + (x[i]-y[i])/(2^k)
//
void Signal::IIR_Filter(int start, int stop, char stage, unsigned char *input, unsigned char *output)
{
	
	int lsum;
	int lstart = start -10;

	if(stage == 1)								// corner frequency at 1GSa/s ca. 70Mhz with coefficient 0.5 
	{
		output[lstart] = input[lstart];

		for (int i=lstart;i<stop;i++)
		{ 
			lsum = ((int)input[i] - (int)output[i])>>1;		// using 2 (coefficient 0.25) corner frequency is ca.  30Mhz
			output[i+1] = (unsigned char)((int)output[i] + lsum);	
		}
	}


	if(stage == 2)								// corner frequency at 1GSa/s ca. 35 - 40Mhz with coefficients 0.5 
	{
		CopyBuffer[lstart] = input[lstart];

		for (int i=lstart;i<stop;i++)
		{ 
			lsum = ((int)input[i] - (int)CopyBuffer[i])>>1;	
			CopyBuffer[i+1] = (unsigned char)((int)CopyBuffer[i] + lsum);	
		}

		output[lstart] = CopyBuffer[lstart];

		for (int i=lstart;i<stop;i++)
		{ 
			lsum = ((int)CopyBuffer[i] - (int)output[i])>>1;	
			output[i+1] = (unsigned char)((int)output[i] + lsum);	
		}

	}


	if(stage == 3)								// corner frequency at 1GSa/s ca. 20Mhz with coefficients 0.5 and 0.25 in the last stage
	{
		for (int i=lstart;i<stop;i++)
		{ 
			output[lstart] = input[lstart];

			lsum = ((int)input[i] - (int)output[i])>>1;	
			output[i+1] = (unsigned char)((int)output[i] + lsum);	
		}

		CopyBuffer[lstart] = output[lstart];

		for (int i=lstart;i<stop;i++)
		{ 
			lsum = ((int)output[i] - (int)CopyBuffer[i])>>1;	
			CopyBuffer[i+1] = (unsigned char)((int)CopyBuffer[i] + lsum);	
		}

		output[lstart] = CopyBuffer[lstart];

		for (int i=lstart;i<stop;i++)
		{ 
			lsum = ((int)CopyBuffer[i] - (int)output[i])>>2;	
			output[i+1] = (unsigned char)((int)output[i] + lsum);	
		}

	}


}
//##########################################################################################################################################################
/*
//BF average
void Signal::Average(int start, int stop, unsigned char mode, unsigned char *input, unsigned char *avrg_buffer)
{




}
*/
//##########################################################################################################################################################
// BF Logic Processor for analyzing logical signals with single ended I/O

/*	 Logic Type |   Low   |  High  
	--------------------------------
	 TTL 5V     | <=0.8V  | >=2.0V		=> positive logic
	--------------------------------
	 CMOS 5V    | <=1.5V  | >=3.5V		=> positive logic
	--------------------------------
	 LVTTL 3.3V | <=0.8V  | >=2.0V		=> positive logic
	--------------------------------
	 CMOS 2.5V  | <=0.7V  | >=1.7V		=> positive logic
	--------------------------------
	 CMOS 1.8V  | <=0.7V  | >=1.17V		=> positive logic
	--------------------------------
	 RS232      |-15V..-3V| 3V..15V		=> negative logic
	--------------------------------
*/
void Signal::LOGA_LogicProcessor(void)
{

	if (USTB_Mode != USTB_OFF) return;

	if (FFT_Mode != FFT_OFF) return;

	if (XY_Mode != 0) return;

	if (MenuStatus[MENU_ACQUIRE][0] == LOGA_OFF)
	{
			//if (LA_active) Signal::Build_ScaleLookupTable();
			LA_active = 0;	// break endless loop
			return;
	}


	//-------------------------------------------------------------------------
	//		prepare logic processing
	//-------------------------------------------------------------------------


	char lVoltRange = 0;
	int lTriggPos   = 0;		

	Channel_1_Active_bak = Channel_1_Active;
	Channel_2_Active_bak = Channel_2_Active;
	Channel_3_Active_bak = Channel_3_Active;
	Channel_4_Active_bak = Channel_4_Active;
	//Channel_Math_Active_bak = Channel_Math_Active;

	Channel_Math_Active = 0;


	// make adjustments for logic type
	switch(MenuStatus[MENU_ACQUIRE][0])
	{

		case LOGA_TTL:	// fall through
		case LOGA_LVTTL:
		{
			lTriggPos = (GRID_HEIGHT / 2) - 70;		// set trigger to 1.45V
			lVoltRange = 9;					// set voltage range 1V
			break;
		}
		case LOGA_CMOS:
		{
			lTriggPos = (GRID_HEIGHT / 2) - 125;		// set trigger to 2.5V
			lVoltRange = 9;					// set voltage range 1V
			break;
		}
		case LOGA_CM25:
		{
			lTriggPos = (GRID_HEIGHT / 2) - 115;		// set trigger to 1.2V
			lVoltRange = 8;					// set voltage range 500mV
			break;
		}
		case LOGA_CM18:
		{
			lTriggPos = (GRID_HEIGHT / 2) - 91;		// set trigger to 0.95V
			lVoltRange = 8;					// set voltage range 500mV
			break;
		}
		case LOGA_RS232:
		{
			lTriggPos = (GRID_HEIGHT / 2) - 6;		// set trigger to 0.5V
			lVoltRange = 11;				// set voltage range 5V
			break;
		}
	}
	
	//------------------------------------------------
	// 		setup trigger
	//------------------------------------------------
	
	if (!LA_active)							// backup only if LOGA was not active before
	{
		Selected_Voltage_CH1_bak = Selected_Voltage_CH1;
		Selected_Voltage_CH2_bak = Selected_Voltage_CH2;
		Selected_Voltage_CH3_bak = Selected_Voltage_CH3;
		Selected_Voltage_CH4_bak = Selected_Voltage_CH4;
	
		Trigger_Pos_CH1_bak = Trigger_Pos_CH1;
		Trigger_Pos_CH2_bak = Trigger_Pos_CH2;
		Trigger_Pos_CH3_bak = Trigger_Pos_CH3;
		Trigger_Pos_CH4_bak = Trigger_Pos_CH4;
	}

	// set channel voltage ranges
	if(MenuStatus[MENU_CHANNEL1][3] == 107)	//probe 10:1
	Selected_Voltage_CH1 = lVoltRange - 3;
	else					//probe 1:1
	Selected_Voltage_CH1 = lVoltRange;

	if(MenuStatus[MENU_CHANNEL2][3] == 107)	//probe 10:1
	Selected_Voltage_CH2 = lVoltRange - 3;
	else					//probe 1:1
	Selected_Voltage_CH2 = lVoltRange;

	if(MenuStatus[MENU_CHANNEL3][3] == 107)	//probe 10:1
	Selected_Voltage_CH3 = lVoltRange - 3;
	else					//probe 1:1
	Selected_Voltage_CH3 = lVoltRange;

	if(MenuStatus[MENU_CHANNEL4][3] == 107)	//probe 10:1
	Selected_Voltage_CH4 = lVoltRange - 3;
	else					//probe 1:1
	Selected_Voltage_CH4 = lVoltRange;


	Trigger_Pos_CH1 = lTriggPos;
	Trigger_Pos_CH2 = lTriggPos;
	Trigger_Pos_CH3 = lTriggPos;
	Trigger_Pos_CH4 = lTriggPos;

	ZeroLevelCH1 = (GRID_HEIGHT / 2);		// for calculating triggerlevel
	ZeroLevelCH2 = (GRID_HEIGHT / 2);
	ZeroLevelCH3 = (GRID_HEIGHT / 2);
	ZeroLevelCH4 = (GRID_HEIGHT / 2);

	// trigger mode
	TriggerWay = TRIG_EDGE;				// trigger edge
	LED_ON[4] = 0;	//Math off
	//LED_ON[7] = 0;	//QM off
	LED_ON[8] = 1;	//edge on
	LED_ON[10] = 0;	//puls off
	Hardware::Send_LED();

	MenuStatus[MENU_TRIGGERMODE][0] = TRIG_COMB;	// trigger mode combi
	MenuStatus[MENU_TRIGGERMODE][1] = 95;		// coupling DC
	HoldOff.Write_Value(0.0);			// holdoff off
	HoldOff_Value = 0;
	MenuStatus[MENU_TRIGGEREDGE][0] = 2;		// rising

	Hardware::SetupTrigger();

	Display::DRAWSTATUS(6, 1);			// Draw Trigger Level
	Display::DRAWSTATUS(7, 0);			// Draw Trigger Mode	
	Display::DRAWSTATUS(8, 0);			// Draw Trigger Way	

	if(QM_Enabled)
	{
		QM_Enabled = 0;
		QM_Vertical_Active = 0;
		QM_Horizontal_Active = 0;
		Display::DrawQMData(0);		// remove the QM data
	}	

	// set DAC to scale middle and set offset correction
	switch(lVoltRange)
	{
		case 6:
		case 9://1 V
		{
			CH1_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][0][0];
			CH2_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][1][0];
			CH3_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][2][0];
			CH4_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][3][0];
			break;
		}
		case 7:
		case 10://2 V
		{
			CH1_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][0][1];
			CH2_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][1][1];
			CH3_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][2][1];
			CH4_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][3][1];
			break;
		}
		case 8:
		case 11://5 V
		{
			CH1_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][0][2];
			CH2_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][1][2];
			CH3_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][2][2];
			CH4_DAC_Offset = DAC_MIDSCALE + DAC_Correction[CalSet][3][2];
			break;
		}
	}


	// center traces to grid middle and setup voltage ranges
	GainIdx = 0;
	Channel_1_Active = 1;	
	Channel_2_Active = 1;

	Hardware::SetSwitches(1, Selected_Voltage_CH1);
	Hardware::SetSwitches(2, Selected_Voltage_CH2);

	Hardware::SetDacOffset(1);	
	Hardware::SetDacOffset(2);

	UserIF::ON_LogicZero(&Virtual_ZeroLevelCH1, &ZeroLevelCH1);
	UserIF::ON_LogicZero(&Virtual_ZeroLevelCH2, &ZeroLevelCH2);	

	if (NumberOfChannels == 4)
	{
		Channel_3_Active = 1;
		Channel_4_Active = 1;
		Hardware::SetSwitches(3, Selected_Voltage_CH3);
		Hardware::SetSwitches(4, Selected_Voltage_CH4);
		Hardware::SetDacOffset(3);	
		Hardware::SetDacOffset(4);
		UserIF::ON_LogicZero(&Virtual_ZeroLevelCH3, &ZeroLevelCH3);
		UserIF::ON_LogicZero(&Virtual_ZeroLevelCH4, &ZeroLevelCH4);	
	}


	// restore channels
	Channel_1_Active = Channel_1_Active_bak;
	Channel_2_Active = Channel_2_Active_bak;
	Channel_3_Active = Channel_3_Active_bak;
	Channel_4_Active = Channel_4_Active_bak;

	if (Channel_1_Active)Display::DRAWSTATUS(1, 1);			// Logic Type
	if (Channel_2_Active)Display::DRAWSTATUS(2, 1);			// Logic Type
	if (NumberOfChannels == 4)
	{
		if (Channel_3_Active)Display::DRAWSTATUS(3, 1);		// Logic Type
		if (Channel_4_Active)Display::DRAWSTATUS(4, 1);		// Logic Type
	}

	// build scale lookup tables
	buildScaleLookupTable();


	if (LA_active) return; 						// don't allow recursive call
	else LA_active = 1; 						// set logic analyzer active

	MenuStatus[MENU_TIMEBASE][2]  = INACTIVE;			// deactivate XY-button
	MenuStatus[MENU_TIMEBASE][3]  = INACTIVE;			// deactivate FFT-button

	// modify cursor menu
	MenuItemDef[16][3] = 0;
	MenuItemDef[16][4] = 0;
	MenuItemDef[16][5] = 0;
	MenuStatus[16][0] = INACTIVE;

	// modify QM selection
	MenuPopupStatus[4][0] = 1;
	MenuPopupStatus[4][3] = 1;
	MenuPopupStatus[4][4] = 3;
	MenuPopupStatus[4][5] = 1;
	MenuPopupStatus[4][6] = 1;
	MenuPopupStatus[4][7] = 1;
	MenuPopupStatus[4][10] = 1;
	MenuPopupStatus[4][11] = 1;

	QM_Type_Old[0] = 5;		// freqency
	QM_Type_Old[1] = 0;		// none
	QM_Type_Old[2] = 0;		// none

	QM_Type[0] = QM_Type_Old[0];
	QM_Type[1] = QM_Type_Old[1];
	QM_Type[2] = QM_Type_Old[2];



	if (Cursor_Enabled)Display::DRAW_ALL_CURSOR();

printf("\n\rStarting logic processor \n\r");
	
	if(Run) Hardware::Start_Record();
	else SingleShot = 1;	//ACQ_NewData = 1;

	UI_request = 0;
	AS_request = 0;
	

	//-------------------------------------------------------------------------
	//		logic processor loop
	//-------------------------------------------------------------------------
	for(;LA_active;)
	{
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		//UserIF::Rotary_Interface();

		if (Rotary_Steps != 0)
		{
			UI_request = 0;		//reset UI-request flag	
		
			Hardware::ResetTimer3(TimerRotPeriod);
		
			if ((Rotary_Switch & 0x00000001) == 0x00000001) { UserIF::ON_Rotary_Position(); RC_user_if = 1;}				//memory browser
			else if ((Rotary_Switch & 0x00000002) == 0x00000002) { if (MenuStatus[MENU_TRIGGEREDGE][1] == 141) UserIF::ON_Trigger_Level(); }//trigger level only for extern
			else if ((Rotary_Switch & 0x00000004) == 0x00000004) { UserIF::ON_Main_Wheel(); RC_user_if = 1; }				//main wheel
			else if ((Rotary_Switch & 0x00000008) == 0x00000008) { UserIF::ON_LogicTB(); RC_user_if = 1; }
			else if ((Rotary_Switch & 0x00000010) == 0x00000010 && Run) { UserIF::ON_LogicZero(&Virtual_ZeroLevelCH2, &ZeroLevelCH2); }
			else if ((Rotary_Switch & 0x00000080) == 0x00000080 && Run) { UserIF::ON_LogicZero(&Virtual_ZeroLevelCH1, &ZeroLevelCH1); }
			else if ((Rotary_Switch & 0x00000100) == 0x00000100 && Run) { UserIF::ON_LogicZero(&Virtual_ZeroLevelCH4, &ZeroLevelCH4); }
			else if ((Rotary_Switch & 0x00000800) == 0x00000800 && Run) { UserIF::ON_LogicZero(&Virtual_ZeroLevelCH3, &ZeroLevelCH3); }
			
			Rotary_Steps = 0;
		}

		//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		//UserIF::Keyboard_Interface();

		if (Keyboard_Changed)
		{
			Keyboard_Changed = 0;
		
			ButtonChanged = 1;  //BF -> kann weg??	
					
			if      ((Keyboard_mem & 0x00080000) == 0x00) {UserIF::Buttonhandler(30); RC_user_if = 1; }	// Function Button 1
			else if ((Keyboard_mem & 0x00040000) == 0x00) {UserIF::Buttonhandler(31); RC_user_if = 1; }	// Function Button 2
			else if ((Keyboard_mem & 0x00020000) == 0x00) {UserIF::Buttonhandler(32); RC_user_if = 1; }	// Function Button 3
			else if ((Keyboard_mem & 0x00010000) == 0x00) {UserIF::Buttonhandler(33); RC_user_if = 1; }	// Function Button 4
			else if ((Keyboard_mem & 0x00400000) == 0x00) {UserIF::Buttonhandler(34); RC_user_if = 1; }	// Function Button 5
			else if ((Keyboard_mem & 0x00100000) == 0x00) {UserIF::Buttonhandler(35); RC_user_if = 1; }	// Function Button 6
			
			else if ((Keyboard_mem & 0x00200000) == 0x00) { UserIF::Buttonhandler(1); RC_user_if = 1; }	// Channel 1 Button
			else if ((Keyboard_mem & 0x00800000) == 0x00) { UserIF::Buttonhandler(2); RC_user_if = 1; }	// Channel 2 Button
			else if ((Keyboard_mem & 0x01000000) == 0x00) { UserIF::Buttonhandler(3); RC_user_if = 1; }	// Channel 3 Button 
			else if ((Keyboard_mem & 0x02000000) == 0x00) { UserIF::Buttonhandler(4); RC_user_if = 1; }	// Channel 4 Button		
			//else if ((Keyboard_mem & 0x00008000) == 0x00) UserIF::Buttonhandler(23);			// Auto Scale
			else if ((Keyboard_mem & 0x00000100) == 0x00) { UserIF::Buttonhandler(8); RC_user_if = 1; }	// Save/Recall
			else if ((Keyboard_mem & 0x00000800) == 0x00) { UserIF::Buttonhandler(17); RC_user_if = 1; }	// Quick Print
			else if ((Keyboard_mem & 0x00002000) == 0x00) UserIF::Buttonhandler(6);				// Utility
			else if ((Keyboard_mem & 0x00004000) == 0x00) { UserIF::Buttonhandler(16); RC_user_if = 1; }	// Cursor
			else if ((Keyboard_mem & 0x00000200) == 0x00) { UserIF::Buttonhandler(19); RC_user_if = 1; }	// Quick Messurement 
			else if ((Keyboard_mem & 0x00000400) == 0x00) { UserIF::Buttonhandler(0); RC_user_if = 1; }	// Acquire	
			else if ((Keyboard_mem & 0x00001000) == 0x00) { UserIF::Buttonhandler(5); RC_user_if = 1; }	// Display
			else if ((Keyboard_mem & 0x00000010) == 0x00) UserIF::Buttonhandler(14);			// Edge
			else if ((Keyboard_mem & 0x00000040) == 0x00) UserIF::Buttonhandler(12);			// Trigger Mode /Coupling
			else if ((Keyboard_mem & 0x00000080) == 0x00) UserIF::Buttonhandler(10);			// Mode Button (Main/Delayed)
			else if ((Keyboard_mem & 0x00000004) == 0x00) { UserIF::Buttonhandler(37); RC_user_if = 1; }	// Run / Stop Button
			else if ((Keyboard_mem & 0x00000008) == 0x00) UserIF::Buttonhandler(38);			// Single Button
			UI_request = 0;	
		}

		Hardware::Handle_ADC();

		//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		//Signal::ProcessSignalData();	// -> rausnehmen und drawfactor hier bestimmen, Interpolation übernehmen

		// draw factor and draw start
		if (((MainTimebase + VirtualTimebase) < 4) && FFT_Mode == FFT_OFF) 		// BF 20ns + 10ns + 5ns + 2ns main mode - interpolated signal
		{ draw_start = 0; draw_factor = 1; }
		else 										// BF >= 50ns main mode - true signal and FFT
		{ 
			draw_start = (short) MemWinStart + PreTrigComp;				// must be calculated new after every acquisition
			draw_factor = (short)ZoomFactor;
		}
		
		if (MenuStatus[MENU_TIMEBASE][1] == BTN_ON)					// Delayed
		{
			if (ZoomFactorDel < 1) 							// 20ns + 10ns delayed mode  - interpolated signal
			{
				draw_dm_ixstart  = 0;						// set to zero because whole interpolation buffer must be drawn
				draw_dm_ixfactor = (short) ZoomFactorDel;	
			}
			else									// >= 50ns delayed mode - true signal
			{
				draw_dm_ixstart  = MemWinStart + PreTrigComp + (short)((float)Cursor_Delayed_1 * ZoomFactor);	//BF #003
				draw_dm_ixfactor = (short) ZoomFactorDel;	
			}
		}

		S1Ptr = SIGNAL1;
		S2Ptr = SIGNAL2;
		S3Ptr = SIGNAL3;
		S4Ptr = SIGNAL4;

		//--------------------------------------------------------------------------------------
		//        	 Interpolation (time stretch) for timebase 20ns, 10ns 5ns 2ns
		//--------------------------------------------------------------------------------------
		short lDel_IntPol_Offs = MemWinStart + PreTrigComp + (short)((float)Cursor_Delayed_1 * ZoomFactor);	//BF #003 Interpolation offset for delayed signal
		int lCalcStart = MemWinStart + PreTrigComp;					// determine calculation range 
	
		if (Channel_1_Active)
		{	
			if ((MainTimebase + VirtualTimebase) < 4)
			{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S1Ptr, SIGNAL1_Intpolate); }
			
			if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1)) //delayed mode
			{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S1Ptr, SIGNAL1_Intpolate_delayed); }
		}
		
		if (Channel_2_Active)
		{	
			if ((MainTimebase + VirtualTimebase) < 4)
			{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S2Ptr, SIGNAL2_Intpolate); }
			
			if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
			{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S2Ptr, SIGNAL2_Intpolate_delayed); }
		}	
		//4-Channel Version
		if (NumberOfChannels == 4)
		{	
			if (Channel_3_Active)
			{	
				if ((MainTimebase + VirtualTimebase) < 4)
				{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S3Ptr, SIGNAL3_Intpolate); }
				
				if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
				{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S3Ptr, SIGNAL3_Intpolate_delayed); }
			}	
			
			if (Channel_4_Active)
			{		   	
				if ((MainTimebase + VirtualTimebase) < 4)
				{ interpolate(MainTimebase+VirtualTimebase, lCalcStart, S4Ptr, SIGNAL4_Intpolate); }
				
				if ((MenuStatus[MENU_TIMEBASE][1] == BTN_ON) && (ZoomFactorDel < 1))	//delayed mode
				{ interpolate(MainTimebase - DelayedTimebase - 1, lDel_IntPol_Offs, S4Ptr, SIGNAL4_Intpolate_delayed); }
			}
		}	



		//Display::DrawSignals();
		Display::LOGA_DrawTraces();	

		Hardware::TransferPlanes();

		AMDFlash::Write_Config_Flash();

	}	//end logic processor loop
printf("\n\rLeaving logic processor \n\r");

	//-------------------------------------------------------------------------
	//		reset to normal acquisition
	//-------------------------------------------------------------------------

	// remember channel status
	Channel_1_Active_bak = Channel_1_Active;
	Channel_2_Active_bak = Channel_2_Active;
	Channel_3_Active_bak = Channel_3_Active;
	Channel_4_Active_bak = Channel_4_Active;

	// restore voltage ranges
	Selected_Voltage_CH1 = Selected_Voltage_CH1_bak;
	Selected_Voltage_CH2 = Selected_Voltage_CH2_bak;
	Selected_Voltage_CH3 = Selected_Voltage_CH3_bak;
	Selected_Voltage_CH4 = Selected_Voltage_CH4_bak;

	// restore trigger level
	Trigger_Pos_CH1 = Trigger_Pos_CH1_bak;
	Trigger_Pos_CH2 = Trigger_Pos_CH2_bak;
	Trigger_Pos_CH3 = Trigger_Pos_CH3_bak;
	Trigger_Pos_CH4 = Trigger_Pos_CH4_bak;

	GainIdx = MenuStatus[MENU_HARDWARE][1] - 230;			//set gain index to get the correct scaling

	// set all channels active to take the changes affect
	Channel_1_Active = 1;	
	Channel_2_Active = 1;

	// set restored voltage ranges
	Hardware::SetSwitches(1, Selected_Voltage_CH1);
	Hardware::SetSwitches(2, Selected_Voltage_CH2);

	//activate settings
	Rotary_Steps = 0;
	UserIF::ON_Zero_Channel_1();
	Rotary_Steps = 0;
	UserIF::ON_Zero_Channel_2();
	if (NumberOfChannels == 4)
	{
		Channel_3_Active = 1;
		Channel_4_Active = 1;
	
		Hardware::SetSwitches(3, Selected_Voltage_CH3);
		Hardware::SetSwitches(4, Selected_Voltage_CH4);

		Rotary_Steps = 0;
		UserIF::ON_Zero_Channel_3();
	
		Rotary_Steps = 0;
		UserIF::ON_Zero_Channel_4();
	}

	// restore channel status
	Channel_1_Active = Channel_1_Active_bak;
	Channel_2_Active = Channel_2_Active_bak;
	Channel_3_Active = Channel_3_Active_bak;
	Channel_4_Active = Channel_4_Active_bak;

	if (Channel_1_Active)Display::DRAWSTATUS(1, 1);			// voltage range
	if (Channel_2_Active)Display::DRAWSTATUS(2, 1);			// voltage range
	if (NumberOfChannels == 4)
	{
		if (Channel_3_Active)Display::DRAWSTATUS(3, 1);		// voltage range
		if (Channel_4_Active)Display::DRAWSTATUS(4, 1);		// voltage range
	}

	Display::DRAWSTATUS(6, 1);					// Draw Trigger Level

	// restore cursor menu
	MenuItemDef[16][3] = 41;
	MenuItemDef[16][4] = 41;
	MenuItemDef[16][5] = 35;
	MenuStatus[16][0] = 27;

	// restore QM selection
	MenuPopupStatus[4][0] = 3;
	MenuPopupStatus[4][3] = 2;
	MenuPopupStatus[4][4] = 2;
	MenuPopupStatus[4][5] = 2;
	MenuPopupStatus[4][6] = 2;
	MenuPopupStatus[4][7] = 2;
	MenuPopupStatus[4][10] = 2;
	MenuPopupStatus[4][11] = 2;

	MenuStatus[MENU_TIMEBASE][2]  = BTN_OFF;			// reactivate XY-button
	MenuStatus[MENU_TIMEBASE][3]  = BTN_OFF;			// reactivate FFT-button
	
	//if(!Run) ACQ_NewData = 1;
	if(!Run) SingleShot = 1;
	//if(Run) Start_Record();
	//else ADC_Data_Available = 0;

	// build scale lookup tables
	buildScaleLookupTable();

	//RC_overlay = 0;	->?????
}
//##########################################################################################################################################################
/*Basic FIR with floating point calculation
#define NZEROS 	10
#define GAIN_DIV   5.023437500e+00	//divisor
#define GAIN_FAC   0.199066874		//factor

static float xv[NZEROS+1];

static float xcoeffs[] = { +0.0468750000, +0.1250000000, +0.3281250000, +0.6250000000,
			   +0.8906250000, +0.9921875000, +0.8906250000, +0.6250000000,
			   +0.3281250000, +0.1250000000, +0.0468750000,
			 };

void Signal::FIR_Filter(int start, int stop, unsigned char *input, unsigned char *output)
{
	for (int sample=start;sample<stop;sample++)
     	{ 
		float sum; int i;
		for (i = 0; i < NZEROS; i++) xv[i] = xv[i+1];
		xv[NZEROS] = (float)input[sample] * GAIN_FAC;
		sum = 0.0;
		for (i = 0; i <= NZEROS; i++) sum += (xcoeffs[i] * xv[i]);
		output[sample] = (unsigned char)sum;
	}
}
*/
//##########################################################################################################################################################
/*Basic fixed point FIR algorithm without optimization 
#define NZEROS 10
static short xv[NZEROS+1];
static short xcoeffs[] = {  +46, +108, +280, +511, +709, +787, +709, +511, +280,  +108,  +46 };


void Signal::FIR_Filter(int start, int stop, unsigned char *input, unsigned char *output)
{
	short lstop = stop+NZEROS/2;

	for (short sample=start-NZEROS;sample<lstop;sample++)
     	{ 
		int sum; char i;
		for (i = 0; i < NZEROS; i++) xv[i] = xv[i+1];				//shift values one step through the delay chain -> can be made faster by circular buffer
		xv[NZEROS] = (short)input[sample] - ADC_ZERO;				//get next input value and convert to signed
		sum = 0;								//initialize adder
		for (i = 0; i <= NZEROS; i++){
		//if(xv[i]==0)continue;
		sum += (xcoeffs[i] * xv[i]);}		//multiply and add
		output[sample-NZEROS/2] = (unsigned char)(sum >> 12) + ADC_ZERO;	//rescale, convert to unsigned and compensate group delay
	}
}

*/
//##########################################################################################################################################################
/****************************************************************************************
/*! Fixed point FIR algorithm with circular buffer and multiplication by lookup table
*   and integer precision of 15 bit for noise filtering.
*  The advantage of circular buffers is that they alleviate the need to move
*  data samples around in the delay line (as in the basic algorithm). 
*  Most DSP microprocessors implement circular buffers in hardware, which 
*  allows a single FIR tap can be calculated in a single instruction.  
*  but since C doesn't have any constructs to represent circular
*  buffers, you need to "fake" them in C by adding an extra "if" statement
*  inside the FIR calculation, to reset the circular pointer.
*****************************************************************************************/
void Signal::FIR_NoiseFilter(int start, int stop, unsigned char *input, unsigned char *output)
{
	short lstop = stop+((FIR_LENGTH-1)/2);

    	char coeff, cpointer=0;
    	int accum;
	short circ_buff[FIR_LENGTH];

	// initialize circular buffer
	//for(ii = 0; ii < NCOEFF; ii++)
	//circ_buff[ii] = 0;

	for (short sample=start-(FIR_LENGTH-1); sample<lstop; sample++)
	{ 
		circ_buff[cpointer] = (short)input[sample];// - ADC_ZERO;// * gain;		// get next input value,and store it at the beginning of the delay line
												// conversion to signed is done in lookup table, gain is included in coeffs
		if (++cpointer >= FIR_LENGTH)         						// incr circular pointer and check for wrap 
        	{ cpointer = 0; }

    		// calc FIR and rotate circular buffer pointer
		accum = 0;
    		for (coeff = 0; coeff < FIR_LENGTH; coeff++)
		{ 
			accum += _FirLookup[coeff][circ_buff[cpointer]];			// MAC operation by lookup table

			if (++cpointer >= FIR_LENGTH)         					// incr circular pointer and check for wrap 
			{ cpointer = 0; }
		}

		output[sample-((FIR_LENGTH-1)/2)] = (unsigned char)(accum >> 15) + ADC_ZERO;	// rescale, convert to unsigned and compensate group delay
												// integer width is fixed to 15 bit	
	}

}
//##########################################################################################################################################################
/*! Fixed point FIR algorithm with circular buffer and multiplication by lookup table.
    For sinc interpolation only, variable filter length and integer word size */
void Signal::FIR_SincFilter(int start, int stop, unsigned char *input, unsigned char *output)
{
	short lstop = stop+((_SincLength-1)/2);
	//short taps = length-1;

    	char coeff, cpointer=0;
    	int accum;
	short circ_buff[_SincLength];

	// initialize circular buffer
	//for(ii = 0; ii < NCOEFF; ii++)
	//circ_buff[ii] = 0;

	for (short sample=start; sample<lstop; sample++)
	{ 
		circ_buff[cpointer] = (short)input[sample];// - ADC_ZERO;// * gain;		// get next input value,and store it at the beginning of the delay line
												// conversion to signed is done in lookup table, gain is included in coeffs
		if (++cpointer >= _SincLength)         						// incr circular pointer and check for wrap 
        	{ cpointer = 0; }

    		// calc FIR and rotate circular buffer pointer
		accum = 0;
    		for (coeff = 0; coeff < _SincLength; coeff++)
		{ 
			accum += _SincLookup[coeff][circ_buff[cpointer]];			// MAC operation by lookup table

			if (++cpointer >= _SincLength)         					// incr circular pointer and check for wrap 
			{ cpointer = 0; }
		}

		output[sample] = (unsigned char)(accum >> _SincIntWidth) + ADC_ZERO;		// rescale, convert to unsigned 	

	}

}
//##########################################################################################################################################################
/*! FIR Filter coefficients and lookup table*/
const short Signal::_FIR_COEFFS[3][FIR_LENGTH] = {
	{    0,   69,  317,  828, 1647, 2700, 3778, 4592, 4897,  4592, 3778, 2700, 1647,  828,  317 },	//0 fir 1
	{    0,   70,  322,  836, 1655, 2704, 3773, 4580, 4881,  4580, 3773, 2704, 1655,  836,  322 },	//1 fir 2
	{    0,  +66, +409,+1193,+2151,+2599,+2151,+1193, +409,   +66,    0,    0,    0,    0,    0 }	//2 fir 3
};

int Signal::_FirLookup[FIR_LENGTH][256];

/*! calculate lookup table for FIR mac operation*/
void Signal::FIR_buildNoiseFilterLookupTable(void)
{
	char filter; // filter selection

	switch(MenuStatus[MENU_ACQUIRE][2])
	{
		case 997: filter = 0; break;
		case 998: filter = 1; break;
		case 999: filter = 2; break;
		default: return;
	}

	for (short coeff=0;coeff<FIR_LENGTH;coeff++)	// calculate a lookup set for every coefficent
	    for (short i=0;i<256;i++)
		_FirLookup[coeff][i] = (int)((i-ADC_ZERO) * _FIR_COEFFS[filter][coeff]);	// product of signed value and coefficient

}
//##########################################################################################################################################################

const short Signal::_SINC_COEFFS[4][SINC_LENGTH] = {
	{  +0, +0, +0, +0, +0, +0, +0, +0, +0,  +0,  +0,    0,    0,    0,    0,    0,    0 },//0 sinc ->  2ns/div
	//{    0,  +37, +172, +448,  +921, +1636, +4893, +6739, +8415, +9591,+10014, +9591, +8415, +6739, +4893, +3185, +1825,  +889, +338,  +73,  0 },//1 sinc ->  5ns/div fc=0.02 (200MHz) Blackman
	{ +130, +232, +502, +983, +1669, +2496, +3352, +4101, +4613, +4795, +4613, +4101, +3352, +2496, +1669,  +983,  +502,  +232, +130 },//2 sinc -> 10ns/div fc=0.04 (200MHz) Hamming
	{ +130, +232, +502, +983, +1669, +2496, +3352, +4101, +4613, +4795, +4613, +4101, +3352, +2496, +1669,  +983,  +502,  +232, +130 },//2 sinc -> 10ns/div fc=0.04 (200MHz) Hamming
      //{    0,  +30, +167, +507, +1151, +2137, +3372, +4616, +5549, +5896, +5549, +4616, +3372, +2137, +1151,  +507,  +167,  +30,    0 },//2 sinc -> 10ns/div fc=0.04 (200MHz) Blackman
	{    0,  -24,  +43, +631, +2400, +5760,+10192,+14111,+15688,+14111,+10192, +5760, +2400,  +631,   +43,   -24,     0 }		//3 sinc -> 20ns/div fc=0.08 (200MHz) Blackman
}; 


int Signal::_SincLookup[SINC_LENGTH][256];

unsigned char Signal::_SincLength = SINC_LENGTH;				// filter length, number of coefficients, order + 1, depends on cutoff/samplerate
unsigned char Signal::_SincIntWidth = 15;					// integer size in bit


/*
* Windowed sinc FIR filter
*
*  Type                         : low pass 24th order
*  Filter length (order + 1)    : 25
*  Cutoff frequency (normed)    : 0.020000
*  Window                       : Blackman
*  Gain                         : 10.000000
*  Fixed point width            : 13
*  Integer factor (fixed point) : 8192
*
*
*  floating point               fixed point
*  ---------------------------------------------
*  h[0] = -0.000000             h[0] = 0
*  h[1] = 0.004628              h[1] = 37
*  h[2] = 0.021050              h[2] = 172
*  h[3] = 0.054788              h[3] = 448
*  h[4] = 0.112526              h[4] = 921
*  h[5] = 0.199788              h[5] = 1636
*  h[6] = 0.318141              h[6] = 2606
*  h[7] = 0.462907              h[7] = 3792
*  h[8] = 0.622292              h[8] = 5097
*  h[9] = 0.778489              h[9] = 6377
*  h[10] = 0.910699             h[10] = 7460
*  h[11] = 0.999380             h[11] = 8186
*  h[12] = 1.030621             h[12] = 8442
*  h[13] = 0.999380             h[13] = 8186
*  h[14] = 0.910699             h[14] = 7460
*  h[15] = 0.778489             h[15] = 6377
*  h[16] = 0.622292             h[16] = 5097
*  h[17] = 0.462907             h[17] = 3792
*  h[18] = 0.318141             h[18] = 2606
*  h[19] = 0.199788             h[19] = 1636
*  h[20] = 0.112526             h[20] = 921
*  h[21] = 0.054788             h[21] = 448
*  h[22] = 0.021050             h[22] = 172
*  h[23] = 0.004628             h[23] = 37
*  h[24] = -0.000000            h[24] = 0


*/


void Signal::FIR_buildSincLookupTable(void)
{
printf("\n\rBuilding sinc lookup table\n\r");

	// determine filter length depending on interpolated sample rate and cutoff frequency
	if (MainTimebase > 3) return;
	else if (MainTimebase == 3){ _SincLength = 17; _SincIntWidth = 15; }	// 20ns/div ->  2.5GSa/s
	else if (MainTimebase == 2){ _SincLength = 19; _SincIntWidth = 13; }	// 10ns/div ->  5GSa/s
	else if (MainTimebase == 1){ _SincLength = 25; _SincIntWidth = 13; }	//  5ns/div -> 10GSa/s
	else if (MainTimebase == 0){ _SincLength = 25; _SincIntWidth = 13; }	//  2ns/div -> 25GSa/s

printf("MainTimebase = %d\n\r",MainTimebase);
for (short i=0; i<_SincLength; i++)
   printf("Coeff[%d] 	= %d\n\r",i,_SINC_COEFFS[MainTimebase][i]);


	// calculate a lookup set for every coefficent
	for (short coeff=0;coeff<_SincLength;coeff++)
	    for (short i=0;i<256;i++)
	    {
		_SincLookup[coeff][i] = (int)((i-ADC_ZERO) * _SINC_COEFFS[MainTimebase][coeff]);	// product of signed value and coefficient for the MAC stage

		if (i==0) printf("Coeff[%d] : %d    Table[0] = %d\n\r", coeff, _SINC_COEFFS[MainTimebase][coeff], _SincLookup[coeff][i] );
		else if (i==1) printf("Coeff[%d] : %d    Table[1] = %d\n\r", coeff, _SINC_COEFFS[MainTimebase][coeff], _SincLookup[coeff][i] );
		else if (i==255) printf("Coeff[%d] : %d    Table[255] = %d\n\r", coeff, _SINC_COEFFS[MainTimebase][coeff], _SincLookup[coeff][i] );
	    }
}


