BACKRUSH  대화방입장  유닉스명령  다음  자료실  Ascii Table   Exploit   원격접속  달력,시간   프로세스  
지하철노선   Whois   RFC문서   SUN FAQ   SUN FAQ1   C메뉴얼   PHP메뉴얼   너구리   아스키월드 아이피서치

글쓴이: serial SerialPort.cpp [시리얼통신] 조회수: 8691


// SerialPort.cpp : implementation file
//

#include "stdafx.h"
#include "CraneControl.h"
#include "SerialPort.h"


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

/////////////////////////////////////////////////////////////////////////////
// CSerialPort

CSerialPort::CSerialPort()
{
m_hComm = NULL;
m_bThreadAlive = FALSE;
m_Thread = NULL;
m_ovrWrite.Offset = 0;
m_ovrWrite.OffsetHigh = 0;
m_osRead.Offset = 0;
m_ovrWrite.OffsetHigh = 0;
m_strComErrMsg =_T(""); //에러 리포트 ..초기 실행시 비우고
}

CSerialPort::~CSerialPort()
{
ClosePort();
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CSerialPort, CObject)
//{{AFX_MSG_MAP(CSerialPort)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0

/////////////////////////////////////////////////////////////////////////////
// CSerialPort member functions
BOOL CSerialPort::OpenPort(CWnd* pPortOwner, LPTTYSTRUCT lpTTY)
{
BOOL bResult = FALSE;
char szPort[8]; //
DCB dcb; //장치 제어 블록 구조체 (Device-Control Block, DCB)
COMMTIMEOUTS cto; //타임아웃값 설정
CString sMessage; //에러 메시지

m_pOwner = pPortOwner;
m_nPortNr = lpTTY->byCommPort; //접속 port 설정

//시리얼 포트의 상태를 받기위해 이벤트 개체를 이용한 스레드간의 동기화
//포토를 열기위한 전처리
m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(m_osRead.hEvent == NULL)
{
AfxMessageBox("m_osRead.hEvent Error");
return FALSE;
}

m_ovrWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if(m_ovrWrite.hEvent == NULL)
{
AfxMessageBox("m_ovrWrite.hEvent Error");
return FALSE;
}

sprintf(szPort, "COM%d", m_nPortNr); //버퍼 오버플로우 보호를 위한 함수인데 여기에서는
//commport가 지정된다

//포트 디바이스를 연다
m_hComm = CreateFile(szPort, // 'COM1 or COM2...'communication port string (COMX)
GENERIC_READ | GENERIC_WRITE, // 일고쓰기지정...억세스 모드
0, // 다른프로그램과의 공유모드
NULL, // 보안정보 (보안안함)
OPEN_EXISTING, // 기존의 파일을 연다..comm devices 생성방법
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //파일 플래그와 속성
NULL); // 템플레이트 파일 필요없음..template must be 0 for comm devices


if (m_hComm == INVALID_HANDLE_VALUE)
{
m_strComErrMsg = "Can't Create Device port ";
m_hComm = NULL;
return FALSE;
}


ZERO_MEMORY(dcb); //RS-232c장치 제어 블록 구조체를 초기화
dcb.DCBlength = sizeof(DCB); //DCB 크기 비교
if (!GetCommState(m_hComm, &dcb)) //DCB초기화
return FALSE;

dcb.BaudRate = lpTTY->dwBaudRate; // DCB구조체의 크기
dcb.Parity = lpTTY->byParity; //CTS 지정 플러그 1이면 CTS가 1이 될 때까지 기다린다.
dcb.ByteSize = lpTTY->byByteSize; //number of bits/byte, 4-8 포트에 의해 현재 사용되는 데이터 비트수
dcb.StopBits = lpTTY->byStopBits; //정지 비트:포트에 의해 현재 사용되는 데이터 비트수

dcb.fOutxCtsFlow = 0; //CTS 지정 플러그 1이면 CTS가 1이 될 때까지 기다린다.
dcb.fOutxDsrFlow = 0; //DSR 지정 플러그 1이면 DSR이 1이 될 때 까지 기다린다.
//if(m_nPortNr == 7)
//{
// dcb.fDtrControl = DTR_CONTROL_DISABLE; //DTR 지정 플러그 DTR_CONTROL_DISBLE로 설정시 DTR이 OFF되고
//DTR_CONTROL_ENABLE 를 설정하면 DTR은 ON이된다.
// dcb.fRtsControl = RTS_CONTROL_DISABLE; //RTS는 이값이 RTS_CONTROL_DISABLE로 설정시 0이되고
// RTS_CONTROL_ENABLE로 설정될 때 ON이 된다.
//}


dcb.fOutX = 0; // 이값이 1이면 XoffChar문자 수신시 중단
// XON/XOFF out flow control
dcb.fInX = 0; // 이값이 1이면 XoffChar문자는 수신 버퍼가 XoffLim바이트
// 안에 있을 경우 보내지고 XonChar 무자는 XonLim안에 있을 때
// 보내진다.
dcb.fBinary = TRUE; // binary mode설정 1로 설정하면 binary mode가능
dcb.fParity = TRUE; // 패리티 검사 기능 유무 .. enable parity check
dcb.XonChar = ASCII_XON;
dcb.XoffChar = ASCII_XOFF;
dcb.XonLim = 100;
dcb.XoffLim = 100;

if (!SetCommState(m_hComm, &dcb)) //DCB를 포토에 연결
{
CloseHandle(m_hComm);
return FALSE;
}


//타임 아웃값 설정
cto.ReadIntervalTimeout = 100;
cto.ReadTotalTimeoutConstant = 100;
cto.ReadTotalTimeoutMultiplier = 100;

if (!SetCommTimeouts(m_hComm, &cto)) //수신과 송신의 시간을 설정
return FALSE;

//통신포토로 통해 문자가 수신되었다는 것을 마스크로 설정
if (!SetCommMask(m_hComm, EV_RXCHAR))
return FALSE;

//버퍼를 모두 깨끗하게 청소해 놓고 또한 포트 디바이스를 초기화
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

m_bThreadAlive = FALSE;
return TRUE;
}




