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

📄 supersp.cpp

📁 串口开发的另一种方式.rar
💻 CPP
字号:
#include "stdafx.h"
#include "superSP.h"
#include <process.h>


//////////////////////////////////////////////////////////////////////////
// 静态成员

void CSuperSerialPort::SafeRelease(pPACKAGE pPack)
{
	if (NULL != pPack)
	{
		delete pPack;
		pPack = NULL;
	}
}


// 这两个函数被设计成友元目的是可以访问类的私有变量
ULONG WINAPI ReceiveThread(LPVOID pVoid)
{
	long threadStatus;
	DWORD dwMask, dwTrans;
	DWORD dwErrFlag;
	BOOL bExit = false;
	CSuperSerialPort* pCom = (CSuperSerialPort *)pVoid;

//	
//
	while (!bExit)
	{
		threadStatus = 
			WaitForMultipleObjects(CSuperSerialPort::emMAX_EVENT_NUMBER,
			pCom->m_hEvent,
			FALSE,
			INFINITE);
		threadStatus -= WAIT_OBJECT_0;

		if (threadStatus < 0 ||
			threadStatus >= CSuperSerialPort::emMAX_EVENT_NUMBER)
		{
			bExit = true;
			break;
		}

		// 进行事件处理
		switch (threadStatus)
		{
		case CSuperSerialPort::emTHREAD_EXIT:
			bExit = true;
			break;
//
		case CSuperSerialPort::emTHREAD_RUN:
			ClearCommError(pCom->GetComHandle(),
				&dwErrFlag,
				&pCom->m_comState);

			// 缓存队列中有数据
			if (pCom->m_comState.cbInQue)
			{
				pPACKAGE pPack = new PACKAGE;
				DWORD rdLen = pCom->m_comState.cbInQue;
				pPack->iLen   = rdLen;
				
				// 根据长度读取指定字节到包中
				if (ReadFile(pCom->GetComHandle(), 
					pPack->pData,
					pPack->iLen,
					&rdLen,
					&pCom->m_ovReader))
				{
					// 发送包到win消息队列
					pPack->iLen = rdLen;
                    EnterCriticalSection(&pCom->m_csRead);
					pCom->m_ReadCount += pPack->iLen;
					LeaveCriticalSection(&pCom->m_csRead);
					PostPackage(pCom, pPack);
					continue;
				}
			}

			dwMask = 0;
			
			if (!WaitCommEvent(pCom->GetComHandle(),
				&dwMask,
				&pCom->m_ovWaitEvent))
			{
				// GetLastError查找错误
				DWORD errorCode = GetLastError();
				if (errorCode == ERROR_IO_PENDING)
				{
					GetOverlappedResult(pCom->GetComHandle(),
						&pCom->m_ovWaitEvent,
						&dwTrans,
						TRUE);
				}
				else // 非交叠操作,输出错误信息并退出
				{
					LPVOID lpMsg;
					
					FormatMessage(
						FORMAT_MESSAGE_ALLOCATE_BUFFER | 
						FORMAT_MESSAGE_FROM_SYSTEM | 
						FORMAT_MESSAGE_IGNORE_INSERTS,
						NULL,
						errorCode,
						MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
						(LPTSTR)&lpMsg,
						0,
						NULL);
					
					TRACE((LPCTSTR)lpMsg);
					LocalFree(lpMsg);
					bExit = true;
				}
			}	
			
            break;


		default:
			break;
		}
	}
	
	return 0;
}



void PostPackage(CSuperSerialPort* pCom,  pPACKAGE pPack)
{
	if (NULL != pCom)
	{
		if (pCom->GetFileTransferFlag()) 
		{
			pCom->m_pFileWnd->PostMessage(pCom->m_dwDoFileMsg,
				(WPARAM)pPack);
		}
		else
		{
			vWINLIST::iterator it;
			for (it = pCom->m_winList.begin();
			it != pCom->m_winList.end();
			it++)
			{
				it->pWin->PostMessage(it->msg, (WPARAM)pPack);
			}
		}
	}
}




