⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialcommlayer.cpp

📁 串口通讯在客户端/服务器类型的应用程序设计中经常要使用到
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    LPBYTE lpszStringToWrite = (LPBYTE) LocalAlloc(LPTR, dwNumberOfBytesToWrite);
	memcpy(lpszStringToWrite,cCmdStr,dwNumberOfBytesToWrite);

	if (WriteThread->PostThreadMessage(PWM_COMMWRITE, 
		(WPARAM) (dwNumberOfBytesToWrite), (LPARAM) lpszStringToWrite))
	{
		return 0;
	}
	LocalFree(lpszStringToWrite);
	return 1;
}

//
//  函数: BOOL CRCCComm::CheckSum(RCCFrameHead Header)
//  用途: 校验检查和是否正确.
//  参数: 
//    Header 帧头数据
//  返回值:
//      TRUE 校验成功
//      FALSE 校验失败
//  备注:
//  帧头检查和是一字节的简单数据校验和
// 
BOOL CRCCComm::CheckSum(RCCFrameHead Header)
{
	WORD wCheckSum=0;
	BYTE bCheckSum=0;
	int i;
	bCheckSum = Header.CheckSum;
	Header.CheckSum = 0;
	for ( i=0;i < HeaderSize; i++)
		wCheckSum += ((BYTE *)&Header)[i];
	if((wCheckSum & 0xFF) == bCheckSum) 
		return TRUE;
	else return FALSE;
}

//
//  函数: BYTE CRCCComm::GetCheckSum(RCCFrameHead *Header)
//  用途: 得到帧头检查和
//  参数: 
//    Header 帧头数据
//  返回值:
//      帧头数据校验值
//  备注:
//  帧头检查和是一字节的简单数据校验和
// 
BYTE CRCCComm::GetCheckSum(RCCFrameHead *Header)
{
	WORD wCheckSum=0;
	int i;
	for ( i=0;i < HeaderSize; i++)
		wCheckSum += ((BYTE *)Header)[i];
	return (BYTE)(wCheckSum&0xFF);
}

//
//  函数: int CRCCComm::GenOneFrame(void)
//  用途: 将SendBuffer之中的数据生成一个帧,放入类变量DataFrame,准备发送出去。
//  参数: 无
//  返回值:
//      0表示成功
//  备注:
//  数据发送将采取压缩方式,如果压缩后长度大于压缩前长度,则采用非压缩方式
//
int CRCCComm::GenOneFrame(void)
{
	int FrameLength = min(BytesPerBlock,SendBufferLength);

	DataFrame.Header.Flag = FrameFlag;
	DataFrame.Header.Version = RCC_VERSION;
	int SendFrameNo = (PrevSendFrameNo==255?1:PrevSendFrameNo+1);
	DataFrame.Header.FrameNo = SendFrameNo;
	PrevSendFrameNo = SendFrameNo;
	DataFrame.Header.Reserved = 0;
	DataFrame.Header.CheckSum = 0;

#ifdef __RCC_ZIP__
	FileEncodeDecode encodeObject(SendBuffer,ZippedBuf,FrameLength);
    int ZippedLength = encodeObject.Encode(); //赋值压缩后的长度
	if((ZippedLength != -1) && (ZippedLength+2 < FrameLength))
	{
		DataFrame.Header.Kind = frmZippedData;
		memcpy(DataFrame.Data+2,ZippedBuf,ZippedLength);
		DataFrame.Header.Length = ZippedLength + 2;
		*(WORD *)DataFrame.Data = FrameLength;
		DataFrame.Crc = GetCrc(ZippedLength+2,(BYTE *)DataFrame.Data);
	}
	else
	{
#endif
		DataFrame.Header.Kind = frmData;
		DataFrame.Header.Length = FrameLength;
		memcpy(DataFrame.Data,SendBuffer,FrameLength);
		DataFrame.Crc = GetCrc(FrameLength,(BYTE *)DataFrame.Data);
#ifdef __RCC_ZIP__
	}
#endif
	DataFrame.Header.CheckSum = GetCheckSum(&DataFrame.Header);

#ifdef __RCC_DEBUG__
	char DbgMsg[100];
	sprintf(DbgMsg,"[%d]生成一帧,长度[%d],RCCStatus[%d]",SendFrameNo,FrameLength+10,RCCStatus);
	DisplayMessage(DbgMsg);

	int hLogFile;
    if ( ( hLogFile = sopen ( "Log.Txt", O_RDWR | O_APPEND | O_CREAT ,SH_DENYNO,
        S_IREAD | S_IWRITE ) ) != -1 )
	{
        _write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
		_write ( hLogFile,"\r\n",2);
		for ( int m=0; m<FrameLength+10; m++)
		{
			if(!(m%20))
				_write ( hLogFile,"\r\n",2);
			sprintf(DbgMsg,"[%X]",((unsigned char*)&DataFrame)[m]);
			_write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
		}
		_write ( hLogFile,"\r\n",2);
		_close(hLogFile);
	}
#endif

	DelDealtData(SendBuffer,SendBufferLength,FrameLength);
	return 0;
}

//
//  函数: int CRCCComm::SendDataFrame(void)
//  用途: 将GenOneFrame函数生成的DataFrame帧发送出去。
//  参数: 无
//  返回值:
//      0 表示成功
//      1 表示失败
//  备注:
// 
int CRCCComm::SendDataFrame(void)
{
	int dwNumberOfBytesToWrite = HeaderSize+2+DataFrame.Header.Length;
    LPBYTE lpszStringToWrite = (LPBYTE) LocalAlloc(LPTR, dwNumberOfBytesToWrite);
	memcpy(lpszStringToWrite,&DataFrame,dwNumberOfBytesToWrite);

	if (WriteThread->PostThreadMessage(PWM_COMMWRITE, 
		(WPARAM) dwNumberOfBytesToWrite, (LPARAM) lpszStringToWrite))
	{
		WriteTime = GetTickCount();
		return 0;
	}
	LocalFree(lpszStringToWrite);
	return 1;
}

//
//  函数: int CRCCComm::SendMsgFrame(BYTE frmType,int NewFrameOrReSend)
//  用途: 生成一个消息帧,用于应答数据
//  参数: 
//      frmType 帧类别
//      NewFrameOrReSend 指示是重新生成还是重发上一消息帧
//  返回值:
//      0 表示成功
//      1 表示失败
//  备注:
//      如果发送frmSysError帧数量达到十次,再关闭链接
// 
int CRCCComm::SendMsgFrame(BYTE frmType,int NewFrameOrReSend)
{
	if(NewFrameOrReSend != RESEND)
	{ //重新生成新的一帧
		MsgFrame.Flag = FrameFlag;
		MsgFrame.Version = RCC_VERSION;
		MsgFrame.FrameNo = PrevReceFrameNo;
		MsgFrame.Length = HeaderSize;
		MsgFrame.Reserved = 0;
		MsgFrame.CheckSum = 0;
		switch(frmType)
		{
		case frmDataAnswer://数据应答帧
			MsgFrame.Kind = frmDataAnswer;
			frmErrorNums = 0;
			break;
		case frmPolling://检测帧
			MsgFrame.FrameNo = PrevSendFrameNo;
			MsgFrame.Kind = frmPolling;
			frmErrorNums = 0;
			break;
		case frmPlAnswer://检测应答帧
			MsgFrame.Kind = frmPlAnswer;
			frmErrorNums = 0;
			break;
		case frmAbort://异常中止帧
			MsgFrame.FrameNo = 0;
			MsgFrame.Kind = frmAbort;
			frmErrorNums = 0;
			break;
		case frmSysError://系统错误帧
			MsgFrame.Kind = frmSysError;
			frmErrorNums ++;
			if(frmErrorNums >= 10)
			{
				PostRCCMessage(RCC_ERROR,0);
				Close();
				return 1;
			}
			break;
		default:
			ASSERT(FALSE);
			return 1;
		}
		MsgFrame.CheckSum = GetCheckSum(&MsgFrame);
		if(frmType != frmSysError)
		{
			LastFrameClass = 2;
		}
	}

#ifdef __RCC_DEBUG__
	char DbgMsg[100];
	sprintf(DbgMsg,"发应的应答帧[%d],帧号[%d]",MsgFrame.Kind,MsgFrame.FrameNo);
	DisplayMessage(DbgMsg);
#endif

    LPBYTE lpszStringToWrite = (LPBYTE) LocalAlloc(LPTR, HeaderSize);
	memcpy(lpszStringToWrite,&MsgFrame,HeaderSize);

	if (WriteThread->PostThreadMessage(PWM_COMMWRITE, 
		(WPARAM)HeaderSize, (LPARAM) lpszStringToWrite))
	{
		return 0;
	}
	LocalFree(lpszStringToWrite);
	return 1;
}

//
//  函数: LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
//  用途: 底层通讯消息截获函数
//  参数: 
//  返回值:
//  备注:
//  本底层主要的通讯方式基于消息,所有的消息分发都通过本函数 
LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	// TODO: Add your specialized code here and/or call the base class
	int Device;
	int NotifyCode;
	switch(message)
	{
	case WM_TIMER: //时间处理函数
		Timer();
		return 1;
	case PWM_GOTCOMMDATA:
		OnRawReceive((LPSTR)lParam,(DWORD)wParam); //LPSTR lpNewString,DWORD dwSizeOfNewString)
		return 1;
	case PWM_REQUESTHANGUP: //关闭链接
#ifdef __RCC_DEBUG__
		DisplayMessage("关闭!");
#endif
		Close();
		return 1;
	case PWM_RECEIVEERROR:
#ifdef __RCC_DEBUG__
		DisplayMessage("发生错误!");
#endif
		return 1;
	case WM_RCCNOTIFY:
		NotifyCode = LOWORD(wParam);
		Device = HIWORD(wParam);
		switch(NotifyCode)
		{
		case RCC_RAWWRITE: //原始写入
			if(SendBufferLength <= 0)
			{
				PostRCCMessage(RCC_WRITE,0);				
				return 1;
			}
			if(RCCStatus == RCC_STAT_COMM) // || RCCStatus == RCC_STAT_POLLING
			{
				GenOneFrame(); //生成一帧数据帧
				SendDataFrame(); //发送一帧数据帧
				RCCStatus = RCC_STAT_DATA;
				LastFrameClass = 1;
			}
			return 1;
		case RCC_CONNECT:
			OnConnect();
			break;
		case RCC_READ:
			OnReceive();
			break;
		case RCC_WRITE:
			OnSend();
			break;
		case RCC_CLOSE:
			OnClose();
			break;
		case RCC_ERROR:
			OnError();
			break;
		case RCC_RAWREAD:
			break;
		case RCC_BIN_STATE:
			OnBinaryState(lParam);
			break;
		case RCC_STR_STATE:
			OnStringState(lParam);
			break;
		}
	}
	return CWnd::WindowProc(message, wParam, lParam);
}

//发送RCC底层通讯消息
int CRCCComm::PostRCCMessage(int Msg,int Notify)
{
	return PostMessage(WM_RCCNOTIFY,MAKEWPARAM(Msg,CommNo),Notify);
}

int CRCCComm::SendRCCMessage(int Msg,int Notify)
{
	return SendMessage(WM_RCCNOTIFY,MAKEWPARAM(Msg,CommNo),Notify);
}

//
//  函数: int CRCCComm::DelDealtData(char *Buffer,int &Length,int DelNum)
//  用途: 删除缓冲区的数据,并将剩下的数据往前挪
//  参数: 
//      Buffer 数据缓冲区
//      Length 数据缓冲区长度
//      DelNum 需要删除的数据长度
//  返回值: 目前无具体涵义
//  备注:
// 
int CRCCComm::DelDealtData(char *Buffer,int &Length,int DelNum)
{
	ASSERT(Length >= DelNum);
	if(DelNum <= 0) return 0;
	if(Length == DelNum)
	{
		Length = 0;
	}
	else
	{
		memcpy(Buffer,&Buffer[DelNum],Length-DelNum);
		Length -= DelNum;
	}
	return 0;
}

