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

📄 serialcommlayer.cpp

📁 串口通讯在客户端/服务器类型的应用程序设计中经常要使用到
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// SerialCommLayer.cpp : implementation file
//

#include "stdafx.h"
#include "SerialDlg.h"
#include "SerialCommLayer.h"

# include <io.h>
# include <share.h>
# include <fcntl.h>
# include <string.h>
# include <malloc.h>
# include <time.h>
# include <memory.h>
# include <process.h>
# include <sys\types.h>
# include <sys\stat.h>
# include <sys\locking.h>
# include <SYS\TIMEB.H>
# include <direct.h>
# include <errno.h>

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

extern UINT FileSize,nBytesRead;
extern char *FileBuf;
extern CListBox *SysListBox;
extern void DisplayMessage(char * msg);

#define  CrcGENERATE        0xa001   
WORD CrcTable[0x100];
#define INVALID_HANDLE (HANDLE)-1
#define __RCC_ZIP__ 1
#define __RCC_DEBUG__ 1
void CrcInit()
{
    WORD i,j;
    WORD crc;

    for(i=0;i<0x100;i++)
    {
	crc=i;
	for(j=0;j<8;j++)
	{
		if(crc&1)
		{
		    crc>>=1;
		    crc^=CrcGENERATE;
		}
		else
		    crc>>=1;
	}
	CrcTable[i]=crc;
     }
}



WORD  GetCrc(WORD count,BYTE *bufferP)
{
	static int first=1;
    
	WORD crc=0;
	BYTE msg;
	int i;

	if(first)
	{
		CrcInit();
		first=0;
	}
	for(i=0;i<count;i++,bufferP++)
	{
		msg=(crc&0xff)^(*bufferP);
		crc>>=8;
		crc^=CrcTable[msg];
	}
	return	crc;
}

/////////////////////////////////////////////////////////////////////////////
// CCommReadThread

IMPLEMENT_DYNCREATE(CCommReadThread, CWinThread)

CCommReadThread::CCommReadThread()
{
	hCommFile = NULL;
	hCloseEvent = NULL;
	hComm32Window = NULL;
}

CCommReadThread::~CCommReadThread()
{
}

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

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

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

/////////////////////////////////////////////////////////////////////////////
// CCommReadThread message handlers
/////////////////////////////////////////////////////////////////////////////
// CCommWriteThread

IMPLEMENT_DYNCREATE(CCommWriteThread, CWinThread)

CCommWriteThread::CCommWriteThread()
{
	hCommFile = NULL;
	hCloseEvent = NULL;
	hComm32Window = NULL;
	SendDataEmpty = TRUE;
}

CCommWriteThread::~CCommWriteThread()
{
}

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

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

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

/////////////////////////////////////////////////////////////////////////////
// CCommWriteThread message handlers


//(******************************************************************************)
//  READ THREAD
//(******************************************************************************)