//////////////////////////////////////////////////////////////////////////
// 构造/析构

CSuperSerialPort::CSuperSerialPort()
: m_nextWinId(1),
  m_WriteCount(0),
  m_ReadCount(0),
  m_bIsOpen(false),
  m_bIsTransferFile(false)
{
	InitializeCriticalSection(&m_csWrite);
	InitializeCriticalSection(&m_csRead);
}

CSuperSerialPort::~CSuperSerialPort()
{

	CloseHandle(m_com.comHandle);	
}

//////////////////////////////////////////////////////////////////////////
// 操作控制

//
// Open 函数
//
// 参数: TCHAR* com    串口名
//       UINT rate     波特率
//       UINT parity   校验位
//       BYTE dataBits 数据位
//       UINT stopBits 停止位
//
// 返回值: true 成功, false 失败
//
// 注意: 如果返回失败,请调用GetErrorCode来查找原因
//

BOOL CSuperSerialPort::Open(TCHAR* com,
							UINT rate,
							UINT parity,
							BYTE dataBits,
							float stopBits)
{
	m_errorCode = emET_SUCCEDED;
	COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};

	if (NULL == com)
	{
		m_errorCode = emET_COM_UNNAMED;
		return false;
	}

	strcpy(m_com.com, com);
	m_com.comRate   = rate;
	m_com.comParity = parity;
	m_com.dataBits  = dataBits;
	
	if (stopBits == 1) {
		stopBits = 0;
	} else if (stopBits == 1.5){
        stopBits = 1;
	} else {
		stopBits = 2;
	}

	m_com.stopBits  = stopBits;

	
	// 串口已经打开
	if (m_com.comHandle != INVALID_HANDLE_VALUE)
	{
		m_errorCode = emET_OPENED;
		return FALSE;
	}

	DCB  dcb;
	memset(&dcb, 0, sizeof(dcb));
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate  = m_com.comRate;
	dcb.Parity    = m_com.comParity;
	dcb.fParity   = m_com.comParity & 0; // 0&0 = 0, 1,2 & 0 = 1
	dcb.StopBits  = m_com.stopBits; // 0, 1, 2 = 1, 1.5, 2
	dcb.ByteSize  = m_com.dataBits;

	dcb.fOutxCtsFlow    = 0;
	dcb.fOutxDsrFlow    = 0;
	dcb.fDtrControl     = DTR_CONTROL_DISABLE;
	dcb.fDsrSensitivity = 0;
	dcb.fRtsControl     = RTS_CONTROL_DISABLE;
	dcb.fOutX           = 0;
	dcb.fInX            = 0;
	
	/* ----------------- misc parameters ----- */
	dcb.fErrorChar      = 0;
	dcb.fBinary         = 1;
	dcb.fNull           = 0;
	dcb.fAbortOnError   = 0;
	dcb.wReserved       = 0;
	dcb.XonLim          = 2;
	dcb.XoffLim         = 4;
	dcb.XonChar         = 0x13;
	dcb.XoffChar        = 0x19;
	dcb.EvtChar         = 0;
	
	// 
	m_com.comHandle = CreateFile(m_com.com,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_OVERLAPPED,
		NULL);

	if (m_com.comHandle == INVALID_HANDLE_VALUE)
	{
		m_errorCode = emET_NO_OPEN;
		return false;
	}

	if (SetCommMask(m_com.comHandle, EV_RXCHAR |  EV_BREAK | EV_CTS | EV_RLSD) &&
		SetCommTimeouts(m_com.comHandle, &cto) &&
		SetCommState(m_com.comHandle, &dcb) &&
		SetupComm(m_com.comHandle, 1024, 1024)) // 默认输入输出缓存大小
	{
		m_bIsOpen = true;
		return true;
	}
	else
	{ 
		m_errorCode = emET_UNKNOW;
		return false;
	}
	
}


//
// Close 函数
//