void CSerialPort::ClosePort()
{
if (m_Thread != NULL)
{
DWORD dwSuspendCount;
do
{
dwSuspendCount = m_Thread->ResumeThread();
}
while((dwSuspendCount != 0) && (dwSuspendCount != 0xffffffff));
}

m_bThreadAlive = FALSE; //스레드 해제

//컴포트 닫기
if (m_hComm != NULL)
CloseHandle(m_hComm);
//데이터 구조체 해제
if(m_ovrWrite.hEvent!= NULL )
{
CloseHandle(m_ovrWrite.hEvent);
CloseHandle(m_osRead.hEvent);
}

m_hComm = NULL;
m_ovrWrite.hEvent = NULL;
m_osRead.hEvent = NULL;

}

//쓰레드 생성
BOOL CSerialPort::StartMonitoring()
{
if (!(m_Thread = AfxBeginThread(CommThread, this)))
{
m_strComErrMsg += "Thread Start Error";
//MessageBox(NULL,"Thread Start Error",NULL,MB_OK);
return FALSE;
}

m_bThreadAlive = TRUE;

return TRUE;
}


//thread의 재시작
BOOL CSerialPort::RestartMonitoring()
{
if (m_Thread)
m_Thread->ResumeThread();
return TRUE;
}


// thread의 대기
BOOL CSerialPort::StopMonitoring()
{
if (m_Thread)
m_Thread->SuspendThread();
return TRUE;
}





UINT CSerialPort::CommThread(LPVOID pParam)
{
DWORD dwEvent = 0;
DWORD dwError = 0;
BOOL bResult = TRUE;
CSerialPort *port = NULL;

BYTE buff[256]; //---- 읽기 버퍼
DWORD dwRead; //
//스레드를 off하기위해 0으로 셋팅
//ReadComm()함수에서 버퍼의 데이터를 다 읽지 못하면 0이 아닌 다른값이 있다.


port = (CSerialPort*)pParam;
//port->m_bThreadAlive = TRUE;

//시리얼포트의 포트 디바이스가 연결되어있다면
//버퍼를 모두 깨끗하게 청소해 놓고 또한 포트 디바이스를 초기화
if (port->m_hComm)
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);


while(port->m_bThreadAlive) //쓰레드가 활성화되어 있을동안
{
dwEvent = 0;

//함수의 2번째 인자는 OVERLAPPED구조체 이다. 보통 통신을 할 경우 동기화를 하기
//때문에 이구조체를 사용하지 않고 NULL로 설정
//WaitCommEvent(port->m_hComm, &dwEvent,NULL); //문자가 들어오기를 기다림
//WaitCommEvent( port->m_hComm, &dwEvent,&port->m_ovrWrite);

//if ((dwEvent & EV_RXCHAR) == EV_RXCHAR) //문자열이 들어왔을 때 수행하는 내용
//{
do
{
dwRead = port->ReadComm(buff, 256);
if (dwRead > 0)
port->ProcessRcvData(port, buff, (BYTE)dwRead );
else
Sleep(90); //100이 되면 실행 중 에러남
} while (dwRead);
//}
}

return 0;
}