//
//  过程名: CCommReadThread::Run
//  用途: 读线程的启动过程.
//  参数: 无
//  返回: 无
//  备注:
//  读线程使用异步读文件方式及将从端口收到的数据发送到应用程序窗口
//  读线程使用POSTMESSAGE发送消息,与应用程序的运行是异步进行的。
//  如果应用程序的关闭事件触发,则读线程退出。
//
//
int CCommReadThread::Run() 
{
	// TODO: Add your specialized code here and/or call the base class
	char szInputBuffer[INPUTBUFFERSIZE];
	DWORD nNumberOfBytesRead;
	
	HANDLE HandlesToWaitFor[3];
	DWORD dwHandleSignaled;
	
	DWORD fdwEvtMask;
	
	// 为异步文件读准备结构
	OVERLAPPED overlappedRead;
	
	// 为异步文件事件准备结构
	OVERLAPPED overlappedCommEvent;
	
	memset(&overlappedRead, sizeof(overlappedRead), 0 );
	memset(&overlappedCommEvent, sizeof(overlappedCommEvent), 0 );
	
	overlappedRead.hEvent = CreateEvent( NULL, TRUE, TRUE, NULL);
	if (overlappedRead.hEvent == 0)
	{
		PostHangupCall();
		goto EndReadThread;
	}
	
	overlappedCommEvent.hEvent = CreateEvent( NULL, TRUE, TRUE, NULL);
	if(overlappedCommEvent.hEvent == 0)
	{
		PostHangupCall();
		goto EndReadThread;
	}
	
	// 我们将一直侦听以下事件的发生
	HandlesToWaitFor[0] = hCloseEvent;
	HandlesToWaitFor[1] = overlappedCommEvent.hEvent;
	HandlesToWaitFor[2] = overlappedRead.hEvent;
	
	
	// 设置通讯口事件触发的屏蔽码
	if(!SetCommMask(hCommFile, EV_ERR|EV_RLSD|EV_RING))
	{
		PostHangupCall();
		goto EndReadThread;
	}
	
	// 开始侦听串口事件(错误)
	if(!SetupCommEvent( &overlappedCommEvent,  &fdwEvtMask ))
	{
        goto EndReadThread;
	}
	
	// 开始侦听读事件
	if(!SetupReadEvent( &overlappedRead,
		szInputBuffer, INPUTBUFFERSIZE,
		&nNumberOfBytesRead ))
        goto EndReadThread;
	
	// 主循环开始
	while(TRUE)
	{
		// 一直等待直到某些事件的发生(数据到,错误,应用程序停止).
		dwHandleSignaled = WaitForMultipleObjects(3, HandlesToWaitFor,
			FALSE, INFINITE);
		
		switch(dwHandleSignaled)
		{
		case WAIT_OBJECT_0:     // 时间等到,不可能会发生.
			goto EndReadThread;
	
		case WAIT_OBJECT_0 + 1: // 串口事件检测到.
			// 处理串口事件.
#ifdef __RCC_DEBUG__
			DisplayMessage("检测到读事件");
#endif
			if(!HandleCommEvent( &overlappedCommEvent, &fdwEvtMask, TRUE))
				goto EndReadThread;
			
			// 为下一次侦听串口事件做准备.
			if(!SetupCommEvent( &overlappedCommEvent, &fdwEvtMask ))
				goto EndReadThread;
			//{break;??}

		case WAIT_OBJECT_0 + 2: // 读串口事件检测到
			// 得到新的数据!
			if(!HandleReadEvent( &overlappedRead,
				szInputBuffer,
				INPUTBUFFERSIZE,
				&nNumberOfBytesRead ))
				goto EndReadThread;
			
			// 为下一次接收更多的数据做准备.
			if(!SetupReadEvent( &overlappedRead,
				szInputBuffer, INPUTBUFFERSIZE,
				&nNumberOfBytesRead ))
				goto EndReadThread;
			break;
			
		case WAIT_FAILED:       // 等待失败,不会发生.
			PostHangupCall();
			goto EndReadThread;
		default: // 这种情况永远不会发生.
			PostHangupCall();
			goto EndReadThread;
		} //case dwHandleSignaled
	} //while True
	
EndReadThread:
	
	PostHangupCall();
	PurgeComm( hCommFile, PURGE_RXABORT | PURGE_RXCLEAR );
	CloseHandle( overlappedRead.hEvent );
	CloseHandle( overlappedCommEvent.hEvent );
	return 0;
}

//
//  FUNCTION: SetupCommEvent(LPOVERLAPPED, LPDWORD)
//
//  PURPOSE: Sets up the overlapped WaitCommEvent call.
//
//  PARAMETERS:
//    lpOverlappedCommEvent - Pointer to the overlapped structure to use.
//    lpfdwEvtMask          - Pointer to DWORD to received Event data.
//
//  RETURN VALUE:
//    TRUE if able to successfully setup the WaitCommEvent.
//    FALSE if unable to setup WaitCommEvent, unable to handle
//    an existing outstanding event or if the CloseEvent has been signaled.
//
//  COMMENTS:
//
//    This function is a helper function for the Read Thread that sets up
//    the WaitCommEvent so we can deal with comm events (like Comm errors)
//    if they occur.
//
//
BOOL CCommReadThread::SetupCommEvent(LPOVERLAPPED lpOverlappedCommEvent,LPDWORD lpfdwEvtMask)
{
	DWORD dwLastError;
	
StartSetupCommEvent:
	
	// Make sure the CloseEvent hasn't been signaled yet.
	// Check is needed because this function is potentially recursive.
	if (WaitForSingleObject( hCloseEvent,0 )!=WAIT_TIMEOUT)
		return FALSE;
	
	// Start waiting for Comm Errors.
	if(WaitCommEvent( hCommFile, lpfdwEvtMask, lpOverlappedCommEvent))
	{
		// This could happen if there was an error waiting on the
		// comm port.  Lets try and handle it.
		
		if(!HandleCommEvent( NULL, lpfdwEvtMask, FALSE))
		{
			//{??? GetOverlappedResult does not handle "NIL" as defined by Borland}
			return FALSE;
		}
		
		// What could cause infinite recursion at this point?
		goto StartSetupCommEvent;
	}
	
	// We expect ERROR_IO_PENDING returned from WaitCommEvent
	// because we are waiting with an overlapped structure.
	
	dwLastError = GetLastError();
	
	// LastError was ERROR_IO_PENDING, as expected.
	if(dwLastError == ERROR_IO_PENDING)
	{
		return TRUE;
	}
	
	// Its possible for this error to occur if the
	// service provider has closed the port.  Time to end.
	if( dwLastError == ERROR_INVALID_HANDLE)
		return FALSE;
	
	// Unexpected error. No idea what could cause this to happen.
	PostHangupCall();
	return TRUE;
}