void CSuperSerialPort::Close()
{
	CloseHandle(m_com.comHandle);
	SetEvent(m_hEvent[emTHREAD_EXIT]);
	ResetEvent(m_hEvent[emTHREAD_RUN]);
	m_bIsOpen = false;
	m_com.comHandle = INVALID_HANDLE_VALUE;

	m_ReadCount  = 0;
	m_WriteCount = 0;
}


//
// Attach 函数
//
// 参数: CWnd* pwin  窗口指针
//       DWORD msg   窗口消息
//
// 返回值: 返回一个附加到串口窗口列表的位置
//
// 注意: 窗口的附加Id(2^32)会用完,会导致程序崩溃
//
UINT CSuperSerialPort::Attach(CWnd* pwin, DWORD msg)
{
	if (NULL == pwin)
	{
		return 0;
	}

	WIN_ARG wa;
	wa.winId = m_nextWinId++;
	wa.msg   = msg;
	wa.pWin  = pwin;
	m_winList.push_back(wa);

	return wa.winId;
}


//
// Detach 函数
// 
// 参数: UINT winId  窗口附加时的Id
//

void CSuperSerialPort::Detach(UINT winId)
{
	if (winId == 0 || winId >= m_nextWinId)
	{
		return;
	}

	vWINLIST::iterator it;
	for(it = m_winList.begin();
	    it != m_winList.end();
		it++)
	{
		if (it->winId == winId)
		{
			m_winList.erase(it);
			break;
		}
	}
}



//
// SendData 函数
// 
// 参数: pPACKAGE pPack 要发送的数据包
//
// 返回值: true 发送成, false 发送失败
//

BOOL CSuperSerialPort::SendData(pPACKAGE pPack)
{
	DWORD dwErrFlag;
	COMSTAT comStat;
	m_errorCode = emET_SUCCEDED;

	if (m_com.comHandle == INVALID_HANDLE_VALUE)
	{
		m_errorCode = emET_NO_HANDLE;
		return false;
	}

	ClearCommError(m_com.comHandle, 
		&dwErrFlag,
		&comStat);

    BOOL bl;
	UINT nums = 0;
	UINT reserve = 0;
	
	// 数据过大
    if (pPack->iLen > pPack->emMAX_SIZE)
	{
		nums = pPack->iLen/pPack->emMAX_SIZE;
		reserve = pPack->iLen%pPack->emMAX_SIZE;
    
	
		// 分解传输
		for (int i= 0; i<nums; i++)
		{
			PACKAGE pk;
			pk.iLen = pk.emMAX_SIZE;
			memcpy(pk.pData, 
				pPack->pData+i*pPack->emMAX_SIZE,
				pPack->emMAX_SIZE*sizeof(BYTE));

			bl = WriteComm(&pk);
		}

		// 如果还有剩余的数据
		if (reserve != 0)
		{
			PACKAGE pk;
			pk.iLen = reserve;
			memcpy(pk.pData,
				pPack->pData+nums*pPack->emMAX_SIZE,
				pPack->emMAX_SIZE*sizeof(BYTE));
			bl = WriteComm(&pk);
		}
	}
	else
	{
		bl = WriteComm(pPack);
	}
	
	
	return bl;
} 

BOOL CSuperSerialPort::WriteComm(pPACKAGE pPack)
{
	DWORD wV;
    BOOL bl;

	bl = WriteFile(m_com.comHandle,
		pPack->pData,
		pPack->iLen,
		&wV, 
		&m_ovWriter);
	
	if (!bl)
	{
		if (GetLastError() == ERROR_IO_PENDING)
		{
			bl = GetOverlappedResult(m_com.comHandle,
				&m_ovWriter,
				&wV,
				TRUE);
		}
	}
	
	EnterCriticalSection(&m_csWrite);
	m_WriteCount += pPack->iLen; // 统计
	LeaveCriticalSection(&m_csWrite);

	return bl;
}

//
// StartReceive 函数
//
// 参数: LPVOID arg 传入对象,主要包含串口对象
//
// 返回值:  true 启动成功, false 启动失败
//
// 注意: 传入的参数必须包含串口对象, 否则不能接收数据
//

