// threadMag.cpp : implementation file
//

#include "stdafx.h"
#include "CheckTr.h"
#include "threadMag.h"
//#include "libspectr.h"

#include <wtypes.h>
#include <initguid.h>
#include <time.h>
#include <math.h>


#define MAX_LOADSTRING 256

extern "C" {
#include "hidsdi.h"
#include <setupapi.h>
}

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//function prototypes
extern "C" __declspec(dllimport) int getStatus(unsigned char* statusFlags,unsigned short* framesInMemory);
extern "C" __declspec(dllimport) int setFrameFormat(unsigned short numOfStartElement, unsigned short numOfEndElement, unsigned char reductionMode, unsigned short *numOfPixelsInFrame);
extern "C" __declspec(dllimport) int getFrameFormat(unsigned short *numOfStartElement, unsigned short *numOfEndElement, unsigned char *reductionMode, unsigned short *numOfPixelsInFrame);
extern "C" __declspec(dllimport) int setAcquisitionParameters(unsigned short numOfScans, unsigned short numOfBlankScans, unsigned char scanMode, unsigned long exposureTime);
extern "C" __declspec(dllimport) int getAcquisitionParameters(unsigned short* numOfScans, unsigned short* numOfBlankScans, unsigned char* scanMode, unsigned long* timeOfExposure);
extern "C" __declspec(dllimport) int getFrame(unsigned short* framePixelsBuffer, unsigned short numOfFrame);
extern "C" __declspec(dllimport) int eraseFlash();
extern "C" __declspec(dllimport) int readFlash(unsigned char *buffer, unsigned long offset, unsigned long bytesToRead);
extern "C" __declspec(dllimport) int writeFlash(unsigned char *buffer, unsigned long offset, unsigned long bytesToWrite);
extern "C" __declspec(dllimport) int getDeviceCount();
extern "C" __declspec(dllimport) int resetDevice();
extern "C" __declspec(dllimport) int triggerAcquisition();
extern "C" __declspec(dllimport) int clearMemory();
extern "C" __declspec(dllimport) int setExternalTrigger(unsigned char TrigEnableMode, unsigned char TrigSignalFrontMode);
extern "C" __declspec(dllimport) int setOpticalTrigger(unsigned char enableMode, unsigned long pixel, unsigned long threshold);

extern void WINAPI HIDIOCompletionRoutine(DWORD, DWORD, LPOVERLAPPED);
int const WM_USRMSGTO=WM_USER+90;
int const WM_USRMSGFROM=WM_USER+91;


#define USBD_VID                     0xE220
#define USBD_PID                     0x0100
#define MAXMODULE 50




//Application global variables 

	HIDP_CAPS		Capabilities;
	PSP_DEVICE_INTERFACE_DETAIL_DATA	detailData;
	HANDLE			DeviceHandle;
	HANDLE			hEventObject;
	HANDLE			hDevInfo;
	GUID			HidGuid;
	OVERLAPPED		HIDOverlapped;
	const unsigned short int	MAXREPORTSIZE= 256;
/////////////////////////////////////////////////////////////////////////////
// CthreadMag
IMPLEMENT_DYNAMIC(CthreadMag, CWinThread)

//const UINT WM_MYMES=RegisterWindowMessage( FINDMSGSTRING );

