// ClientComm.cpp: implementation of the CClientComm class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ClientComm.h"
#include "Modbus.h"
#include "MbCommon.h"
#include <winbase.h>

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CWinThread* m_IOThread;
UINT ProcessIOEvent( LPVOID pParam );

CClientComm::CClientComm():CnComm()
{
	rcvbufferlen = 0;
	comsetinfo[0] = 38400;
	comsetinfo[1] = 4;
	comsetinfo[2] = 0;
	comsetinfo[3] = 0;

	m_IOThread=::AfxBeginThread(ProcessIOEvent,this);
	SetNotifyThreadId(m_IOThread->m_nThreadID);

	prevSendtime = GetTickCount();
	CloseThread = 0;
	usingflag = 0;
}

CClientComm::~CClientComm()
{
	CloseThread = 1;
	Sleep(100);
	m_IOThread = NULL;
	CloseCom();
}

s16 CClientComm::comsend(u8 *src, s16 srclen)
{
	if(srclen<=0)srclen = methord::strlen_1(src);
	if(IsOpen()==false)return -1;
	
	while(1)
	{
		if(prevSendtime>(GetTickCount()+20))break;
		if(prevSendtime<(GetTickCount()-20))break;
		Sleep(10);
	}
	if(IsOpen()==false)return -1;
	prevSendtime = GetTickCount();

	if (Comm_.IsDebug)
	{
		src[srclen] = 0;

		CString temp = methord::u8tostr(src, srclen);
		info += _T("\r\n发送:") + temp;
	}	
	
	if (IsOverlappedMode() || IsTxBufferMode())
		Write(src,srclen);
	else
	{
		//! 阻塞非缓冲区模式 必须检查返回值，确保数据完全发送出
		for (int i = 0; i<srclen; i++ )
			i += Write(src + i, srclen - i);
	}
	return srclen;
}

bool CClientComm::SetComState(s16 status)
{
	bool setok=false;
	if (!IsOpen())return setok;
	
	struct Parity{
		BYTE dwParity;
		TCHAR sParity[24];
	} Paritys[] = 
	{
		{NOPARITY    ,_T("NO")},
		{ODDPARITY   ,_T("ODD")},
		{EVENPARITY  ,_T("EVEN")},
		{MARKPARITY  ,_T("MARK")},
		{SPACEPARITY ,_T("SPACE")}
	};
	
	BYTE ByteSizes[] = {4, 5, 6, 7, 8};
	
	struct StopBit {
		BYTE dwStopBit;
		TCHAR sStopBit[24];
	} StopBits [] = 
	{
		{ONESTOPBIT   ,_T("ONESTOPBIT")},
		{ONE5STOPBITS ,_T("ONE5STOPBITS")},
		{TWOSTOPBITS  ,_T("TWOSTOPBITS")},
	};
	
	//波特率 数据位 校验方式 停止位	
	DCB* pDcb = GetState();	
	
	pDcb->BaudRate = comsetinfo[0];
	pDcb->ByteSize = ByteSizes[comsetinfo[1]%5];
	pDcb->StopBits = StopBits[comsetinfo[3]%3].dwStopBit;
	pDcb->Parity   = Paritys[comsetinfo[2]%5].dwParity;		
	
	
	switch(status)
	{
	case 0x00://关闭串口
		Close();
		setok = true;
		break;
	case 0x01://打开串口波特率1		
		setok =SetState(pDcb);
		break;
	}
	
	if(setok==false)
	{
		TCHAR szBuf[1024];
		wsprintf(szBuf, _T("SetState(%d, %d, %d, %d), Fail. Code:%d"), 
			pDcb->BaudRate, 
			Paritys[pDcb->Parity].dwParity, 
			ByteSizes[pDcb->ByteSize], 
			StopBits[pDcb->StopBits].dwStopBit,
			GetLastError());
		MessageBox(NULL,szBuf,_T("Error"),MB_OK);
	}	
	return setok;
}

s16 CClientComm::CloseCom(void)
{
	u16 time=2000;
	while((usingflag)&&(time--))Sleep(10);
	usingflag =1;
	Close();
	usingflag = 0;
	
	return 0;
}
s16 CClientComm::DealReceive(void)
{
	int  srcindex=0;
	long timetemp;

	if(IsOpen()==false) {return -1;}
	u16 time=10;
	while((usingflag)&&(time--))Sleep(10);
	usingflag = 1;
	if(IsOpen()==false) {usingflag=0;return -1;}
	
	//先记录下来，避免某种原因，人为的原因，操作几次之间时间长，缓存不一致
	do {
		int len = Comm_.Read(rcvingbuf+rcvbufferlen, 2048);		
		if(len<=0) {usingflag=0;return -1;}
		//! 接收缓冲模式下，要确保把已经在Comm_.Input()缓冲区的数据处理完
		//! 否则如果没有新的数据再来，不会继续通知你
		rcvbufferlen+=len;
		if(rcvbufferlen>MAX_COM_RXBUFF)rcvbufferlen = MAX_COM_RXBUFF;

		if (Comm_.IsDebug)
		{
			rcvingbuf[rcvbufferlen] = 0;

			CString temp = methord::u8tostr(rcvingbuf, rcvbufferlen);
			info += _T("\r\n接收:") + temp;
		}
		

		int flag;
		while ((rcvbufferlen-srcindex) >=5)
		{			
				flag = DealCode(rcvingbuf+srcindex,rcvbufferlen-srcindex);
				
				timetemp = prevtime;
				prevtime = 0;
				if (flag == 0)
				{
					if(timetemp==0){prevtime = GetTickCount();break;}
					if(GetTickCount()-timetemp>100)
					{
						srcindex++;
					}
					else
						prevtime = timetemp;
				}
				else if (flag > 0)
				{
					srcindex+=flag;//正确分析一条数据，从缓存中移除数据。
				}
				else
				srcindex++;
		}
		for(int i=0;i<rcvbufferlen-srcindex;i++)
		{
			rcvingbuf[i] = rcvingbuf[srcindex+i];
		}
		rcvbufferlen = rcvbufferlen-srcindex;
	}while(IsRxBufferMode() && Input().SafeSize());

	 usingflag=0;
	 return 0;
}

s16 CClientComm::OpertorDO(s16 ioindex,bool onoff)
{
	u8 src[10];
	u8 dst[255];
	s16 dstlen =0;
	u16 Bit = 0x0001;

	CString temp;
	if(onoff)
	{
		src[0]=0x01;

		temp.Format(_T("\r\n操作DO  打开第%d个继电器 "),ioindex+1);
	}
	else
	{
		src[0] = 0x00;
		temp.Format(_T("\r\n操作DO  关闭第%d个继电器 "), ioindex + 1);
	}
	
	
	info += temp;
	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 0x05, ioindex, 1, src, 1, dst);
	
	DOWriteFLag[0]&=~Bit;
	
	u8 ErrorCnt = 0;
	while(ErrorCnt<3)
	{		
		comsend(dst,dstlen);
		Sleep(200);
		if(DOWriteFLag[0]&Bit)
		{
			DOWriteFLag[0]&=~Bit;
			return 1;			
		}
		ErrorCnt++;
	}
	return 0;
}

s16 CClientComm::OpertorDO(bool onoff)
{
	u8 src[10];
	u8 dst[512];
	s16 dstlen =0;
	u16 Bit = 0x0002;
	if(onoff)
	{
		src[0]=0xff;
		src[1]=0xff;

		info += _T("\r\n操作DO 全部打开");
	}
	else 
	{
		src[0]=0x00;
		src[1]=0x00;
		info += _T("\r\n操作DO 全部关闭");
	}	
	
	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 15, 0, DO_CNT, src, 2, dst);

	DOWriteFLag[0]&=~Bit;
	
	u8 ErrorCnt = 0;
	while(ErrorCnt<3)
	{		
		comsend(dst,dstlen);
		Sleep(200);
		if(DOWriteFLag[0]&Bit)
		{
			DOWriteFLag[0]&=~Bit;
			return 1;			
		}
		ErrorCnt++;
	}
	return 0;
}