//
//  FUNCTION: SetupReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
//  PURPOSE: Sets up an overlapped ReadFile
//
//  PARAMETERS:
//    lpOverlappedRead      - address of overlapped structure to use.
//    lpszInputBuffer       - Buffer to place incoming bytes.
//    dwSizeofBuffer        - size of lpszInputBuffer.
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes.
//
//  RETURN VALUE:
//    TRUE if able to successfully setup the ReadFile.  FALSE if there
//    was a failure setting up or if the CloseEvent object was signaled.
//
//  COMMENTS:
//
//    This function is a helper function for the Read Thread.  This
//    function sets up the overlapped ReadFile so that it can later
//    be waited on (or more appropriatly, so the event in the overlapped
//    structure can be waited upon).  If there is data waiting, it is
//    handled and the next ReadFile is initiated.
//    Another possible reason for returning FALSE is if the comm port
//    is closed by the service provider.
//
//
//
BOOL CCommReadThread::SetupReadEvent(LPOVERLAPPED lpOverlappedRead,LPSTR lpszInputBuffer,
									 DWORD dwSizeOfBuffer,LPDWORD lpnNumberOfBytesRead)
{
	DWORD dwLastError;
	
StartSetupReadEvent:
	
	// Make sure the CloseEvent hasn't been signaled yet.
	// Check is needed because this function is potentially recursive.
	if(WaitForSingleObject(hCloseEvent,0) != WAIT_TIMEOUT)
		return FALSE;
	
	// Start the overlapped ReadFile.
	if (ReadFile( hCommFile,lpszInputBuffer, dwSizeOfBuffer,
		lpnNumberOfBytesRead, lpOverlappedRead ))
	{
		// This would only happen if there was data waiting to be read.
		
		// Handle the data.
		if(!HandleReadData( lpszInputBuffer, *lpnNumberOfBytesRead ))
		{
			return FALSE;
		}
		// Start waiting for more data.
		goto StartSetupReadEvent;
	}   
	   // ReadFile failed.  Expected because of overlapped I/O.
	dwLastError = GetLastError();
			 
	// LastError was ERROR_IO_PENDING, as expected.
	if(dwLastError == ERROR_IO_PENDING)
	{
		return TRUE;
	}
	
	// Its possible for this error to occur if the
	// service provider has closed the port.  Time to end.
	if(dwLastError == ERROR_INVALID_HANDLE)
	{
		return FALSE;
	}
	
	// Unexpected error come here. No idea what could cause this to happen.
	PostHangupCall();
	
	return TRUE;
}

//
//  FUNCTION: HandleCommEvent(LPOVERLAPPED, LPDWORD, BOOL)
//
//  PURPOSE: Handle an outstanding Comm Event.
//
//  PARAMETERS:
//    lpOverlappedCommEvent - Pointer to the overlapped structure to use.
//    lpfdwEvtMask          - Pointer to DWORD to received Event data.
//     fRetrieveEvent       - Flag to signal if the event needs to be
//                            retrieved, or has already been retrieved.
//
//  RETURN VALUE:
//    TRUE if able to handle a Comm Event.
//    FALSE if unable to setup WaitCommEvent, unable to handle
//    an existing outstanding event or if the CloseEvent has been signaled.
//
//  COMMENTS:
//
//    This function is a helper function for the Read Thread that (if
//    fRetrieveEvent == TRUE) retrieves an outstanding CommEvent and
//    deals with it.  The only event that should occur is an EV_ERR event,
//    signalling that there has been an error on the comm port.
//
//    Normally, comm errors would not be put into the normal data stream
//    as this sample is demonstrating.  Putting it in a status bar would
//    be more appropriate for a real application.
//
//
BOOL CCommReadThread::HandleCommEvent(LPOVERLAPPED lpOverlappedCommEvent,
									  LPDWORD lpfdwEvtMask,BOOL fRetrieveEvent)
{
	DWORD dwDummy;
	DWORD dwErrors;
	DWORD dwLastError;
	DWORD dwModemEvent;
	
	// If this fails, it could be because the file was closed (and I/O is
	// finished) or because the overlapped I/O is still in progress.  In
	// either case (or any others) its a bug and return FALSE.
	if(fRetrieveEvent)
	{
		if(!GetOverlappedResult( hCommFile,
			lpOverlappedCommEvent, &dwDummy, FALSE ))
		{
			dwLastError = GetLastError();
			
			// Its possible for this error to occur if the
			// service provider has closed the port.  Time to end.
			if( dwLastError == ERROR_INVALID_HANDLE)
				return FALSE;
			
			PostHangupCall();
			return FALSE;
		}
	}
	
	// Was the event an error?

⌨️ 快捷键说明

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