개발메모 & 프로그램/개발메모 & 자료
- [MFC 6.0] Comm.cpp
메가아재
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 ) ; }
반응형