s16 CClientComm::AskDI(void)
{
	u8 src[10];
	u8 dst[512];
	s16 dstlen =0;
	
	if(DI_CNT)
	{
		if (Comm_.IsDebug)info += _T("\r\n读取DI");
		dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 0x02, 0, DI_CNT, src, 1, dst);
		return comsend(dst,dstlen);
	}
	return -1;
}
s16 CClientComm::AskDO(void)
{
	u8 src[10];
	u8 dst[512];
	s16 dstlen =0;
	
	if(DO_CNT)
	{
		if (Comm_.IsDebug)info += _T("\r\n读取DO");
		dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 0x01, 0, DO_CNT, src, 1, dst);
		return comsend(dst,dstlen);
	}
	return -1;
}
s16 CClientComm::AskAI(void)
{
	u8 src[10];
	u8 dst[512];
	s16 dstlen = 0;

	if (AI_CNT)
	{
		if (Comm_.IsDebug)info += _T("\r\n读取AI");
		dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 0x04, 0, AI_CNT, src, 1, dst);
		return comsend(dst, dstlen);
	}
	return -1;
}


s16 CClientComm::OpertorWBaud(int baud232,int baud485)
{
	u16 src[10];
	u8 dst[512];
	s16 dstlen =0;
	u16 Bit = 0x0001;

	src[0] = baud232;
	src[1] = baud485;


	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 16, 1000, 2, src, 2, dst);

	HoldWriteFLag[0]&=~Bit;
	
	u8 ErrorCnt = 0;
	while(ErrorCnt<3)
	{		
		comsend(dst,dstlen);
		Sleep(1000);
		if(HoldWriteFLag[0]&Bit)
		{
			HoldWriteFLag[0]&=~Bit;
			return 1;			
		}
		ErrorCnt++;
	}
	return 0;
}

s16 CClientComm::OpertorRBaud()
{
	u16 src[10];
	u8 dst[512];
	s16 dstlen =0;
	u16 Bit = 0x0001;

	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 3, 1000, 2, src, 2, dst);

	HoldReadFLag[0]&=~Bit;
	
	u8 ErrorCnt = 0;
	while(ErrorCnt<3)
	{		
		comsend(dst,dstlen);
		Sleep(200);
		if(HoldReadFLag[0]&Bit)
		{
			HoldReadFLag[0]&=~Bit;
			return 1;			
		}
		ErrorCnt++;
	}
	return 0;
}


s16 CClientComm::OpertorWBaseAddr(int addr)
{
	u16 src[10];
	u8 dst[512];
	s16 dstlen = 0;
	u16 Bit = 0x0001;

	src[0] = addr;


	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 16, 1002, 1, src, 2, dst);

	HoldWriteFLag[0] &= ~Bit;

	u8 ErrorCnt = 0;
	while (ErrorCnt<3)
	{
		comsend(dst, dstlen);
		Sleep(1000);
		if (HoldWriteFLag[0] & Bit)
		{
			HoldWriteFLag[0] &= ~Bit;
			return 1;
		}
		ErrorCnt++;
	}
	return 0;
}
s16 CClientComm::OpertorRBaseAddr()
{
	u16 src[10];
	u8 dst[512];
	s16 dstlen = 0;
	u16 Bit = 0x0001;

	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, equipaddr, 3, 1002, 1, src, 0, dst);

	HoldReadFLag[0] &= ~Bit;

	u8 ErrorCnt = 0;
	while (ErrorCnt<3)
	{
		comsend(dst, dstlen);
		Sleep(200);
		if (HoldReadFLag[0] & Bit)
		{
			HoldReadFLag[0] &= ~Bit;
			return 1;
		}
		ErrorCnt++;
	}
	return 0;
}

s16 CClientComm::OpertorRAddr()
{
	u16 src[10];
	u8 dst[512];
	s16 dstlen = 0;
	u16 Bit = 0x0001;

	dstlen = CModbus::DealMasterSnd(PROTOCOL_RTU_MODE, 0xfe, 4, 1000, 1, src, 0, dst);

	InputReadFLag[0] &= ~Bit;

	u8 ErrorCnt = 0;
	while (ErrorCnt<3)
	{
		comsend(dst, dstlen);
		Sleep(200);
		if (InputReadFLag[0] & Bit)
		{
			InputReadFLag[0] &= ~Bit;
			return 1;
		}
		ErrorCnt++;
	}
	return 0;
}
s16 CClientComm::DealCode(u8 *src,s16 srclen)
{
	int srcindex;//本次读取的长度

	u8  dst[512];
	s16 dstlen;
	//解析出Modbus
	if( (srcindex=CMBAscii::eMBASCIIReceive(src,srclen,dst,&dstlen)) >0 ) // ASII 模式
    {}
    else if( (srcindex=CMBRtu::eMBRTUReceive(src,srclen,dst,&dstlen))>0 ) // RTU 模式
    {}
    else return ( -1 );
	//继续解析信息，并将解析完毕的信息存储于寄存器表中		
	if(dst[0]!=equipaddr)return -1;
	
	DealModbus(dst,dstlen);

	return srcindex;
}

