📄 serialcommlayer.cpp
字号:
// SerialCommLayer.cpp: implementation of the CRCCComm class.
// 本程序于 2007.04.25 ~ 2007.04.27 基本调试完成。
// chenyong 2007.04.27
// 参考自 bhw98 的程序 。若发现bug或有好的建议,请联系:bhw98@sina.com
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SerialPort.h"
#include "SerialCommLayer.h"
#include <io.h>
#include <fcntl.h>
#include <share.h>
#include <sys/stat.h>
#include "sms.h"
extern CListCtrl * lstCtrl;
extern void DisplayMessage(char * msg);
extern void writeToFile(LPSTR filename,LPSTR pDataToWrite, DWORD dwNumberOfBytesToWrite);
extern HANDLE hCommEventArrive;
extern char smsResponseBuf[500];
extern unsigned int smsResponseBuf_length;
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
void writeToFile(LPSTR filename,LPSTR pDataToWrite, DWORD dwNumberOfBytesToWrite)
{
int hLogFile;
if ( (hLogFile = sopen(filename, O_RDWR | O_APPEND | O_CREAT,
SH_DENYNO, S_IREAD | S_IWRITE)) != -1 )
{
char DbgMsg[100];
sprintf(DbgMsg,"接收到字符串[%d]:", dwNumberOfBytesToWrite);
_write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
_write ( hLogFile,"\r\n",2);
for ( unsigned int m=0; m < dwNumberOfBytesToWrite; m++)
{
if(!(m%20))
_write ( hLogFile,"\r\n",2);
sprintf(DbgMsg,"[%X]",(unsigned char)pDataToWrite[m]);
_write ( hLogFile, DbgMsg, strlen ( DbgMsg ) );
}
_write ( hLogFile,"\r\n",2);
_close(hLogFile);
}
}
//(******************************************************************************)
// READ THREAD
//(******************************************************************************)
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::Run
// 用途: 读线程的启动过程.
// 参数: 无
// 返回: 无
// 备注:
// 读线程使用异步读文件方式及将从端口收到的数据发送到应用程序窗口
// 读线程使用POSTMESSAGE发送消息,与应用程序的运行是异步进行的。
// 如果应用程序的关闭事件触发,则读线程退出。
//
int CCommReadThread::Run()
{
char szInputBuffer[INPUTBUFFERSIZE];
DWORD nNumberOfBytesRead;
HANDLE HandlesToWaitFor[2];
DWORD dwHandleSignaled;
// 为异步文件读准备结构
OVERLAPPED overlappedRead;
memset(&overlappedRead, 0, sizeof(overlappedRead));
overlappedRead.hEvent = CreateEvent( NULL, TRUE, TRUE, NULL);
if (overlappedRead.hEvent == 0)
{
goto EndReadThread;
}
HandlesToWaitFor[0] = hCloseEvent;
HandlesToWaitFor[1] = overlappedRead.hEvent;
// 开始侦听读事件
if( !SetupReadEvent(&overlappedRead, szInputBuffer, INPUTBUFFERSIZE,
&nNumberOfBytesRead ))
goto EndReadThread;
while(TRUE)
{
// 一直等待直到某些事件的发生(数据到,错误,应用程序停止).
dwHandleSignaled = WaitForMultipleObjects(2, HandlesToWaitFor,
FALSE, INFINITE);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0: // CloseEvent signaled.
//time to exit.
goto EndReadThread;
case WAIT_OBJECT_0 + 1: // 串口读事件检测到
// 得到新的数据!
if( !HandleReadEvent( &overlappedRead, szInputBuffer,
INPUTBUFFERSIZE, &nNumberOfBytesRead ))
goto EndReadThread;
// 为下一次接收更多的数据做准备.
if( !SetupReadEvent( &overlappedRead, szInputBuffer, INPUTBUFFERSIZE,
&nNumberOfBytesRead ))
goto EndReadThread;
break;
case WAIT_FAILED: // 等待失败,不会发生.
goto EndReadThread;
default: // 这种情况永远不会发生.
goto EndReadThread;
} //case dwHandleSignaled
} //while True
EndReadThread:
PostHangupCall();
PurgeComm( hCommFile, PURGE_RXABORT | PURGE_RXCLEAR );
CloseHandle( overlappedRead.hEvent );
return 0;
}
//
// 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.
dwLastError = GetLastError();
if(dwLastError != ERROR_IO_PENDING)
{
return TRUE;
}
return TRUE;
}
//
// FUNCTION: HandleReadData(LPCSTR, DWORD)
//
// PURPOSE: Deals with data after its been read from the comm file.
//
// PARAMETERS:
// lpszInputBuffer - Buffer to place incoming bytes.
// dwSizeofBuffer - size of lpszInputBuffer.
//
// RETURN VALUE:
// TRUE if able to successfully handle the data.
// FALSE if unable to allocate memory or handle the data.
//
// COMMENTS:
//
// This function is yet another helper function for the Read Thread.
// It LocalAlloc()s a buffer, copies the new data to this buffer and
// calls PostWriteToDisplayCtl to let the EditCtls module deal with
// the data. Its assumed that PostWriteToDisplayCtl posts the message
// rather than dealing with it right away so that the Read Thread
// is free to get right back to waiting for data. Its also assumed
// that the EditCtls module is responsible for LocalFree()ing the
// pointer that is passed on.
BOOL CCommReadThread::HandleReadData(LPCSTR lpszInputBuffer,DWORD dwSizeOfBuffer)
{
LPSTR lpszPostedBytes;
if( dwSizeOfBuffer != 0)
{
// Do something with the bytes read.
lpszPostedBytes = new char[dwSizeOfBuffer+1];
if (lpszPostedBytes == NULL)
{
return FALSE;
}
memcpy((void *)lpszPostedBytes,lpszInputBuffer,dwSizeOfBuffer );
lpszPostedBytes[dwSizeOfBuffer] = 0;
//writeToFile("Log_ReadThread.txt", (char *)lpszInputBuffer, dwSizeOfBuffer);
return ReceiveData( lpszPostedBytes, dwSizeOfBuffer );
}
return FALSE;
}
BOOL CCommReadThread::ReceiveData(LPSTR lpNewString,DWORD dwSizeOfNewString)
{
if( !PostMessage( hComm32Window, PWM_GOTCOMMDATA,
WPARAM(dwSizeOfNewString), LPARAM(lpNewString) ))
{
return FALSE;
}
return TRUE;
}
//
// FUNCTION: HandleReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
// PURPOSE: Retrieves and handles data when there is data ready.
//
// 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 retrieve and handle the available data.
// FALSE if unable to retrieve or handle the data.
//
// COMMENTS:
//
// This function is another helper function for the Read Thread. This
// is the function that is called when there is data available after
// an overlapped ReadFile has been setup. It retrieves the data and
// handles it.
BOOL CCommReadThread::HandleReadEvent(LPOVERLAPPED lpOverlappedRead,LPSTR lpszInputBuffer,
DWORD dwSizeOfBuffer,LPDWORD lpnNumberOfBytesRead)
{
if ( GetOverlappedResult( hCommFile, lpOverlappedRead,
lpnNumberOfBytesRead, TRUE ))
{
return HandleReadData( lpszInputBuffer, *lpnNumberOfBytesRead );
}
return FALSE;
}
void CCommReadThread::PostHangupCall()
{
PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}
//(******************************************************************************)
// WRITE THREAD
//(******************************************************************************)
// CCommWriteThread
IMPLEMENT_DYNCREATE(CCommWriteThread, CWinThread)
CCommWriteThread::CCommWriteThread()
{
hCommFile = NULL;
hCloseEvent = NULL;
hComm32Window = NULL;
}
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()
//
// FUNCTION: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
// PURPOSE: Writes a given string to the comm file handle.
//
// PARAMETERS:
// lpOverlappedWrite - Overlapped structure to use in WriteFile
// pDataToWrite - String to write.
// dwNumberOfBytesToWrite - Length of String to write.
//
// RETURN VALUE:
// TRUE if all bytes were written. False if there was a failure to
// write the whole string.
//
// COMMENTS:
//
// This function is a helper function for the Write Thread. It
// is this call that actually writes a string to the comm file.
// Note that this call blocks and waits for the Write to complete
// or for the CloseEvent object to signal that the thread should end.
// Another possible reason for returning FALSE is if the comm port
// is closed by the service provider.
//
//
BOOL CCommWriteThread::HandleWriteData(LPOVERLAPPED lpOverlappedWrite,
LPSTR pDataToWrite,
DWORD dwNumberOfBytesToWrite)
{
DWORD dwLastError,dwNumberOfBytesWritten,
dwWhereToStartWriting,dwHandleSignaled;
HANDLE HandlesToWaitFor[2];
dwNumberOfBytesWritten = 0;
dwWhereToStartWriting = 0; // Start at the beginning.
HandlesToWaitFor[0] = hCloseEvent;
HandlesToWaitFor[1] = lpOverlappedWrite->hEvent;
// Keep looping until all characters have been written.
do
{
if( !WriteFile( hCommFile,
&(pDataToWrite[ dwWhereToStartWriting ]),
dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
lpOverlappedWrite ))
{
// WriteFile failed. Expected; lets handle it.
dwLastError = GetLastError();
if (dwLastError != ERROR_IO_PENDING)
return FALSE;
// This is the expected ERROR_IO_PENDING case.
// Wait for either overlapped I/O completion,
// or for the CloseEvent to get signaled.
dwHandleSignaled = WaitForMultipleObjects(2, HandlesToWaitFor,
FALSE, INFINITE);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0: // CloseEvent signaled!
// Time to exit.
return FALSE;
case WAIT_OBJECT_0 + 1: // Wait finished.
// Time to get the results of the WriteFile
if(!GetOverlappedResult(hCommFile,
lpOverlappedWrite,
&dwNumberOfBytesWritten, TRUE))
{
return FALSE;
}
break;
case WAIT_FAILED: // Wait failed. Shouldn't happen.
return FALSE;
default: // This case should never occur.
return FALSE;
}//end of case
}// end of WriteFile failure
// Some data was written. Make sure it all got written.
dwNumberOfBytesToWrite -= dwNumberOfBytesWritten;
dwWhereToStartWriting += dwNumberOfBytesWritten;
} while (dwNumberOfBytesToWrite > 0); // Write the whole thing.
// Wrote the whole string.
return TRUE;
}
//
// PROCEDURE: TWriteThread.Execute
//
// PURPOSE: The starting point for the Write thread.
//
// PARAMETERS:
// lpvParam - unused.
//
// RETURN VALUE:
// DWORD - unused.
//
// COMMENTS:
//
// The Write thread uses a PeekMessage loop to wait for a string to write,
// and when it gets one, it writes it to the Comm port. If the CloseEvent
// object is signaled, then it exits. The use of messages to tell the
// Write thread what to write provides a natural desynchronization between
// the UI and the Write thread.
//
//
int CCommWriteThread::Run()
{
// TODO: Add your specialized code here and/or call the base class
MSG msg;
DWORD dwHandleSignaled;
OVERLAPPED overlappedWrite;
BOOL CompleteOneWriteRequire;
memset(&overlappedWrite, 0, sizeof(overlappedWrite));
overlappedWrite.hEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
if(overlappedWrite.hEvent == 0)
goto EndWriteThread;
CompleteOneWriteRequire = TRUE;
// This is the main loop. Loop until we break out.
while(TRUE)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -