www.pudn.com > IEC104MasterSlave.rar > IEC104Master.cpp, change:2013-04-18,size:22221b


// IEC104Master.cpp: implementation of the CIEC104Master class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "NAIEC104Master.h" 
#include "IEC104Master.h" 
#include "IEC104Types.h" 
#include "CP56Time2a.h" 
#include "SocketException.h" 
#include <stdio.h> 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#if !defined( EOK ) 
#  define EOK 0         /* no error */ 
#endif 
 
#define EIO             5 
#define ENOENT          2 
#define ECONNECT        3 
 
BOOL isYKACK = false; 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CIEC104Master::CIEC104Master() 
{ 
	this->Connected=false; 
	RxThread = 0; 
	RxId	 = 0; 
	TrThread = 0; 
	TrId	 = 0; 
	Init(false); 
	SetParams(); 
	return; 
} 
 
CIEC104Master::~CIEC104Master() 
{ 
	// free resources 
	CloseLink(); 
	CloseHandle(TrThread); 
	return; 
} 
 
// 
//	Internal variables initialization 
// 
void CIEC104Master::Init(bool free) 
{ 
	if(RxThread) 
		CloseHandle(RxThread); 
	 
	if(free) 
		CloseHandle(TrThread); 
	 
	ErrorMode = 0; 
	Socket	  = 0; 
	RxThread  = 0; 
	RxId	  = 0; 
	//TrThread  = 0; 
	//TrId	  = 0; 
	RxCounter = 0; 
	TxCounter = 0; 
	LastAckRx = 0; 
	LastAckTx = 0; 
	timer_Connect = 0; 
	timer_Confirm = 0; 
	timer_S_Ack	  = 0; 
	timer_U_Test  = 0; 
	 
	//	timer_Connectflag = false; 
	//	timer_Confirmflag = false; 
	timer_S_Ackflag	  = true; 
	timer_U_Testflag  = true;    // 初始化为真,如果过程中有超时,置为false 
	 
	return; 
} 
 