CthreadMag::CthreadMag(CWnd* pWnd,
					   int				*mesage_to,
					   unsigned char	*DataIn,
					   unsigned char	*DataOut,
					   int				*NScans,
					   double			*Spectra,
					   double			*Spectra1,
					   bool				*SpecToGet,
					   bool				*DevDetT,
					   unsigned __int16	*startPixT,
					   unsigned __int16	*endPixT,
					   bool				*FastT,
					   bool				*test1T,
					   unsigned __int16	*tot_startPixT,
					   unsigned __int16	*tot_endPixT,
					   bool				*SclDir,
					   double			*NormSpec,
					   bool				*applyNorm,
					   double			*RefSpec,
					   int				*HowToApplyRef,
					   double			*Bck,
					   bool				*applBck,
					   int				*ExpN,
					   double			*bck_a,
					   double			*bck_b,
					   unsigned char	*BoxCarN,
					   bool				*Average,
					   int				*conn_Dev,
					   int				*SpectrToSelect,
					   bool				*Log,
					   bool				*AllClbrToFLASH,
					   double			*ColorNorm,
					   double			*Xscl_lmbd,
					   char				*InfoString,
					   double			*slopeIndex,
					   bool				*reset,
					   int				*Blank,
					   unsigned char	*TrigEnableMode,
					   unsigned char	*TrigSignalFrontMode,
					   unsigned char	*enableMode, 
					   unsigned __int16	*pixel, 
					   unsigned __int16	*threshold
					   )
{
	m_pMainWnd	=	pWnd;
	mesage_toT	=	mesage_to;
	InputReport	=	DataIn;
	OutputReport=	DataOut;
	NScansT		=	NScans;
	SpectraT	=	Spectra;
	Spectra1T	=	Spectra1;
	SpecToGetT	=	SpecToGet;
	DevDet		=	DevDetT;//need to detect device?
	startPix	=	startPixT;
	endPix		=	endPixT;
	Fast		=	FastT;
	test1		=	test1T;
	tot_startPix=	tot_startPixT;
	tot_endPix	=	tot_endPixT;
	SclDirT		=	SclDir;//true rising X scale, false - falling X scale;
	NormSpecT	=	NormSpec;
	applyNormT	=	applyNorm;
	RefSpecT	=	RefSpec;
	HowToApplyRefT	=	HowToApplyRef;	
	BckT		=	Bck;
	applBckT	=	applBck;
	ExpNT		=	ExpN;
	bck_aT		=	bck_a;
	bck_bT		=	bck_b;
	BoxCarNT	=	BoxCarN;	
	AverageT	=	Average;
	conn_DevT	=	conn_Dev;
	SpectrToSelectT	=	SpectrToSelect;
	LogT		=	Log;
	AllClbrToFLASHT = AllClbrToFLASH;
	ColorNormT	=	ColorNorm;
	Xscl_lmbdT	=	Xscl_lmbd;
	InfoStringT =	InfoString;
	slopeIndexT =	slopeIndex;
	resetT		=	reset;
	BlankT		=	Blank;
	TrigEnableModeT			=	TrigEnableMode;
	TrigSignalFrontModeT	=	TrigSignalFrontMode;
	enableModeT	=	enableMode;
	pixelT		=	pixel;
	thresholdT	=	threshold;

	if(*AverageT==false)	AverageOld=true;
	else					AverageOld=false;
	RLn=32;
	TransNmb=115;
	ShiftAddress=384;
	length=48;

	bckInd=0;
	ExpOld=-1;
	TrigEnableModeOld=255;
	TrigSignalFrontModeOld=255;
	enableModeOld=255;
	pixelOld=32000;
	thresholdOld=64000;

	send_message=false;
	scanMode=3;
}

CthreadMag::~CthreadMag()
{
	CloseHandle(DeviceHandle);
	CloseHandle(ReadHandle);
}

BOOL CthreadMag::InitInstance()
{
	// TODO:  perform and per-thread initialization here
	return TRUE;
}

int CthreadMag::ExitInstance()
{
	// TODO:  perform any per-thread cleanup here
	return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CthreadMag, CWinThread)
	//{{AFX_MSG_MAP(CthreadMag)
	
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
	ON_THREAD_MESSAGE(WM_USRMSGTO, Mes_Anal)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CthreadMag message handlers