DWORD CSerialPort::ReadComm(BYTE *pBuff, DWORD nToRead)
{
DWORD dwRead, dwError, dwErrorFlags;

COMSTAT comstat; //통신 장치의 정보를 담고있는 구조체

//버퍼에 남아있는 바이트의 수를 파악하여 한번에 읽어들이는 작업을 한다.
//이 방법은 매우 복잡한 버퍼 관리를 요구하지만
//엄청나게 많은 데이터가 수신된 것을 읽어들이는 횟수를 한번으로 줄여준다.
ClearCommError( m_hComm, &dwErrorFlags, &comstat);

dwRead = comstat.cbInQue; // bytes in input buffer

//버퍼에 데이터가 있다면
if(dwRead > 0)
{
//데이터 읽기
//데이터를 읽는 것은 위의 데이터를 쓰는 함수와 비슷다. 함수명은 ReadFile입니다.
//첫번째 인자는 파일 핸들러이고,
//두 번째 인자는 써야 할 데이터,
//세 번째 인자는 써야 할 바이트의 수,
//네 번째 인자는 써야 할 바이트수가 들어 있는 번지,
//다섯 번째 인자는 위에서 만든 overWrite입니다.
if( !ReadFile( m_hComm, pBuff, nToRead, &dwRead, &m_osRead) )//오버랩대신 NULL로 하면 통신 안됨
{
//데이터가 남아있다면
if (GetLastError() == ERROR_IO_PENDING)
{
/*timeouts에 정해준 시간만큼 기다려준다.
GetOverlappedResult가 작업의 결과를 레포트 해준다.
만약오류가 발생하였다면 GetOverlappedResult는 FALSE를 돌려주고
GetLastError가 오류 코드를 되돌려 준다.
만약 작업이 성공적으로 끝났다면 GetOverlappedResult는 TRUE를 돌려준다.
주의 : GetOverlappedResult는 작업이 종료되었는지 실패된 상태인지를 알수 있다.
GetOverlappedResult가 FALSE를 돌려주고
GetLastError가 ERROR_IO_INCOMPLETE이면 그 작업은 종료된 것이 아니다.
또한 GetOverlappedResult는 작업이 종료될 때까지 붙잡을 수 있다.
bWait파라미터와 같은 것에 TRUE를 넘겨 줌으로써 오버렙과 논오버렙을 전환할 수 있다. */

while (! GetOverlappedResult( m_hComm, &m_osRead, &dwRead, TRUE))
{
dwError = GetLastError();

if (dwError != ERROR_IO_INCOMPLETE) //작업이 종료되면
{
ClearCommError( m_hComm, &dwErrorFlags, &comstat); //데이타 읽고
break;
} //End of four if

} //End of first while

}//End of third if
else //데이터가 없다면
{
dwRead = 0;
ClearCommError( m_hComm, &dwErrorFlags, &comstat);
}//third if for end of else
} //end of second if
} //End of firat if
//--> 실제 읽어들인 갯수를 리턴.
return dwRead;
}

void CSerialPort::ProcessRcvData(CSerialPort* port, BYTE *byBuf, int nSize)
{
if( !nSize ){return;} //데이타가 없으면

memset(m_strData, NULL, 32);

for( int i=0; i<nSize; i++ ) //포트로받은 데이터를 전역배열에 저장
m_strData[i] = byBuf[i];

if(m_pOwner)
m_pOwner->SendMessage(WM_RECEIVE_COM, (LPARAM)port->m_nPortNr, (WPARAM) nSize);
}

//데이터 SEND
DWORD CSerialPort::WriteComm(BYTE *pBuff, DWORD nToWrite)
{
DWORD dwWritten, dwError, dwErrorFlags;
COMSTAT comstat;
int n;
//데이터 쓰기
/***********************************************************************
*첫번째 인자는 파일 핸들러(포트 디바이스), 두 번째 인자는써야 할 데이터*
*세 번째 인자는 써야 할 바이트의 수, 네 번째 인자는 써야 할 바이트수가 *
*들어 있는 번지, 다섯 번째 인자는 위에서 만든osWrite *
************************************************************************/
n = WriteFile(m_hComm, pBuff, nToWrite, &dwWritten,&m_ovrWrite);

if(!n)//포트에 제대로 써지지 않았으면
{
if(GetLastError() == ERROR_IO_PENDING ) // 아직 전송할 문자가 남아있다면
{
//---- 통신결과가 실패하면 어떤 에러가 났는지 알기위해 GetLastError를 호출한다.
while( !GetOverlappedResult(m_hComm,&m_ovrWrite,&dwWritten,TRUE) )
{
dwError = GetLastError();
if(dwError != ERROR_IO_INCOMPLETE) //작업은 종료된 것이 아니면
{
ClearCommError(m_hComm,&dwErrorFlags,&comstat);
break;
}
}
}
else
{
dwWritten = 0;
ClearCommError(m_hComm,&dwErrorFlags,&comstat);
}

}

return dwWritten;
}


관련글 : 1 건 글쓴시간 : 2008/11/17 19:45 from 220.76.223.41

 

제 목

조회

날짜

글쓴이

 

[응답]SerialPort.cpp [시리얼통신]

6259

2008.11.17

1


  SerialPort.h : header file[아래해더파일] 목록보기 새글 쓰기 지우기 응답글 쓰기 글 수정 [응답]SerialPort.cpp [시리얼통신]  
BACKRUSH  대화방입장  유닉스명령  다음  자료실  Ascii Table   Exploit   원격접속  달력,시간   프로세스  
지하철노선   Whois   RFC문서   SUN FAQ   SUN FAQ1   C메뉴얼   PHP메뉴얼   너구리   아스키월드 아이피서치