// 
//	Open TCP/IP connection.  创建socket, 建立连接connect 
// 
int CIEC104Master::OpenLink(char *serverIP, int port) 
{ 
	WORD wVersionRequested; 
	int wsaerr; 
	 
	// connected ? 
	if(GetSockConnectStatus()) 
	{ 
		// report warning 
		sprintf(LastError, "Socket is connected!\n"); 
		TRACE(LastError); 
		if(!ErrorMode) 
			this->OnErrorMsg(EIO, LastError); 
		else 
			throw new SocketException(LastError, EIO); 
		return ECONNECT; 
	} 
	else 
	{ 
		// Using MAKEWORD macro, Winsock version request 2.2 
		wVersionRequested = MAKEWORD(2, 2); 
		wsaerr = WSAStartup(wVersionRequested, &wsaData); 
		if(wsaerr != 0) 
		{ 
			/* Tell the user that we could not find a usable */ 
			/* WinSock DLL.*/ 
			sprintf(LastError, "The Winsock dll not found!\n"); 
			TRACE(LastError); 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return ENOENT; 
		} 
#ifdef _DEBUG 
		sprintf(LastError, "The Winsock dll found! - The status: %s.\n", wsaData.szSystemStatus); 
		TRACE(LastError); 
#endif 
		sprintf(this->RemoteHost, serverIP); 
		this->RemotePort = port; 
 
		// init socket 
		// Create the socket as a IPv4 (AF_INET). 
		Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
		if(Socket == INVALID_SOCKET) 
		{ 
			//Output the error recieved when creating the socket. 
			sprintf(LastError, "Socket error: %ld\n", WSAGetLastError()); 
			TRACE(LastError); 
			WSACleanup(); 
			Socket = 0; 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
 
		//Assign the remote info to our socket address structure. 
		RemoteInfo.sin_family = AF_INET; 
		RemoteInfo.sin_addr.s_addr = inet_addr(this->RemoteHost); 
		RemoteInfo.sin_port = htons((SHORT)this->RemotePort); 
 
#if 0 
		if(!TrThread) 
		{ 
			// TrThread = CreateThread(0, 0, &this->TimerHandler, (LPVOID)this,0, &TrId); 
			TrThread = CreateThread(0, 0, &this->TimerHandler, (LPVOID)this,0, NULL); 
			if(TrThread==0) 
			{ 
				sprintf(LastError, "CreateThread() failed: %d\n",GetLastError()); 
				TRACE(LastError); 
				if(!ErrorMode) 
					this->OnErrorMsg(EIO, LastError); 
				else 
					throw new SocketException(LastError, EIO); 
				//CloseLink(); 
				return EIO; 
			} 
		} 
#endif 
 
		//Time to connect to the remote computer! 
		if(connect(Socket, (SOCKADDR*)&RemoteInfo, sizeof(RemoteInfo)) == SOCKET_ERROR) 
		{ 
			sprintf(LastError, "Socket error: Unable to establish a connection to %s:%i!\n", RemoteHost, RemotePort); 
			TRACE(LastError); 
			closesocket(Socket); 
			WSACleanup(); 
			Socket = 0; 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
 
		// 创建接收线程 
		// RxThread = CreateThread(0, 0, &this->RxHandler, (LPVOID)this,0, &RxId); 
		RxThread = CreateThread(0, 0, &this->RxHandler, (LPVOID)this,0, NULL); 
		if(RxThread==0) 
		{ 
			sprintf(LastError, "CreateThread() failed: %d\n",GetLastError()); 
			TRACE(LastError); 
			CloseLink(false); 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
	} 
	this->Connected=true; 
	return EOK; 
} 
 
// 
// 	Close TCP/IP connection 
// 
int CIEC104Master::CloseLink(bool free) 
{ 
	this->Connected = false; 
	shutdown(Socket, SD_BOTH);  //   禁止在一个套接口上进行数据的接收与发送 
	closesocket(Socket);        //   关闭一个套接口 
	WSACleanup();				// 终止Winsock 2 DLL (Ws2_32.dll) 的使用. 
	Init(free); 
	return EOK; 
} 
 
// 
//	TX U-Format Message (APCI only) 
// 
int CIEC104Master::Send_U_Msg(int cmd) 
{ 
	if(GetSockConnectStatus()) 
	{ 
		APCI header; 
		header.start = 0x68; 
		header.len=0x04; 
		header.field1 = 0x03 | cmd;			// U-Format 
		header.field2 = 0; 
		header.field3 = 0; 
		header.field4 = 0; 
		 
		if(send(Socket, (const char*)&header, sizeof(header), 0) == SOCKET_ERROR) 
		{ 
			sprintf(LastError, "send() failed with error: %d\n", WSAGetLastError()); 
			TRACE(LastError); 
			CloseLink(false); 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
		 
		// call callback 
		this->OnTxMsg((BYTE*)&header,sizeof(header)); 
//		this->timer_U_Testflag = false;		// reset TestFR time-out 
 
		return EOK; 
	} 
	sprintf(LastError, "No socket connection!\n"); 
	TRACE(LastError); 
	if(!ErrorMode) 
		this->OnErrorMsg(EIO, LastError); 
	else 
		throw new SocketException(LastError, EIO); 
	return EIO; 
} 
 
// 
//	TX S-Format Message (APCI only) 
// 
int CIEC104Master::Send_S_Msg(void) 
{ 
	if(GetSockConnectStatus() && !GetIsResponseIFrame() && !GetIsResponseS()) 
	{ 
		APCI header; 
		header.start  = 0x68; 
		header.len    = 0x04; 
		header.field1 = 0x01;				// S-Format 
		header.field2 = 0; 
		header.field3 = RxCounter & 0xFE; 
		header.field4 = (RxCounter>>8) & 0xFF; 
		 
//		LastAckRx = RxCounter;				// memorize last rx acknowledge 
		 
		if(send(Socket, (const char*)&header, sizeof(header), 0) == SOCKET_ERROR) 
		{ 
			sprintf(LastError, "send() failed with error: %d\n", WSAGetLastError()); 
			TRACE(LastError); 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
		 
		// call callback 
		this->OnTxMsg((BYTE*)&header,sizeof(header)); 
//		this->timer_U_Testflag = false;		// reset TestFR time-out 
//		this->timer_S_Ackflag  = false;		// reset ACK time-out. 
		return EOK; 
	} 
	 
	sprintf(LastError, "No socket connection!\n"); 
	TRACE(LastError); 
	if(!ErrorMode) 
		this->OnErrorMsg(EIO, LastError); 
	else 
		throw new SocketException(LastError, EIO); 
	return EIO; 
} 
 
// 
//	TX I-Format Message (always contains ASDU) 
// 
int CIEC104Master::Send_I_Msg(BYTE *msgbuf, unsigned int len) 
{ 
	if(GetSockConnectStatus() && !GetIsResponseIFrame()) 
	{ 
		char buf[1024]; 
		 
		APCI *header = (APCI*)buf; 
		(*header).start = 0x68; 
		(*header).len=0x04 + len;		 
		(*header).field1 = TxCounter & 0xFE;// I-Format 
		(*header).field2 = (TxCounter>>8) & 0xFF; 
		(*header).field3 = RxCounter & 0xFE;// I-Format 
		(*header).field4 = (RxCounter>>8) & 0xFF; 
		 
//		LastAckRx = RxCounter;				// memorize last rx acknowledge 
		 
		memcpy(&buf[sizeof(APCI)],msgbuf,len); 
		 
		if(send(Socket, (const char*)buf, len + sizeof(APCI), 0) == SOCKET_ERROR) 
		{ 
			sprintf(LastError, "send() failed with error: %d\n", WSAGetLastError()); 
			TRACE(LastError); 
			CloseLink(false); 
			if(!ErrorMode) 
				this->OnErrorMsg(EIO, LastError); 
			else 
				throw new SocketException(LastError, EIO); 
			return EIO; 
		} 
		 
		// call callback 
		this->OnTxMsg((BYTE*)&buf, len + sizeof(APCI)); 
		 
//		this->timer_U_Testflag = false;		// reset TestFR time-out 
//		this->timer_S_Ackflag  = false;		// reset ACK time-out. 
		 
		// increment N(S) Send Sequence Number 
		TxCounter += 2; 
		 
		return EOK; 
	} 
	 
	sprintf(LastError, "No socket connection!\n"); 
	TRACE(LastError); 
	if(!ErrorMode) 
		this->OnErrorMsg(EIO, LastError); 
	else 
		throw new SocketException(LastError, EIO); 
	return EIO; 
} 
 
// 
//	START Command 
// 
int CIEC104Master::Send_StartDT(void) 
{ 
	return Send_U_Msg(CMD_STARTDT); 
} 
 
// 
//	STOP Command 
// 
int CIEC104Master::Send_StopDT(void) 
{ 
	return Send_U_Msg(CMD_STOPDT); 
} 
 
// 
//	TEST Frame Command 
// 
int CIEC104Master::Send_TestFR(void) 
{ 
	return Send_U_Msg(CMD_TESTFR); 
} 
 
// 
//	Interrogation Command 
// 
int CIEC104Master::Interrogate(int asdu, int group) 
{ 
	ASDU msg; 
	msg.header.type = 0x64;					// interrogation command 
	msg.header.qual = 0x01;					// number of elements 
	msg.header.tx_cause_1 = 0x06;			// activation 
	msg.header.tx_cause_2 = 0x00; 
	msg.header.commom_asdu_1 = asdu & 0xFF; 
	msg.header.commom_asdu_2 = (asdu>>8) & 0xFF; 
	// 貌似少了3个字节的信息体地址 
	// group information 
	msg.data[0] = 0x00; 
	msg.data[1] = 0x00; 
	msg.data[2] = 0x00; 
	msg.data[3] = 20 + group; 
	return Send_I_Msg((BYTE*)&msg, 10); 
} 
 
// 
//	Connection Stastus 
// 
bool CIEC104Master::GetSockConnectStatus(void) 
{ 
	return Connected; 
} 
 
// 
//	Change the mode of error reporting, by default throuth function returned 
//  code:  mode = 0 - by callback / mode = 1 - by exception  
// 
void CIEC104Master::SetErrorMode(int mode) 
{ 
	this->ErrorMode = mode; 
} 
 
// 
// Error reporting 
// 
void CIEC104Master::GetLastErrorMsg(char *msgbuf, size_t len) 
{ 
	if((len >= strlen(LastError)) && (msgbuf!=0)) 
		strcpy(msgbuf, LastError); 
	return; 
} 
 
// 
//	I-Formar message decodification I格式帧解码 
// 
int CIEC104Master::Decode_I_Msg(BYTE *msgbuf, unsigned int len) 
{ 
	ASDU_header *header=NULL; 
	unsigned char num=0, cause=0, n=0; 
	bool seq=false; 
	int	 asdu=0; 
	 
	header = (ASDU_header*)msgbuf; 
 
	num = header->qual & 0x7F;	// number of objects. 
	if(header->qual & 0x80)		// sequence of objects ? 
		seq = true; 
 
	cause = header->tx_cause_1;	// cause of tx. 
	asdu = header->commom_asdu_2 << 8; 
	asdu |= header->commom_asdu_1; 
 
#ifdef _DEBUG 
	sprintf(LastError, "ASDU Address=%d\tTypeID=%d\tCount=%d\tCause=%d\n", 
		asdu, header->type, num, cause); 
//	TRACE(LastError); 
#endif 
 
	// actual time 
	SYSTEMTIME st; 
	FILETIME ft; 
	GetSystemTime(&st); 
	SystemTimeToFileTime(&st,&ft); 
 
	unsigned int pos; 
	unsigned long adr; 
 
	// type identification 
	switch(header->type) 
		{ 
			case 1:		// Single-point information 
				SIQ104	*pi; 
				if(seq) 
					{ 
					SP104 *ps = (SP104*)&msgbuf[sizeof(ASDU_header)]; 
					adr = ps->addr2<<16 | ps->addr1<<8 | ps->addr0; 
#ifdef _DEBUG 
					sprintf(LastError, "SP_%d: %d\tValid: %d\tBlocked: %d\n", 
						adr, ps->siq.spi, ps->siq.iv, ps->siq.bl); 
					TRACE(LastError); 
#endif 
					// call callback 
					this->OnRxSinglePoint(asdu, adr, ps->siq.spi, ps->siq.iv, 
						ps->siq.bl, ft); 
 
					pos = sizeof(ASDU_header)+sizeof(SP104); 
					while(pos < len) 
						{ 
						adr++; 
						pi = (SIQ104*)&msgbuf[pos]; 
#ifdef _DEBUG 
						sprintf(LastError, "SP_%d: %d\tValid: %d\tBlocked: %d\n", 
							adr, pi->spi, pi->iv, pi->bl); 
						TRACE(LastError); 
#endif					 
						// call callback 
						this->OnRxSinglePoint(asdu, adr, ps->siq.spi, ps->siq.iv, 
							ps->siq.bl, ft); 
 
						pos++; 
						} 
					if(cause == 3) 
						Send_S_Msg(); // 突发上送之后发送S帧确认 
					} 
				else 
					{ 
					pos = sizeof(ASDU_header); 
					while(pos < len) 
						{ 
						SP104 *ps = (SP104*)&msgbuf[pos]; 
						adr = ps->addr2<<16 | ps->addr1<<8 | ps->addr0; 
#ifdef _DEBUG 
						sprintf(LastError, "SP_%d: %d\tValid: %d\tBlocked: %d\n", 
							adr, ps->siq.spi, ps->siq.iv, ps->siq.bl); 
						TRACE(LastError); 
#endif						 
						// call callback 
						this->OnRxSinglePoint(asdu, adr, ps->siq.spi, ps->siq.iv, 
							ps->siq.bl, ft); 
 
						pos+=sizeof(SP104); 
						} 
					} 
				break; 
			case 13:	// Measure value, short floating point value  短浮点数测量值 
					pos = sizeof(ASDU_header); 
					while(pos < len) 
						{ 
						SFP104 *pf = (SFP104*)&msgbuf[pos]; 
						adr = pf->addr2<<16 | pf->addr1<<8 | pf->addr0; 
						float *val = (float*)&pf->val[0]; 
#ifdef _DEBUG 
						sprintf(LastError, 
							"SFP_%d: %3.1f\tOFlow: %d\tValid: %d\tBlocked: %d\n", 
							adr, *val, pf->qds.ov, pf->qds.iv, pf->qds.bl); 
						TRACE(LastError); 
#endif						 
						// call callback 
						this->OnRxMeasuredValue(asdu, adr, *val, pf->qds.iv, 
							pf->qds.bl, ft); 
 
						pos+=sizeof(SFP104); 
						} 
				break; 
			case 30:	// Single-point information with time tag CP56Time2a 带CP56时标的单点信息 
					pos = sizeof(ASDU_header); 
					while(pos < len) 
						{ 
						SP104_T *ps = (SP104_T*)&msgbuf[pos]; 
						adr = ps->addr2<<16 | ps->addr1<<8 | ps->addr0; 
						CP56Time2a *t = new CP56Time2a(ps->time); 
#ifdef _DEBUG 
						char buf[40]; 
						t->GetTimeString(buf,40); 
						sprintf(LastError, "SP_%d: %d\tValid: %d\tBlocked: %d\t%s\n", 
							adr, ps->siq.spi, ps->siq.iv, ps->siq.bl, buf); 
						TRACE(LastError); 
#endif						 
						// call callback 
						this->OnRxSinglePoint(asdu, adr, ps->siq.spi, ps->siq.iv, 
							ps->siq.bl, t->_GetFileTime()); 
						 
						pos+=sizeof(SP104_T); 
						} 
					if(cause == 3) 
						Send_S_Msg(); // 突发上送之后发送S帧确认 
				break; 
			case 36:	// Measure value, short float point value w/CP56Time2a 带CP56时标的短浮点测量值 
					pos = sizeof(ASDU_header); 
					while(pos < len) 
						{ 
						SFP104_T *pf = (SFP104_T*)&msgbuf[pos]; 
						adr = pf->addr2<<16 | pf->addr1<<8 | pf->addr0; 
						float *val = (float*)&pf->val[0]; 
						CP56Time2a *t = new CP56Time2a(pf->time); 
#ifdef _DEBUG 
						char buf[40]; 
						t->GetTimeString(buf,40); 
						sprintf(LastError, 
							"SFP_%d: %3.1f\tOFlow: %d\tValid: %d\tBlocked: %d\t%s\n", 
							adr, *val, pf->qds.ov, pf->qds.iv, pf->qds.bl, buf); 
						TRACE(LastError); 
#endif						 
						// call callback 
						this->OnRxMeasuredValue(asdu, adr, *val, pf->qds.iv, 
							pf->qds.bl, t->_GetFileTime()); 
 
						pos+=sizeof(SFP104_T); 
						} 
				break; 
#ifdef _DEBUG 
			case 45: 
				if(cause == 7 && !isYKACK)  // 收到遥控返校 
				{ 
					OnYKEXE(msgbuf, len);// 遥控执行 
					isYKACK = true; 
				} 
				else if(cause == 7 && isYKACK) 
				{ 
					OnYKDeact(msgbuf, len); // 遥控撤销 
					isYKACK = false; 
				} 
				break; 
			case 70:	//站端初始化结束 
				TRACE("End of Initialization\n"); 
				break; 
			case 100:  // 总召唤命令 
				if(cause == 7)  // 激活确认 
					sprintf(LastError, "Interrogation Command (Group %d): Activation Confirmation.\n", 
						msgbuf[9]-20); 
				else if(cause == 10)   // 激活结束 
				{ 
					Send_S_Msg();      // 总召唤结束发送S帧确认 
					sprintf(LastError, "Interrogation Command (Group %d): Activation Termination.\n", 
						msgbuf[9]-20); 
				} 
				else 
					sprintf(LastError, "Interrogation Command (Group %d): Unknown.\n", 
						msgbuf[9]-20); 
				TRACE(LastError); 
				break; 
			default: 
					TRACE("Not Implemented!\n"); 
				break; 
#endif 
		} 
 
	return EOK; 
} 
 
 
// 
// RX Thread  消息接收线程 
// 
DWORD WINAPI CIEC104Master::RxHandler(LPVOID lpParam) 
{ 
	char buf[65535]; 
	int  res = 0; 
	unsigned int  j = 0; 
	unsigned char len = 0; 
	 
	CIEC104Master *master = (CIEC104Master*)lpParam; 
	 
	//	TRACE("Rx handler ready!\n"); 
	 
	while(res != SOCKET_ERROR) 
	{ 
		res = recv(master->Socket, buf, sizeof(buf), 0); 
		 
		if(res <= 0 || res == WSAECONNRESET) 
		{ 
			//	TRACE( "Connection Closed.\n"); 
			if(master != NULL) 
				master->onUpdateWnd();; 
			AfxMessageBox("连接已断开"); 
			  
			// 相当于点击停止 
			// 界面相应按钮变灰 
			break; 
		} 
 
		// 将接收到的报文显示出来 
	//	master->OnRxMsg((BYTE*)&buf, res); 
#if 1 
		j   = 0; 
		len = 0; 
		while(j < (unsigned)res) // 68是启动字符  长度  控制域1-4 
		{ 
			if(buf[j] == 0x68) 
			{ 
				len = buf[j+1]; 
			//	_ASSERT(len <= MAX_ASDU_LENGTH); // ERROR 
				if((j+len <= (unsigned)res) && (len <= MAX_ASDU_LENGTH)) 
				{ 
					// call callback 
					master->OnRxMsg((BYTE*)&buf[j], len+2); 
					 
					APCI *p = (APCI*) &buf[j]; 
					int formatType = p->field1&0x03; 
					if(formatType == 0 || formatType == 2) 
					{ 
						//master->RxCounter+=2;	// increment N(R) Recv. Sequence Number 
						master->timer_S_Ackflag  = false;		// 收到I格式帧的时候置为false, 超时的时候置为true. 
 
					//	master->RxCounter = (p->field2<<8) | p->field1; 
 
						int revSendNum = (p->field2<<8) | p->field1; 
						master->RxCounter = revSendNum; 
 
						/* 
						if(master->RxCounter == revSendNum) 
							master->RxCounter += 2;   // 如果收到的发送序号与接收序号相等,接收序号加1 
						else if(master->RxCounter < revSendNum) 
							;// 有报文丢失 
						else if(master->RxCounter > revSendNum) 
							;// 发送方发生了重传 
						*/ 
 
						master->LastAckTx = (p->field4<<8) | p->field3; 
 
 
						master->Send_S_Msg(); 
						master->Decode_I_Msg((BYTE*)&buf[j+sizeof(APCI)], len+2-sizeof(APCI)); 
					//	master->OnRxAsduMsg((BYTE*)&buf[j+sizeof(APCI)], len+2-sizeof(APCI)); 
					} 
 
					else 
					{ 
						if(formatType == 1)    /*  S  */  
							; 
						else 
						{ 
							if(formatType == 3) /*  U  */ 
							{ 
								master->ProcessFormatU(p);								 
								master->LastAckTx = (p->field4<<8) | p->field3; 
							} 
						} 
						 
					} 
					master->timer_U_Testflag = false;		// 接收到I S U格式的帧都需要重置,表示t3内已经接收到报文 
					 
					j = j + len + 1; 
					_ASSERT(len < res);	//ERROR 
				} 
			} 
			j++; 
		} 
#endif 
		Sleep(75); 
	} 
	return 0; 
} 
 
// 
//	Timer for IEC104 events control 
// 
DWORD WINAPI CIEC104Master::TimerHandler(LPVOID lpParam) 
{ 
	CIEC104Master *master = (CIEC104Master*)lpParam; 
	 
	TRACE("Timer handler ready!\n"); 
	 
	while(1) 
	{ 
	//	Sleep(1000); 
		// 间隔1s 
		int timeOrigin = GetTickCount(); 
		while((GetTickCount() - timeOrigin) < 1000); 
 
		if(!master->GetSockConnectStatus())  // t0时间内连接未建立则重新连接并发送U启动帧激活数据传输 
		{ 
			// time-out for reconnection. 
			master->timer_Connect++; 
			if(master->timer_Connect > master->T0) // TCP连接建立的超时时间(超时重新连接) 
			{ 
				master->timer_Connect = 0; 
				if(master->OpenLink(master->RemoteHost, master->RemotePort) == EOK) 
					master->Send_StartDT(); 
			} 
		} 
		else 
		{ 
			// maximun number of frames received before master send ACK. W 
			if((master->RxCounter - master->LastAckRx) >= master->W * 2) 
				// master->Send_S_Msg(); 
			 
			// time-out of waiting ACK to Sended APDU o TestFR 
			master->timer_Confirm++; 
			// t1:RTU(服务器)端启动U格式测试过程后等待U格式测试应答的超时时间(超时处理:断开连接) 
			if(master->timer_Confirm > master->T1)  
			{ 
				if(master->TxCounter - master->LastAckTx > 6) 
				{ 
					master->CloseLink(false); 
				} 
				//master->timer_Confirmflag = true; 
			} 
			 
			// time-out for no data to send, send S-frame to ack data received. OK 
			master->timer_S_Ack++; 
			// t2规定接收方在接收到I格式报文后,若经过t2时间未再收到新的I格式报文, 
	       // 则必须向发送方发送S格式帧对已经接收到的I格式报文进行认可,显然t2必须小于t1。 
			if(master->timer_S_Ack > master->T2)  // (T2 < T1). S格式的超时时间 
			{ 
				master->timer_S_Ack=0; 
				if(master->timer_S_Ackflag)       // 在收到I格式报文的时候置timer_S_Ack为0 
					master->Send_S_Msg(); 
				master->timer_S_Ackflag = true; 
			} 
			 
			// time-out for idle status, send test frame to check link state. OK 
			// t3规定调度端或子站RTU端每接收一帧 I帧、S帧或者U帧将重新触发计时器t3,若在t3内未接收到任何报文,将向对方发送测试链路帧 
			master->timer_U_Test++; 
			if(master->timer_U_Test > master->T3)  // 没有实际的数据交换时,任何一端启动U格式测试过程的最大间隔时间 (发送测试帧) 
			{ 
				master->timer_U_Test=0; 
				if(master->timer_U_Testflag)      // 接收到I S U帧都将timer_U_Test置为0 
					master->Send_TestFR(); 
				master->timer_U_Testflag = true; 
			} 
		} 
	} 
	return 0; 
} 
 
// 
//	IEC 104 Link Parameters 
// 
int CIEC104Master::SetParams(int t0, int t1, int t2, int t3, int k, int w) 
{ 
	T0 = t0; 
	T1 = t1; 
	T2 = t2; 
	T3 = t3; 
	K  =  k; 
	W  =  w; 
	 
	return EOK; 
} 
 
void CIEC104Master::Send_ASDU_Msg(BYTE *msgbuf, int len) 
{ 
	int Index = 0; 
	ASDU msg; 
	msg.header.type = msgbuf[Index++];					// interrogation command 
	msg.header.qual = msgbuf[Index++];					// number of elements 
	msg.header.tx_cause_1 = msgbuf[Index++];			    // activation 
	msg.header.tx_cause_2 = msgbuf[Index++]; 
	msg.header.commom_asdu_1 = msgbuf[Index++] & 0xFF; 
	msg.header.commom_asdu_2 = (msgbuf[Index++]>>8) & 0xFF; 
 
	int groupLen = len - 6; 
 
	// group information 
	for(int i = 0; i<groupLen; i++) 
	{ 
		msg.data[i] = msgbuf[Index++]; 
	} 
	Send_I_Msg((BYTE*)&msg, len); 
} 
 
/***********************遥控执行*********************************/ 
void CIEC104Master::OnYKEXE(BYTE *msgbuf, unsigned int len) 
{ 
	msgbuf[2] = 0x06; 
	msgbuf[9] = 0x01; 
	Send_I_Msg(msgbuf, len); 
} 
 
/***********************遥控撤销*********************************/ 
void CIEC104Master::OnYKDeact(BYTE *msgbuf, unsigned int len) 
{ 
	msgbuf[2] = 0x08; 
	Send_I_Msg(msgbuf, len); 
} 
 
void CIEC104Master::ProcessFormatU(APCI *p) 
{ 
	if((p->field1 & 0xfc) == CMD_STARTDT) // 判断是否是U帧  	// U启动 
	{ 
		Send_U_Msg(CMD_STARTC); 
	} 
	else if((p->field1 & 0xfc) == CMD_STOPDT)  	 // U停止 
	{ 
		Send_U_Msg(CMD_STOPC); 
	} 
	else if((p->field1 & 0xfc) == CMD_TESTFR && !this->GetIsResponseUTest())     // U测试 
	{ 
		Send_U_Msg(CMD_TESTC); 
	} 
}