//LRESULT CthreadMag::Mes_Anal(WPARAM,LPARAM)
void CthreadMag::Mes_Anal(WPARAM,LPARAM)
{
	int Flag1;
	int j,i, k1;
	if(*mesage_toT==20)//read flash
	{
		unsigned char buffer[130000];
		unsigned long offset=0;
		unsigned long bytesToRead=31;
		unsigned char *statusFlags;
		statusFlags=(unsigned char*)malloc(sizeof(unsigned char));
		unsigned short *framesInMemory;
		framesInMemory=(unsigned short*)malloc(sizeof(unsigned short));
		Flag1=getStatus(statusFlags,framesInMemory);
		bytesToRead=6000;
		for(i=0;i<20;i++)
		{
			Flag1=readFlash(buffer+offset, offset, bytesToRead);
			offset+=6000;
		}
		for(i=0;i<=15;i++) InfoStringT[i]=buffer[i];

		if(InfoStringT[5]=='.')
		{
			CString Out;
			int countLines=0;
			i=0;
			while(countLines<1)
			{
				if(buffer[i]==10) countLines++;
				i++;
			}
			Out.Empty();
			while(buffer[i]!=10)
			{
				Out.Insert(Out.GetLength()+1,buffer[i]);
				i++;
			}
			*bck_aT=atof(Out);//color norm factor
			Out.Empty();
			i++;
			while(buffer[i]!=10)
			{
				Out.Insert(Out.GetLength()+1,buffer[i]);
				i++;
			}
			*slopeIndexT=atof(Out);//color norm factor
			Out.Empty();

			countLines=0;
			i=0;
			while(countLines<12)
			{
				if(buffer[i]==10) countLines++;
				i++;
			}
			countLines=0;
			Out.Empty();
			while(countLines<3653)
			{
				Out.Insert(Out.GetLength()+1,buffer[i]);
				i++;
				if(buffer[i]==10)
				{
					Xscl_lmbdT[countLines]=atof(Out);
					countLines++;
					Out.Empty();
				}
			}
			countLines=0;
			Out.Empty();
			while(countLines<2)
			{
				if(buffer[i]==10) countLines++;
				i++;
			}
			countLines=0;
			while(countLines<3653)
			{
				Out.Insert(Out.GetLength()+1,buffer[i]);
				i++;
				if(buffer[i]==10)
				{
					NormSpecT[countLines]=atof(Out);
					countLines++;
					Out.Empty();
				}
			}
			i=i+4;
			countLines=0;
			Out.Empty();
			while(countLines<3653)
			{
				Out.Insert(Out.GetLength()+1,buffer[i]);
				i++;
				if(buffer[i]==10)
				{
					ColorNormT[countLines]=atof(Out);
					countLines++;
					Out.Empty();
				}
			}
		}
		else//no info string
		{
			for(i=0;i<3653;i++)
			{
				Xscl_lmbdT[i]=i;
				NormSpecT[i]=1;
				ColorNormT[i]=1;
			}
			*slopeIndexT=0;
		}
		for (i=0;i<=3685;i++)
		slopeRemoval[i]=1-1/((0.0022*(double(i)+100))*(0.0022*(double(i)+100))+1);

		m_pMainWnd->PostMessage(WM_USRMSGFROM,NULL,NULL);
	}
	else
		if(*mesage_toT==10)//writre all calibration information to FLASH
		{
			unsigned char buffer[130000];
			unsigned long count_buff=0;
			CString Out;
			for(i=0;i<=15;i++)
			{
				buffer[count_buff]=InfoStringT[i];
				count_buff++;
			}
			buffer[count_buff]='\r';
			count_buff++;
			buffer[count_buff]='\n';
			count_buff++;
			
			tmp1=0;
			Out.Format("%e\t",*bck_aT);
			tmp1=Out.GetLength();
			for(i=0;i<tmp1;i++)
			{
				buffer[count_buff]=Out.GetAt(i);
				count_buff++;
			}
			Out.Empty();
			for(i=0;i<=10;i++)
			{
				buffer[count_buff]='\r';
				count_buff++;
				buffer[count_buff]='\n';
				count_buff++;
			}

	////!!!!!!!!!!! Warning NormS and ColorNorm are saved and loaded not inverced if coeff_B<0;
			for(i=0;i<3653;i++)
			{
				tmp1=0;
				if(*SclDirT==true)
					Out.Format("%.3f\t",Xscl_lmbdT[i]);
				else
					Out.Format("%.3f\t",Xscl_lmbdT[3652-i]);
				tmp1=Out.GetLength();
				for(j=0;j<tmp1;j++)
				{
					buffer[count_buff]=Out.GetAt(j);
					count_buff++;
				}
				Out.Empty();

				buffer[count_buff]='\r';
				count_buff++;
				buffer[count_buff]='\n';
				count_buff++;
			}
			buffer[count_buff]='\r';
			count_buff++;
			buffer[count_buff]='\n';
			count_buff++;

			for(i=1;i<=3653;i++)
			{
				tmp1=0;
				if(*SclDirT==true)
					Out.Format("%.3f\t",NormSpecT[i]);
				else
					Out.Format("%.3f\t",NormSpecT[3653-i]);
				tmp1=Out.GetLength();
				for(j=0;j<tmp1;j++)
				{
					buffer[count_buff]=Out.GetAt(j);
					count_buff++;
				}
				Out.Empty();

				buffer[count_buff]='\r';
				count_buff++;
				buffer[count_buff]='\n';
				count_buff++;
			}
			buffer[count_buff]='0';
			count_buff++;
			buffer[count_buff]='\r';
			count_buff++;
			buffer[count_buff]='\n';
			count_buff++;

			for(i=1;i<=3653;i++)
			{
				tmp1=0;
				if(*SclDirT==true)
					Out.Format("%.3f\t",ColorNormT[i]);
				else
					Out.Format("%.3f\t",ColorNormT[3653-i]);
				tmp1=Out.GetLength();
				for(j=0;j<tmp1;j++)
				{
					buffer[count_buff]=Out.GetAt(j);
					count_buff++;
				}
				Out.Empty();

				buffer[count_buff]='\r';
				count_buff++;
				buffer[count_buff]='\n';
				count_buff++;
			}
			buffer[count_buff]='0';
			count_buff++;
			buffer[count_buff]='\r';
			count_buff++;
			buffer[count_buff]='\n';
			count_buff++;

			eraseFlash();
			writeFlash(buffer, 0, count_buff);
			*AllClbrToFLASHT=false;

			m_pMainWnd->PostMessage(WM_USRMSGFROM,NULL,NULL);
		}
		else
			if(*mesage_toT==1)//get spectra
			{
				if(*SclDirT==true)//rising X scale
				{
					startPix1=*startPix;
					endPix1=*endPix;
				}
				else//falling X scale
				{
					startPix1=*tot_endPix-*tot_startPix-*endPix;
					endPix1=*tot_endPix-*tot_startPix-*startPix;
				}
				startPix1+=*tot_startPix;
				endPix1+=*tot_startPix;

				if((ExpOld!=*ExpNT)||(NScansOld!=*NScansT)||(*resetT==true)||(AverageOld!=*AverageT)||(TrigEnableModeOld!=*TrigEnableModeT)||(TrigSignalFrontModeOld!=*TrigSignalFrontModeT)||(enableModeOld!=*enableModeT)||(pixelOld!=*pixelT)||(thresholdOld!=*thresholdT))
				{
					Flag1=clearMemory();
					*resetT=false;
					if(*ExpNT==0) *ExpNT=1;
					NScansOld=*NScansT;
					ExpOld=*ExpNT;
					AverageOld=*AverageT;
					TrigEnableModeOld=*TrigEnableModeT;
					TrigSignalFrontModeOld=*TrigSignalFrontModeT;
					enableModeOld=*enableModeT;
					pixelOld=*pixelT;
					thresholdOld=*thresholdT;

					unsigned short numOfBlankScans=(unsigned short)(*BlankT);
					if((AverageOld==true)&(TrigEnableModeOld==0)&(enableModeOld==0))	scanMode=3; //frame averaging mode
					else					scanMode=0;	//continuous scanMode
					unsigned short numOfStartElement=0;
					unsigned short numOfEndElement=3647;
					unsigned char reductionMode=0;
					unsigned short *numOfPixelsInFrame;
					unsigned long ExposureTo=(unsigned long)(*ExpNT);
					numOfPixelsInFrame=(unsigned short*)malloc(sizeof(unsigned short));
					Flag1=setExternalTrigger(TrigEnableModeOld,TrigSignalFrontModeOld);//unsigned char enableMode, unsigned char signalFrontMode);
					Flag1=setOpticalTrigger(enableModeOld, pixelOld, thresholdOld);
					Flag1=setFrameFormat(numOfStartElement, numOfEndElement, reductionMode, numOfPixelsInFrame);
					Flag1=setAcquisitionParameters((unsigned short)NScansOld, numOfBlankScans, scanMode, (unsigned long)(*ExpNT));
				}
				if((scanMode==0)&(TrigEnableModeOld==0)&(enableModeOld==0))	Flag1=triggerAcquisition();
				unsigned char *statusFlags;
				statusFlags=(unsigned char*)malloc(sizeof(unsigned char));
				unsigned short *framesInMemory;
				framesInMemory=(unsigned short*)malloc(sizeof(unsigned short));
				Flag1=getStatus(statusFlags,framesInMemory);
//				if(Flag1==506)
//				{
//					Flag1=resetDevice();
//					*resetT=true;
//				}
				Flag1=0;
				//statusFlags=0 end of operation
				while( (((*framesInMemory==0)&(scanMode==3)) || ((*statusFlags!=0)&(scanMode!=3))) & (*resetT==false) )//1- one spectra in memory; spectra is ready and at least one spectra is lost because it's not been read
				{
					Sleep(25);
					getStatus(statusFlags,framesInMemory);
					Flag1++;
				}
				*resetT=false;
				unsigned short numOfFrame;
				if(scanMode==3)
				{
					numOfFrame=0xFFFF;
					Flag1=getFrame(InputSpec_loc, numOfFrame);
					for(k1=0;k1<=3693;k1++)
					{
						if(*SpecToGetT==1)	SpectraT[k1]=InputSpec_loc[k1];
						else				Spectra1T[k1]=InputSpec_loc[k1];;
					}
					if(*SpecToGetT==1)	ShapeData(SpectraT);
					else				ShapeData(Spectra1T);
				}
				if(scanMode==0)	
				{
					for(i=0;i<NScansOld;i++)
					{
						Flag1=getFrame(InputSpec_loc, i);
						for(k1=0;k1<=3693;k1++)
						{
							if(*SpecToGetT==1)	SpectraT[k1+i*4096]=InputSpec_loc[k1];
							else				Spectra1T[k1+i*4096]=InputSpec_loc[k1];
						}
						if(*SpecToGetT==1)	ShapeData(SpectraT+i*4096);
						else				ShapeData(Spectra1T+i*4096);
					}
					Flag1=clearMemory();
				}
				
			
	//transmission to *InputSpec1
				
	//end of transmission to *InputSpec1

				if(*SpecToGetT==0)	*SpecToGetT=1;
				else				*SpecToGetT=0;
				*mesage_toT=cnt1;

				m_pMainWnd->PostMessage(WM_USRMSGFROM,NULL,NULL);
			}
			else
				if(*mesage_toT==5)//number connected devices
				{
					*conn_DevT=getDeviceCount();
					if(*conn_DevT!=0)// there are connected devices
					{
					}
					m_pMainWnd->PostMessage(WM_USRMSGFROM,NULL,NULL);
				}
}