BOOL CSuperSerialPort::StartReceive(LPVOID arg)
{
	m_errorCode = emET_SUCCEDED;

	if (NULL == arg)
	{
		m_errorCode = emET_NO_HANDLE;
		return false;
	}

	// 创建事件
	m_hEvent[emTHREAD_EXIT] = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hEvent[emTHREAD_RUN]  = CreateEvent(NULL, TRUE, TRUE, NULL);
	
	m_hReader               = CreateEvent(NULL, TRUE, FALSE, NULL);
	ZeroMemory(&m_ovReader, sizeof(m_ovReader));
	m_ovReader.hEvent       = m_hReader;

	m_hWriter               = CreateEvent(NULL, TRUE, FALSE, NULL);
	ZeroMemory(&m_ovWriter, sizeof(m_ovWriter));
	m_ovWriter.hEvent       = m_hWriter;
	
	m_hWait                 = CreateEvent(NULL, TRUE, FALSE, NULL);
	ZeroMemory(&m_ovWaitEvent, sizeof(m_ovWaitEvent));
	m_ovWaitEvent.hEvent    = m_hWait;
	
	
	m_hReceiveThread = CreateThread(NULL,
		0,
		ReceiveThread,
		arg,
		0,
		&m_threadId);
	if (m_hReceiveThread != NULL)
	{
		SetThreadPriority(m_hReceiveThread,
			THREAD_PRIORITY_BELOW_NORMAL);
	    return true;
	}
	else
	{
		return false;
	}
}


//////////////////////////////////////////////////////////////////////////
// 类属性

COMSTAT* CSuperSerialPort::GetComState()
{
	return &m_comState;
}

HANDLE CSuperSerialPort::GetComHandle()
{
	return m_com.comHandle; 
}

void CSuperSerialPort::SetInOutBuffer(DWORD inBuf, DWORD outBuf)
{
	SetupComm(m_com.comHandle, inBuf, outBuf);
}

DWORD CSuperSerialPort::GetErrorCode()
{
	return m_errorCode;
}

ULONG CSuperSerialPort::GetWritedBytes()
{
	ULONG tmp;
    EnterCriticalSection(&m_csWrite);
	tmp = m_WriteCount;
    LeaveCriticalSection(&m_csWrite);

	return tmp;
}

ULONG CSuperSerialPort::GetReadedBytes()
{
	ULONG  tmp;
	EnterCriticalSection(&m_csRead);
	tmp = m_ReadCount;
	LeaveCriticalSection(&m_csRead);

	return tmp;
}

#ifdef VERSION1_1 // v1.1版本被编译

BOOL CSuperSerialPort::GetFileTransferFlag() const
{
	return m_bIsTransferFile;
}

void CSuperSerialPort::OpenFileTransfer(CWnd* pwin,
									    DWORD msg)
{
	m_bIsTransferFile = true;
	m_pFileWnd        = pwin;
	m_dwDoFileMsg     = msg;
}

void CSuperSerialPort::CloseFileTransfer()
{
	m_bIsTransferFile = false;
	m_pFileWnd        = NULL;
	m_dwDoFileMsg     = 0;
}

#endif

//////////////////////////////////////////////////////////////////////////

// 注意该函数
const TCHAR* CSuperSerialPort::FormatErrorCodeToString(DWORD code)
{
	switch(code)
	{
	case emET_SUCCEDED:
		sprintf(m_errorInfo, _T("操作成功!"));
		break;

	case emET_NO_OPEN:
		sprintf(m_errorInfo, _T("串口没打开或被其他程序打开"));
		break;

	case emET_NO_HANDLE:
		sprintf(m_errorInfo, _T("串口没有句柄"));
		break;

	case emET_OPENED:
		sprintf(m_errorInfo, _T("串口已经打开过"));
		break;

	case emET_COM_UNNAMED:
		sprintf(m_errorInfo, _T("串口没命名"));
		break;
		
	default:
		sprintf(m_errorInfo,
			_T("未定义的错误,请调用系统的GetLastError来查找"));
		break;
	}

	return m_errorInfo;
}

⌨️ 快捷键说明

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