#ifndef _FRAME_RECIEVE_H
#define _FRAME_RECIEVE_H

#include "basetype.h"
#include "bufferloop.h"
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

typedef enum { 
ftFJu,   				    //按飞机平台上行协议校验
ftFJd,  					//按飞机平台下行协议校验
ftEOu,  					//按稳定平台上行协议校验
ftEOd,  					//按稳定平台下行协议校验
ftCJu,  					//按测距测角上行协议校验
ftCJd,  					//按测距测角下行协议校验
ftQBu,  					//按情报上行协议校验
ftQBd,  					//按情报下行协议校验
ftCKd,  					//按测控下行协议校验
ftSFu, ftSFd, ftFKu, ftFKd, ftEOGCSu, ftEOSBu, ftTXd, ftTXd_8B, ftTXd_8B_SM, ftTXd_8B_SAR,				//图像复接数据协议
ftEOU_8B,
ftMIMUu,			//MIMU上行协议数据协议
ftMIMUd,			//MIMU下行协议数据协议
ftGPSu, 			//GPS上行协议数据协议
ftGPSd, 			//GPS下行协议数据协议
ftBDu,  			//北斗上行协议数据协议
ftBDd,  			//北斗下行协议数据协议
ftPOWERu,           //飞控计算机发送到电源管理器的数据帧
ftPOWERd,           //电源管理器发送到飞控计算机的数据帧
ftOILu, 			//飞控计算机发送到油量传感器的数据帧
ftOILd, 			//油量传感器发送到飞控计算机的数据帧
ftMAGu, 			//飞控计算机发送到电子罗盘的数据帧
ftMAGd, 			//电子罗盘发送到飞控计算机的数据帧
ftGKu,  			//飞控计算机发送到高度/空速传感器的数据帧
ftGKd,  			//高度/空速传感器发送到飞控计算机的数据帧
ftNone  		    //自定义校验
}TFrameType;

inline double RoundMax(double v, double vmax)
{
return fmod(v, vmax);
}

inline void ChangeFileNameExt(char *name, const char *ext)
{
	char *p = strrchr(name, '.');
	if(p)	*(p+1) = 0;
	strcat(name, ext);
}

//解析事件回调函数类型
class CFrameAbstract;
typedef void (CALLBACK *FLDropBYTECALLBACK)(CFrameAbstract* frm, UINT16 Count);
typedef void (CALLBACK *FLDropFrameCALLBACK)(CFrameAbstract* frm, UINT16 Count);
typedef void (CALLBACK *FLNotCheckCALLBACK)(CFrameAbstract* frm);
typedef void (CALLBACK *FLCheckCALLBACK)(CFrameAbstract* frm,LPVOID lp);
//数据帧编帧、解析抽象类
class CFrameAbstract : public CBufferLoop {
public:
	CFrameAbstract() :
		FrameLength(32), HeadLength(2), CheckLength(1), CheckPos(31), FrameType(ftNone),
		bphrasing(FALSE), bFileOpen(FALSE), nFlushCount(0),
		hFileOrg(NULL), hFileCheck(NULL), hFileNotCheck(NULL),
		funcDropBYTE(NULL), funcDropFrame(NULL), funcNotCheck(NULL), funcCheck(NULL),
		CountBYTEAll(0), CountBYTEDrop(0), CountFrameAll(0), CountFrameCheck(0), CountFrameNotCheck(0), CountFrameDrop(0),
		funcDropBYTEParam(NULL), funcDropFrameParam(NULL), funcNotCheckParam(NULL), funcCheckParam(NULL)
		{};
	virtual ~CFrameAbstract(){
		funcDropBYTE = NULL;
		funcDropFrame = NULL;
		funcNotCheck = NULL;
		funcCheck = NULL;
		funcDropBYTEParam = NULL;
		funcDropFrameParam = NULL;
		funcNotCheckParam = NULL;
		funcCheckParam = NULL;
		while (TRUE == bphrasing){
			Sleep(100);
		}
		if(bFileOpen){
			fclose(hFileOrg);
			fclose(hFileCheck);
			fclose(hFileNotCheck);
			bFileOpen = FALSE;
		}
	}

protected:
	UINT16 FrameLength; 		   //帧长
	UINT16 HeadLength;  		   //帧头长度
	UINT16 CheckLength; 		   //帧内保存校验字节的长度
	UINT16 CheckPos;			   //帧内保存校验字节的位置
	TFrameType FrameType;          //帧格式类型
public:
	char Name[20];
	BYTE Head[13];
    BOOL bphrasing;	
	TFrameType GetFrameType(){return FrameType;}
	UINT16 GetFrameLength(){return FrameLength;}
	UINT16 GetHeadLength(){return HeadLength;}
private:	
	BOOL bFileOpen;
	INT32 nFlushCount;	
	char strModuleName[1024];
	char strAppPath[1024];
public:
	char strDataPath[1024];
protected:
	char strDataName[1024];
	FILE * hFileOrg;
	FILE * hFileCheck;
	FILE * hFileNotCheck;

	BOOL FullFrame()    //因为没有整个256做校验,排除长短帧,进行查找两个
	{
		int HeaderPos, HeaderPos2;
		HeaderPos = FindHead(0, Length() - HeadLength);    //
		if (0 == HeaderPos) {
			//帧头在最前面
			if (OnCheck())     //用256 257
				DoCheck();
			else {
				HeaderPos2 = FindHead(HeadLength, Length() - HeadLength);
				if (HeaderPos2 >= 0)
				{
                   Drop((UINT16) HeaderPos2);
				   TRACE("Diu >= 0\n");
				   return FALSE;
				}	
				else  
				{ TRACE("Diu < 0\n");

				   DoDropBYTE((UINT16) (Length()-(HeadLength-1))); 
				   return TRUE;
				} 
			}
		} 
		else if (HeaderPos < 0) 
		{
			//没找到帧头
			DoDropBYTE((UINT16) (Length()-(HeadLength-1)));   
		} 
		else 
		{
			//丢弃帧头前的数据
			DoDropBYTE((UINT16) HeaderPos);
			TRACE("Diu < 0\n");
		}
		return FALSE;
	}
	void DoCheck()
	{
		assert(FrameLength > 0);
		CountFrameAll++;
		CountFrameCheck++;
		OnDataCheck();
		Drop(FrameLength);
	}
	void DoNotCheck()
	{
		assert(FrameLength > 0);
		CountFrameAll++;
		CountBYTEDrop += FrameLength;
		CountFrameNotCheck++;
		OnDataNotCheck();
		Drop(FrameLength);
	}
	void DoDropFrame(const int Count)
	{
		assert(Count > 0);
		CountFrameAll++;
		CountBYTEDrop += Count;
		CountFrameDrop++;
		OnDataDropFrame(Count);
		Drop(Count);
	}
	void DoDropBYTE(const int Count)
	{
		
		if(Count <= 0) return;
		
		assert(Count > 0);

		CountBYTEDrop += Count;
		OnDataDropBYTE(Count);
		Drop(Count);
	}
	int FindHead(int Start, const int Length)
	{
		if((Start < 0) || (Length <=0 )) return -1;
		assert((Start >= 0) && (Length > 0));
		BYTE* p = Addr() + Start;
		while (Start < (Length-HeadLength+1)) 
		{
			if (memcmp(p, Head, HeadLength) == 0)
				return Start;
			p++;
			Start++;
		}
		return -1;
	}
	virtual BOOL OnCheck() 											 //帧校验函数
	{

		return 1;
		BYTE* p = Addr();
		struCHECK ck=CheckCRC(p+2);
		if (1 == CheckLength)
		{
			return (ck.C0== p[CheckPos]) ? TRUE : FALSE;
		}
		else if (2 == CheckLength)
		{
			return ((p[CheckPos]==ck.C1)&&(p[CheckPos+1]==ck.C0));
		}
		else
		{
			return false;
		}
	}

protected:
	FLDropBYTECALLBACK funcDropBYTE;
	FLDropFrameCALLBACK funcDropFrame;
	FLNotCheckCALLBACK funcNotCheck;
	FLCheckCALLBACK funcCheck;