s16 CClientComm::DealModbus(u8 *src,s16 srclen)
{
	s16 srcindex=0;	
	u8  Addr = src[srcindex++];
	u8  RegCode = src[srcindex++];
	u16 RegNum =0;
	int i;
	u8  temp;
	switch(RegCode)
	{
		case 1: //1：读线圈寄存器
			RegNum = src[srcindex++];	
			if(RegNum>0)
			{
				temp = src[srcindex++];
				for(i=0;i<8;i++)
				{
					DOStatus[i] = (temp&0x01)?0x01:0x00;
					temp>>=1;
				}
			}
			if(RegNum>1)
			{
				temp = src[srcindex++];
				for(i=0;i<8;i++)
				{
					DOStatus[8+i] = (temp&0x01)?0x01:0x00;
					temp>>=1;
				}
			}				
			for(i=0;i<10;i++)DOReadFLag[i]|= 0x0001;//继电器读取成功	//继电器读取成功	
			break;
		case 2: //2：光耦输入状态
			RegNum = src[srcindex++];	
			if(RegNum>0)
			{
				temp = src[srcindex++];
				for(i=0;i<8;i++)
				{
					DIStatus[i] = (temp&0x01)?0x01:0x00;
					temp>>=1;
				}
			}
			if(RegNum>1)
			{
				temp = src[srcindex++];
				for(i=0;i<8;i++)
				{
					DIStatus[8+i] = (temp&0x01)?0x01:0x00;
					temp>>=1;
				}
			}	
			if(RegNum>2)
			{
				temp = src[srcindex++];
				for(i=0;i<8;i++)
				{
					DIStatus[16+i] = (temp&0x01)?0x01:0x00;
					temp>>=1;
				}
			}
			for(i=0;i<10;i++)DIReadFLag[i]|= 0x0001;	
			break;
		case 5:  //5：写单个线圈寄存器
			for(i=0;i<10;i++)DOWriteFLag[i]|=0x0001;
			break;
		case 15:  //15：写多个线圈寄存器
			for(i=0;i<10;i++)DOWriteFLag[i]|=0x0002;
			break;
		case 16:  //15：写多个保持寄存器
			for(i=0;i<10;i++)HoldWriteFLag[i]|=0x0001;
			break;
		case 3:  //3：读多个保持寄存器
			for(i=0;i<10;i++)HoldReadFLag[i]|=0x0001;
			RegNum = src[srcindex++]/2;
			for(i=0;i<RegNum;i++)
			{
				srcindex+=methord::u8tou16(&src[srcindex],&HoldStatus[i]);
			}
			break;
		case 4:  //4：读多个只读寄存器
			for (i = 0; i<10; i++)InputReadFLag[i] |= 0x0001;
			RegNum = src[srcindex++] / 2;
			for (i = 0; i<RegNum; i++)
			{
				srcindex += methord::u8tou16(&src[srcindex], &InputStatus[i]);
			}
			break;
		break;

	}
	return 0;
}



UINT ProcessIOEvent( LPVOID pParam )
{		
	s8 okflag=0;
	s8 sendflag=10;
	while(true)
	{	
		Sleep(10);	
		if ((GetTickCount() - Comm_.prevSendtime) > ((Comm_.IsDebug)?3000:50))
		{
			Comm_.prevSendtime = GetTickCount();

			sendflag--;
			if(sendflag==0)
			{		
				Comm_.AskDO();
				sendflag = 20;
			}
			else if(sendflag&0x01)
			{				
				Comm_.AskDI();
			}
			else 
			{
				Comm_.AskAI();
			}
				
		}

		Comm_.DealReceive();
		if(Comm_.CloseThread)return 0;
		if(Comm_.RstThread)
		{
				Comm_.RstThread = 0; 
				sendflag =3;
		}

	}
	return(0);
}