void CthreadMag::ShapeData(double *ShapeData)
{
	int k1,i;
	devd=0;
	for(k1=15;k1<=31;k1++) devd+=ShapeData[k1];
	devd/=17;
	devd2=0;
	for(k1=3686;k1<=3692;k1++) devd2+=ShapeData[k1];
	devd2/=7;
	double SlopeAmpl=devd2-devd;
	double DataTmp[4096];
	if(*applyNormT==false) 
	{
		SlopeAmpl=0;
		devd=0;
	}
	for(k1=0;k1<=115;k1++)
	{
		for (ByteNumber=0; ByteNumber <= 31; ByteNumber++)
		{
			cnt1=k1*RLn+ByteNumber;
			if((cnt1>=startPix1)&(cnt1<=endPix1))
			{
				if(*SclDirT==true)//rising X scale
					ShapeData[cnt1-startPix1]=ShapeData[cnt1]-slopeRemoval[cnt1]*SlopeAmpl-devd;//+450;
				else//falling X scale
					DataTmp[cnt1-startPix1]=ShapeData[startPix1+endPix1-cnt1]-slopeRemoval[startPix1+endPix1-cnt1]*SlopeAmpl-devd;
			}
		}
	}
	if(*SclDirT==false)
		for(k1=0;k1<=(*endPix)-(*startPix);k1++)	ShapeData[k1]=DataTmp[k1];	

	for(i=0;i<=(*endPix)-(*startPix);i++)
	{
		if(*applyNormT==true)					//correction
		{
			ShapeData[i]/=NormSpecT[i+(*startPix)];	//correction is taken from all scans
			if(ShapeData[i]>64000) ShapeData[i]=64000;
		}
		if(*applBckT==true)	ShapeData[i]-=BckT[i+(*startPix)];	//backround (should be taken in full mode)
		if(*HowToApplyRefT==1)
		{
			ShapeData[i]=RefSpecT[i+(*startPix)]-ShapeData[i];	//minus ref spectra (should be taken in full mode)
		}
		if(*HowToApplyRefT==2)										//mult. on ref spectra (should be taken in full mode)
			if(RefSpecT[i+(*startPix)]!=0)	ShapeData[i]/=RefSpecT[i+(*startPix)];
			else							ShapeData[i]=-1;
			if(*HowToApplyRefT==3)
			if((RefSpecT[i+(*startPix)]>0) && (ShapeData[i]>0))	ShapeData[i]=-log10(ShapeData[i]/RefSpecT[i+(*startPix)])*0.43429;
			else	ShapeData[i]=0;
	}
	if(*BoxCarNT>=1) BoxCarF(0,(*endPix)-(*startPix), ShapeData, *BoxCarNT);
	if(*LogT==true)
	{
		for(i=0;i<=(*endPix)-(*startPix);i++)
		{
			if(ShapeData[i]>0) ShapeData[i]=log(ShapeData[i]);
			else	ShapeData[i]=0;
		}
	}
}