//
//  函数: int CRCCComm::OnRawReceive(LPSTR lpNewString,DWORD dwSizeOfNewString)
//  用途: 原始数据的接收,本函数是进行RCC协议解析的函数。
//  参数: 
//      lpNewString 接收到的新数据
//      dwSizeOfNewString 新数据的长度
//  返回值: 目前无具体涵义
//  备注:
//      如果应用程序想直接获取原始数据,可稍做修改,派生本函数
// 
int CRCCComm::OnRawReceive(LPSTR lpNewString,DWORD dwSizeOfNewString)
{
#ifdef __RCC_DEBUG__
	char DbgMsg[100];
	sprintf(DbgMsg,"接收到字符串[%d],RCCStatus[%d]",dwSizeOfNewString,RCCStatus);
	DisplayMessage(DbgMsg);
#endif
	if((RCCStatus == RCC_STAT_INIT || RCCStatus == RCC_STAT_ABORT) && (RCCMode == MODE_MODEM))
	{
		ParseAnswer(lpNewString,dwSizeOfNewString);
		delete lpNewString;
		return 1;
	}

#ifdef __RCC_DEBUG__
	int hLogFile;
    if ( ( hLogFile = sopen ( "Log.Txt", O_RDWR | O_APPEND | O_CREAT ,SH_DENYNO,
        S_IREAD | S_IWRITE ) ) != -1 )
	{
        _write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
		_write ( hLogFile,"\r\n",2);
		for ( unsigned int m=0; m<dwSizeOfNewString; m++)
		{
			if(!(m%20))
				_write ( hLogFile,"\r\n",2);
			sprintf(DbgMsg,"[%X]",(unsigned char)lpNewString[m]);
			_write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
		}
		_write ( hLogFile,"\r\n",2);
		_close(hLogFile);
	}
#endif

	if(ReceiveBufferLength + dwSizeOfNewString > ReceiveBufferMaxLength)
	{ //接收缓冲区溢出
		LastError = RCC_ERROR_OVERFLOW;
		PostRCCMessage(RCC_ERROR,RCC_ERROR_OVERFLOW);
		SendMsgFrame(frmAbort); //发送终止传输帧
		delete lpNewString;
		return 1;
	}
	memcpy(&ReceiveBuffer[ReceiveBufferLength],lpNewString,dwSizeOfNewString);
	ReceiveBufferLength += dwSizeOfNewString;
	delete lpNewString;
	int ret = 0;
	if(ReceiveBufferLength >= 54)
		ret = 0;
	while(ReceiveBufferLength >= HeaderSize)
	{
		ret = GetFrame(); //从接收缓冲区之内分析一个帧,将修改ReceiveBufferLength
		if(ret) //返回零则继续,其它不再继续处理
			break;
	}
	return 0;
}

//
//  函数: int CRCCComm::GetFrame(void) 
//  用途: 在帧缓冲区内进行帧分析,根据返回的错误进行相应的处理
//        本函数是系统中最重要的函数之一
//  参数: 无
//  返回值:
//       0 表示可继续解析帧
//       1 表示不再继续解析帧
//  备注:
// 
int CRCCComm::GetFrame(void)
{
	RCCFrameHead FrameHeader;
	int pos = SearchHead(); //首先找到帧头标志
	if(ReceiveBufferLength - pos < HeaderSize)
	{ //如果缓冲区不足以一个帧头
#ifdef __RCC_DEBUG__
		DisplayMessage("字符不够解析,1");
#endif
		return 1;
	}
	memcpy(&FrameHeader,&ReceiveBuffer[pos],HeaderSize);
	pos += HeaderSize;
	if(!CheckSum(FrameHeader))
	{ //检查和不对
#ifdef __RCC_DEBUG__
		DisplayMessage("检查和不对");
		ASSERT(FALSE);
#endif
		SendMsgFrame(frmSysError);
		return 1;
	}
	if(FrameHeader.Version != RCC_VERSION)
	{ //版本不对
#ifdef __RCC_DEBUG__
		DisplayMessage("版本不对");
		ASSERT(FALSE);
#endif
		LastError = RCC_ERROR_VERSION;
		PostRCCMessage(RCC_ERROR,RCC_ERROR_VERSION);
		SendMsgFrame(frmAbort); //发送终止传输帧
		Close();
		return 1;
	}

	RCCDataFrame Data;
	switch(FrameHeader.Kind)
	{
	case frmData://数据帧
		if(pos + FrameHeader.Length + 2 > ReceiveBufferLength)
		{ //缓冲区超出等待剩余部分数据到达
#ifdef __RCC_DEBUG__
			DisplayMessage("数据字符不够解析,1");
#endif
			return 1;
		}
		if(FrameHeader.Length>0 && FrameHeader.Length <=MaxBytesPerBlock)
		{
			//得到一帧数据
			memcpy(&Data,&ReceiveBuffer[pos-HeaderSize],
				HeaderSize + FrameHeader.Length + 2);
			pos += (FrameHeader.Length + 2);
			DelDealtData(ReceiveBuffer,ReceiveBufferLength,pos);
			if(RCCStatus == RCC_STAT_COMM||RCCStatus == RCC_STAT_DATA)
			{ //仅只有在此状态下才接收数据
				WORD Crc = GetCrc(FrameHeader.Length,(BYTE *)Data.Data);
				if(Data.Crc != Crc) //如果校验值不对
				{
#ifdef __RCC_DEBUG__
					DisplayMessage("CRC校验不对");
					ASSERT(FALSE);
#endif
					SendMsgFrame(frmDataAnswer,RESEND);
					return 1;
				}
				int ReceFrameNo=PrevReceFrameNo==255?1:PrevReceFrameNo+1;
				if(FrameHeader.FrameNo == PrevReceFrameNo)
				{ //如果是上一帧的重发帧,则忽略,发送接收OK

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -