메가아재 2016. 2. 29. 05:02
반응형
//Comm.cpp Rs232c 통신을 하기 위한 클래스 
#include "stdafx.h" 
#include "Comm.h" 

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

IMPLEMENT_DYNCREATE(CComm, CObject) 

//////////////////////////////
extern HWND				mhwnd_1;
//////////////////////////////



CComm::CComm( ) 
{ 
idComDev=NULL; 
bFlowCtrl= FC_XONXOFF ; 
fConnected = FALSE ; 
} 

CComm::~CComm( ) 
{ 
DestroyComm(); 
} 

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


///////////////////////////////////////////////////////////////////////////// 
// CComm message handlers 
//CommWatchProc() 
//통신을 하는 프로시저, 즉 데이터가 들어왔을 때 감시하는 
//루틴. 본 루틴은 OpenComPort 함수 실행시 프로시저로 연결됨. 
//OpenComPort 함수 참조 
DWORD CommWatchProc(LPVOID lpData) 
{ 
DWORD dwEvtMask ; 
OVERLAPPED os ; 
CComm* npComm = (CComm*) lpData ; 
char InData[MAXBLOCK + 1]; 
int nLength ; 
//idCommDev라는 핸들에 아무런 컴포트가 안 붙어 있으면 
//에러 리턴 
if ( npComm == NULL || 
!npComm->IsKindOf( RUNTIME_CLASS( CComm ) ) ) 
return (DWORD)(-1); 

memset( &os, 0, sizeof( OVERLAPPED ) ) ; 


os.hEvent = CreateEvent( NULL, // no security 
TRUE, // explicit reset req 
FALSE, // initial event reset 

NULL ) ; // no name 
if ( os.hEvent == NULL ) 
{ 
MessageBox( NULL, "Failed to create event for thread!", "comm Error!", 
MB_ICONEXCLAMATION | MB_OK ) ; 
return ( FALSE ) ; 
} 

if (!SetCommMask(npComm->idComDev, EV_RXCHAR )) 
return ( FALSE ) ; 

//////////////////////////////////////////////////////
EscapeCommFunction(npComm->idComDev,SETRTS);
//////////////////////////////////////////////////////

while (npComm->fConnected ) 
{ 
dwEvtMask = 0 ; 

WaitCommEvent(npComm->idComDev, &dwEvtMask, NULL ); 

if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) 
{ 

do 
{ 
memset(InData,0,80); 
if (nLength = npComm->ReadCommBlock((LPSTR) InData, MAXBLOCK )) 
{ 
npComm->SetReadData(InData); 
//이곳에서 데이터를 받는다. 
} 

///////////////////////////////////////////////////////
	else if( (dwEvtMask & EV_TXEMPTY)==EV_TXEMPTY )
	{
		Sleep(35);

		EscapeCommFunction(npComm->idComDev, SETRTS);
		// 다 보내면 RTS HIGH
	}

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

} 
while ( nLength > 0 ) ; 
} 
} 


CloseHandle( os.hEvent ) ; 


return( TRUE ) ; 

} 
//데이터를 읽고 데이터를 읽었다는 
//메시지를 리턴한다. 
void CComm::SetReadData(LPSTR data) 
{ 

lstrcpy((LPSTR)abIn,(LPSTR)data); 
//ConverData 
//설정된 윈도에 WM_RECEIVEDATA 메시지를 
//날려 주어 현재 데이터가 들어왔다는 것을 
//알려준다. 
SendMessage(m_hwnd,WM_RECEIVEDATA,0,0); 
} 
//메시지를 전달할 hwnd 설정 
void CComm::SetHwnd(HWND hwnd) 
{ 
m_hwnd=hwnd; 
} 
//컴포트를 설정한다. 
void CComm::SetComPort(int port,DWORD rate,BYTE bytesize,BYTE stop,BYTE parity) 
{ 
bPort=port; 
dwBaudRate=rate; 
bByteSize=bytesize; 
bStopBits=stop; 
bParity=parity; 
} 
//XonOff, 즉 리턴값 더블 설정 
void CComm::SetXonOff(BOOL chk) 
{ 
fXonXoff=chk; 
} 
void CComm::SetDtrRts(BYTE chk) 
{ 
bFlowCtrl=chk; 
} 
//컴포트 정보를 만든다. 
//이것을 만들 때 이전에 
// SetComPort(); -> SetXonOff() ->SetDtrRts()한 다음 설정한다. 
BOOL CComm::CreateCommInfo() 
{ 


osWrite.Offset = 0 ; 
osWrite.OffsetHigh = 0 ; 
osRead.Offset = 0 ; 
osRead.OffsetHigh = 0 ; 

//이벤트 창구 설정 

osRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ; 
if (osRead.hEvent == NULL) 
{ 
return FALSE ; 
} 
osWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ; 
if (NULL == osWrite.hEvent) 
{ 
CloseHandle( osRead.hEvent ) ; 
return FALSE; 
} 


return TRUE ; 

} 

//컴포트를 열고 연결을 시도한다. 
//OpenComport() 
BOOL CComm::OpenComPort( ) 
{ 
char szPort[ 15 ] ; 
BOOL fRetVal ; 
COMMTIMEOUTS CommTimeOuts ; 


if (bPort > MAXPORTS) 
lstrcpy( szPort, "\\.\TELNET" ) ; 
else 
wsprintf( szPort, "COM%d", bPort ) ; 

// COMM device를 파일 형식으로 연결한다. 

if ((idComDev = 
CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 
0, // exclusive access 
NULL, // no security attrs 
OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL | 
FILE_FLAG_OVERLAPPED, // overlapped I/O 
NULL )) == (HANDLE) -1 ) 
return ( FALSE ) ; 
else 
{ 

//컴포트에서 데이터를 교환하는 방법을 char 단위를 기본으로 설정 
//하자. 
SetCommMask( idComDev, EV_RXCHAR ) ; 
SetupComm( idComDev, 4096, 4096 ) ; 
//디바이스에 쓰레기가 있을지 모르니까 깨끗이 청소를 하자. 
PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT | 
PURGE_TXCLEAR | PURGE_RXCLEAR ) ; 


CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ; 
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; 
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ; 
CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; 
CommTimeOuts.WriteTotalTimeoutConstant = 1000 ; 
SetCommTimeouts( idComDev, &CommTimeOuts ) ; 
} 

fRetVal = SetupConnection() ; 

if (fRetVal)//연결이 되었다면 fRetVal TRUE이므로 
{ 
fConnected = TRUE ;//연결되었다고 말해 줌. 
//프로시저를 CommWatchProc에 연결하니까 나중에 데이터가 왔다갔다 
//하면 모든 내용은 CommWatchProc가 담당한다. 
AfxBeginThread((AFX_THREADPROC)CommWatchProc,(LPVOID)this); 
} 
else 
{ 
fConnected = FALSE ; 
CloseHandle( idComDev) ; 
} 

return ( fRetVal ) ; 

} 

//파일로 설정된 컴포트와 실질 포트를 연결시킨다. 
//SetupConnection 이전에 CreateComPort를 해주어야 한다. 
BOOL CComm::SetupConnection() 
{ 
BOOL fRetVal ; 
BYTE bSet ; 
DCB dcb ; 


dcb.DCBlength = sizeof( DCB ) ; 

GetCommState( idComDev, &dcb ) ;//dcb의 기본값을 받는다. 


//이 부분을 수정해야 한다. 
dcb.BaudRate = dwBaudRate;//전송 속도 
dcb.ByteSize = bByteSize ;//데이터 비트 
dcb.Parity = bParity;//패리티 체크 
dcb.StopBits = bStopBits;//스톱 비트 

dcb.fOutxDsrFlow =0 ;//Dsr Flow 
dcb.fDtrControl = DTR_CONTROL_ENABLE ;//Dtr Control 
dcb.fOutxCtsFlow = 0 ;//Cts Flow 
dcb.fRtsControl = RTS_CONTROL_ENABLE ; //Ctr Control 
dcb.fInX = dcb.fOutX = 1 ; //XON/XOFF 관한 것 
dcb.XonChar = ASCII_XON ; 
dcb.XoffChar = ASCII_XOFF ; 
dcb.XonLim = 100 ; 
dcb.XoffLim = 100 ; 
dcb.fBinary = TRUE ; 
dcb.fParity = TRUE ; 



dcb.fBinary = TRUE ; 
dcb.fParity = TRUE ; 

fRetVal = SetCommState( idComDev, &dcb ) ; //변경된 Dcb 설정 

return ( fRetVal ) ; 

} 

//컴포트로부터 데이터를 읽는다. 
int CComm::ReadCommBlock(LPSTR lpszBlock, int nMaxLength ) 
{ 
BOOL fReadStat ; 
COMSTAT ComStat ; 
DWORD dwErrorFlags; 
DWORD dwLength; 

// only try to read number of bytes in queue 
ClearCommError( idComDev, &dwErrorFlags, &ComStat ) ; 

dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue ) ; 

if (dwLength > 0) 
{ 
fReadStat = ReadFile( idComDev, lpszBlock, 
dwLength, &dwLength, &osRead ) ; 
if (!fReadStat) 
{ 
//이곳에 에러를 넣다. 
//즉 ReadFile했을 때 데이터가 제대로 안 나오면 fReadState에 여러 
//에러 코드를 리턴한다. 이 때 복구할 수 있으면 좋지만 실질적인 
//복구가 불가능하다. 따라서, 재송출을 해달라는 메시지를 해주는 것이 
//좋다. 
} 
} 

return ( dwLength ) ; 

} 
//컴포트를 완전히 해제한다. 

BOOL CComm::DestroyComm() 
{ 


if (fConnected) 
CloseConnection( ) ; 


CloseHandle( osRead.hEvent ) ; 
CloseHandle( osWrite.hEvent ) ; 

return ( TRUE ) ; 

} 

//연결을 닫는다. 
BOOL CComm::CloseConnection() 
{ 

// set connected flag to FALSE 

fConnected = FALSE ; 


// disable event notification and wait for thread 
// to halt 

SetCommMask( idComDev, 0 ) ; 



EscapeCommFunction( idComDev, CLRDTR ) ; 


PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT | 
PURGE_TXCLEAR | PURGE_RXCLEAR ) ; 
CloseHandle( idComDev ) ; 
return ( TRUE ) ; 

} 



BOOL CComm::WriteCommBlock(LPBYTE lpByte , DWORD dwBytesToWrite) //수정
{ 

BOOL fWriteStat ; 
DWORD dwBytesWritten ; 

fWriteStat = WriteFile( idComDev, lpByte, dwBytesToWrite, 
&dwBytesWritten, &osWrite ) ; 

///////////////////////////////////////////////////////////////
EscapeCommFunction(idComDev, CLRRTS);
///////////////////////////////////////////////////////////////

if (!fWriteStat) 
{ 
//컴포트에 데이터를 제대로 써넣지 못했을 경우이다. 
//이 때는 어떻게 할까. 그것은 사용자 마음이다. 
//다시 보내고 싶으면 재귀송출을 하면 된다. 
//그러나 무한 루프를 돌 수 있다는 점을 주의하자. 
} 
return ( TRUE ) ; 

} 

반응형