	INT32 CountBYTEAll; 												  //接收到的全部字节数
	INT32 CountBYTEDrop;												  //丢弃的字节数
	INT32 CountFrameAll;												  //全部帧计数
	INT32 CountFrameCheck;  											  //有效帧计数
	INT32 CountFrameNotCheck;   										  //校验错的帧计数
	INT32 CountFrameDrop;   											  //短帧计数
	virtual void OnDataDropBYTE(const int Count)	 //无效字节段事件函数,需用户自行编制处理函数
	{
		if (funcDropBYTE != NULL)	funcDropBYTE(this, Count);
	}
	virtual void OnDataDropFrame(const int Count)    //短帧事件函数,需用户自行编制处理函数
	{
		if (funcDropFrame != NULL)	funcDropFrame(this, Count);
	}
	virtual void OnDataNotCheck()  					 //帧校验错事件函数,需用户自行编制处理函数
	{
		//Decode();
		if (funcNotCheck != NULL)	funcNotCheck(this);
		//Distribute();
		//Show();
		if(bFileOpen)	fwrite(Addr(), FrameLength, 1, hFileNotCheck);
	}
	virtual void OnDataCheck()					 //有效帧事件函数,需用户自行编制处理函数
	{
		Decode();
		if (funcCheck != NULL)	funcCheck(this,funcCheckParam);
		Distribute();
		Show();
		if(bFileOpen)	fwrite(Addr(), FrameLength, 1, hFileCheck);
	}

public:
	UINT32 funcDropBYTEParam;
	UINT32 funcDropFrameParam;
	UINT32 funcNotCheckParam;
	LPVOID funcCheckParam;
	void SetDropBYTECallback(FLDropBYTECALLBACK fun, UINT32 Param = 0){		funcDropBYTE = fun;		funcDropBYTEParam = Param;}
	void SetDropFrameCallback(FLDropFrameCALLBACK fun, UINT32 Param = 0){	funcDropFrame = fun;	funcDropFrameParam = Param;}
	void SetNotCheckCallback(FLNotCheckCALLBACK fun, UINT32 Param = 0){		funcNotCheck = fun;		funcNotCheckParam = Param;}
	void SetCheckCallback(FLCheckCALLBACK fun,LPVOID Param = NULL){funcCheck = fun;					funcCheckParam = Param;}
	void SetSaveStatus(BOOL IsSave, const char *name = NULL)
	{
		if(IsSave){
			GetModuleFileName(GetModuleHandle(NULL), strModuleName, 1024);
			char *p = strrchr(strModuleName, '\\');
			if(p)		strncpy(strAppPath, strModuleName, p - strModuleName);
			else		strcpy(strAppPath, strModuleName);
			
			time_t ltime;
			struct tm *t;
			time( &ltime );
			t = localtime( &ltime );

			sprintf(strDataPath, "%s\\RecordOrg-%04d%02d%02d", strAppPath, t->tm_year, t->tm_mon, t->tm_mday);
			char temp[1024];
			sprintf(temp, "%04d%02d%02d %02d%02d%02d", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
			CreateDirectory((LPCSTR)strDataPath, NULL);
			
			if(name == NULL){
				sprintf(strDataName, "%s\\%s-%s.dat", strDataPath, temp, Name);
			}
			else{
				sprintf(strDataName, "%s\\%s-%s.dat", strDataPath, temp, name);
			}
			
			if((hFileOrg = fopen(strDataName, "wb")) != NULL){
				strcpy(temp, strDataName);
				ChangeFileNameExt(temp,"chk");
				if((hFileCheck = fopen(temp, "wb")) != NULL){
					strcpy(temp, strDataName);
					ChangeFileNameExt(temp,"err");
					if((hFileNotCheck = fopen(temp, "wb")) != NULL){
						bFileOpen = TRUE;
					}
					else{
						fclose(hFileCheck);
						fclose(hFileOrg);
					}
					bFileOpen = TRUE;
				}
				else{
					fclose(hFileOrg);
				}
			}
		}
		else{
			if(bFileOpen){
				fclose(hFileOrg);
				fclose(hFileCheck);
				fclose(hFileNotCheck);
				bFileOpen = FALSE;
			}
		}
	}

	void ResetCount()
	{
		//用于计数清零
		CountBYTEAll = 0L;
		CountBYTEDrop = 0L;
		CountFrameAll = 0L;
		CountFrameCheck = 0L;
		CountFrameNotCheck = 0L;
		CountFrameDrop = 0L;
	}
	void Phrase(const BYTE* Src, const UINT32 Count)
	{
		cs->Enter();
		int ReadCount;
		UINT32 LeftCount = Count;
		const BYTE* psrc = Src;
		bphrasing = TRUE;
		while (LeftCount > 0) 
		{
			ReadCount = Append(psrc, LeftCount);//
			psrc += ReadCount;
			LeftCount -= ReadCount;
			CountBYTEAll += ReadCount;
			while (Length() >= (FrameLength+HeadLength))     //
				if (FullFrame())
					break;
		}
		try{
			if(bFileOpen)
			{
				fwrite(Src, Count, 1, hFileOrg);
				if((CountBYTEAll - nFlushCount) > 40960)
				{
					fflush(hFileOrg);
					fflush(hFileCheck);
					fflush(hFileNotCheck);
					nFlushCount = CountBYTEAll;
				}
			}
		}
		catch (...) 
		{
			cs->Leave();
			bphrasing = FALSE;
		}
		cs->Leave();
		bphrasing = FALSE;
	}
	INT32 GetCountBYTEAll(){return CountBYTEAll;}
	INT32 GetCountBYTEDrop(){return CountBYTEDrop;}
	INT32 GetCountFrameAll(){return CountFrameAll;}
	INT32 GetCountFrameCheck(){return CountFrameCheck;}
	INT32 GetCountFrameNotCheck(){return CountFrameNotCheck;}
	INT32 GetCountFrameDrop(){return CountFrameDrop;}
	//output
protected:
	virtual void FrameCrc(BYTE* p)
	{
		struCHECK ck=CheckCRC(p);
		if (CheckLength==1)
		{
          p[CheckPos]=ck.C0;
		}
		if (CheckLength==2)
		{
           p[CheckPos] = ck.C0;
		   p[CheckPos+1]=ck.C1;
		}
	}
public:
	virtual BYTE* SendPrepare()
	{
		BYTE* po;
		po = Addr();
		Encode();
		FrameCrc(po);
		return(po);
	}
	virtual struCHECK CheckCRC(BYTE* const p) = 0;
protected:
	virtual void Encode(){}
	virtual void Decode(){}
	virtual void Distribute(){}
public:
	virtual void Show(){}
};

#endif // !defined(AFX_FRAMERECIEVE_H__79D92644_4FC6_49FB_A28B_59EF7305C25A__INCLUDED_)