void CthreadMag::BoxCarF(int start_pix, int end_pix, double *DataArray, unsigned char param1)
{
	//param1	-	BoxCar parameter (pixels number)
	//lng		-	length of array
	//DataArray	-	DataArray

	double DataTmp[10000];
	double tmp=0;
	int lng,j3,i,lngAv;;
	lng=end_pix-start_pix+1;
	lngAv=0;
	for(i=0;i<=param1;i++)
	{
		for(j3=0;j3<=i+param1;j3++)
		{
			tmp+=DataArray[j3+start_pix];
			lngAv++;
		}
		tmp/=lngAv;
		lngAv=0;
		DataTmp[i+start_pix]=tmp;
		tmp=0;
	}
	for(i=param1;i<=lng-param1;i++)
	{
		for(j3=-param1;j3<=param1;j3++)
		{
			tmp+=DataArray[i+j3+start_pix];
			lngAv++;
		}
		tmp/=lngAv;
		lngAv=0;
		DataTmp[i+start_pix]=tmp;
		tmp=0;
	}
	for(i=lng-param1;i<=lng;i++)
	{
		for(j3=i-param1;j3<lng;j3++)
		{
			tmp+=DataArray[j3+start_pix];
			lngAv++;
		}
		tmp/=lngAv;
		lngAv=0;
		DataTmp[i+start_pix]=tmp;
		tmp=0;
	}
	for(i=0;i<=lng;i++) DataArray[i]=DataTmp[i];
}

