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

📄 serialex.cpp

📁 Alphanumeric messages are encoded in POCSAG format and send to the serial port of a computer. The mo
💻 CPP
字号:
//	SerialEx.cpp - Implementation of the CSerialEx class
//
//	Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


//////////////////////////////////////////////////////////////////////
// Include the standard header files
#define STRICT
#include <crtdbg.h>
#include <tchar.h>
#include <windows.h>


//////////////////////////////////////////////////////////////////////
// Include module headerfile

#include "SerialEx.h"


//////////////////////////////////////////////////////////////////////
// Disable warning C4127: conditional expression is constant, which
// is generated when using the _RPTF and _ASSERTE macros.

#pragma warning(disable: 4127)


//////////////////////////////////////////////////////////////////////
// Enable debug memory manager

#ifdef _DEBUG

#ifdef THIS_FILE
#undef THIS_FILE
#endif

static const char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW

#endif


//////////////////////////////////////////////////////////////////////
// Code

CSerialEx::CSerialEx()
	: m_fStopping(false)
	, m_hThread(0)
#ifndef SERIAL_NO_OVERLAPPED
	, m_hevtOverlappedWorkerThread(0)
#endif
{
}

CSerialEx::~CSerialEx()
{
	// Check if the thread handle is still there. If so, then we
	// didn't close the serial port. We cannot depend on the
	// CSerial destructor, because if it calls Close then it
	// won't call our overridden Close.
	if (m_hThread)
	{
		// Display a warning
		_RPTF0(_CRT_WARN, "CSerialEx::~CSerialEx - Serial port not closed\n");

		// Close implicitly
		Close();
	}
}

LONG CSerialEx::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fStartListener)
{
	// Call the base class first
	long lLastError = CSerial::Open(lpszDevice,dwInQueue,dwOutQueue,SERIAL_DEFAULT_OVERLAPPED);
	if (lLastError != ERROR_SUCCESS)
		return lLastError;

#ifndef SERIAL_NO_OVERLAPPED
	// Create an event that is used for the workerthread. The globally
	// used event is used by the main-thread and cannot be reused
	// for this thread.
	m_hevtOverlappedWorkerThread = ::CreateEvent(0,true,false,0);
	if (m_hevtOverlappedWorkerThread == 0)
	{
		// Obtain the error information
		m_lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN,"CSerialEx::Open - Unable to create event\n");

		// Close the serial port again
		CSerial::Close();

		// Return the error
		return m_lLastError;
	}
#endif


	// Start the listener thread (only on request)
	if (fStartListener)
	{
		lLastError = StartListener();
		if (lLastError != ERROR_SUCCESS)
			return lLastError;
	}

	// Return the error
	return m_lLastError;
}

LONG CSerialEx::Close (void)
{
	// Stop listener thread (wait until it ends)
	StopListener(INFINITE);

#ifndef SERIAL_NO_OVERLAPPED
	// Free event handle
	if (m_hevtOverlappedWorkerThread)
	{
		::CloseHandle(m_hevtOverlappedWorkerThread);
		m_hevtOverlappedWorkerThread = 0;

	}
#endif

	// Call the base class
	return CSerial::Close();
}

LONG CSerialEx::StartListener (void)
{
	// Check if the watcher thread was already running
	if (m_hThread == 0)
	{
		// Make sure the thread has stopped
		_ASSERTE(!m_fStopping);

		// Start the watcher thread
		DWORD dwThreadId = 0;
		m_hThread = ::CreateThread(0,0,ThreadProc,LPVOID(this),0,&dwThreadId);
		if (m_hThread == 0)
		{
			// Display a warning
			_RPTF0(_CRT_WARN, "CSerialEx::StartListener - Unable to start COMM watcher thread\n");

			// Set the error code and exit
			m_lLastError = ::GetLastError();
			return m_lLastError;
		}
	}

	// Return the error
	m_lLastError = ERROR_SUCCESS;
	return m_lLastError;
}

LONG CSerialEx::StopListener (DWORD dwTimeout)
{
	// Check if the thread is running
	if (m_hThread)
	{
		// Set the flag that the thread must be stopped
		m_fStopping = true;

		// Cancel the pending WaitEvent, but we won't do this using
		// CancelIo. This would break Win95 compatibility and some
		// USB serial dongles cannot handle CancelIo correctly. By
		// setting the event mask again, the call will also be
		// completed before the thread exits.
		SetMask(GetEventMask());
		
		// Wait until the watcher thread has stopped
		::WaitForSingleObject(m_hThread,dwTimeout);

		// The thread has stopped
		m_fStopping = false;

		// Close handle to the thread
		::CloseHandle(m_hThread);
		m_hThread = 0;
	}

	// Return the error
	m_lLastError = ERROR_SUCCESS;
	return m_lLastError;
}

DWORD WINAPI CSerialEx::ThreadProc (LPVOID lpArg)
{
	// Route the method to the actual object
	CSerialEx* pThis = reinterpret_cast<CSerialEx*>(lpArg);
	return pThis->ThreadProc();
}

DWORD CSerialEx::ThreadProc (void)
{
	// Use overlapped structure
	LPOVERLAPPED lpOverlapped = 0;

	// Keep looping
	do
	{
#ifndef SERIAL_NO_OVERLAPPED
		// Reset the event handle
		::ResetEvent(m_hevtOverlappedWorkerThread);

		// Initialize the overlapped structure
		OVERLAPPED ovInternal = {0};
		ovInternal.hEvent = m_hevtOverlappedWorkerThread;

		// Start the WaitEvent (use our own overlapped structure)
		if (WaitEvent(&ovInternal) != ERROR_SUCCESS)
			return m_lLastError;

		// Wait for the overlapped operation to complete
		if (::WaitForSingleObject(m_hevtOverlappedWorkerThread,INFINITE) != WAIT_OBJECT_0)
		{
			// Set the internal error code
			m_lLastError = ::GetLastError();

			// Issue an error and quit
			_RPTF0(_CRT_WARN,"CSerialEx::ThreadProc - Unable to wait until COM event has arrived\n");
			return m_lLastError;
		}
#else
		// Start the WaitEvent (don't need to specify an overlapped structure)
		if (WaitEvent() != ERROR_SUCCESS)
			return m_lLastError;
#endif

		// Wait until one of the events happens
		if (!m_fStopping)
		{
			// Determine the event
			EEvent eEvent = GetEventType();

			// Obtain the error status during this event
			DWORD dwErrors = 0;
			if (!::ClearCommError(m_hFile,&dwErrors,0))
			{
				// Set the internal error code
				m_lLastError = ::GetLastError();

				// Issue an error and quit
				_RPTF0(_CRT_WARN, "CSerialEx::ThreadProc - Unable to obtain COM status\n");
			}

			// Convert the error
			EError eError = EError(dwErrors);

			// There was a COMM event, which needs handling. We'll call the
			// event handler. We can receive a "zero" event, when the
			// mask or event character has been set. We won't pass this
			// down to the window.
			if (eEvent)
				OnEvent(eEvent,eError);
		}
	}
	while (!m_fStopping);

	// Bye bye
	return 0;
}

⌨️ 快捷键说明

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