윈도우 시리얼포트 통신 코드

어제 취업 면접을 보러 갔는데
이런저런 기기 통신은 어떻게 했냐고 하길래 시리얼도 쓰고 USB도 쓰고 소켓통신도 하고 했었다고 했다.

시리얼 포트 인터페이스는 직접 만들었는지 아님 라이브러리 가져다 썼냐고 면접관이 물었는데
내 기억엔 그거 딱히 라이브러리 쓸거 없이 MFC에서 그냥 포트 열고 커넥트 해서 읽고 썼다고 말했는데
면접관이 MFC에 그런 라이브러리가 없다는거다.

그럴리가 없는데 그냥 열고 쓰면 됬는데 무슨소린가
시리얼포트가 내가 생각하는 그거 아니라 뭔가 다른게 있는건가 하는 생각이 면접 내내 맴돔

면접은 망이였지만 집에 와서 옛날에 만들었던거 뒤지고 뒤져봄
그리고 찾음.

아.. MFC는 아니고 그냥 WinAPI로 열고 쓰고 했던거군.
그리고 이게 send 한다고 바로 가는게 아니라서 약간 타임 이벤트 같은거 함수 써서 걸어주는게 있었는데
그런거 때문에 라이브러리 말한거였군

별로 좋은건 아니지만 암튼 생각난김에 정리해서 올림.

뭐 이제 시리얼 포트 쓸일이 있을려나 하는 생각도 들지만

#include <strsafe.h>
#include "Serial.h"

CSerial::CSerial()
:m_bOpened(false),m_hIDComDev(NULL){

}

CSerial::~CSerial(){
Close();
}

bool
CSerial::Open( int nPort, int nBaud ){
if( m_bOpened ) 
return (true);

wchar_t szPort[25];
 StringCbPrintfW( szPort, sizeof(szPort), L"\\\\.\\COM%d", nPort );
m_hIDComDev = CreateFileW( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hIDComDev == NULL ) 
return (false);

//------------------------------------------------------------------
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts( m_hIDComDev, &CommTimeOuts );

//------------------------------------------------------------------
 memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

//------------------------------------------------------------------
DCB dcb;
dcb.DCBlength = sizeof(DCB);
GetCommState(m_hIDComDev, &dcb);

dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
//dcb.Parity = Parity;
//dcb.StopBits = StopBits;
//dcb.fBinary = true;
//dcb.fDsrSensitivity = false;
//dcb.fParity = fParity;
//dcb.fOutX = false;
//dcb.fInX = false;
//dcb.fNull = false;
//dcb.fAbortOnError = true;
//dcb.fOutxCtsFlow = false;
//dcb.fOutxDsrFlow = false;
//dcb.fDtrControl = DTR_CONTROL_DISABLE;
//dcb.fDsrSensitivity = false;
//dcb.fRtsControl = RTS_CONTROL_DISABLE;
//dcb.fOutxCtsFlow = false;
//dcb.fOutxCtsFlow = false;

//------------------------------------------------------------------
 
if (SetCommState(m_hIDComDev, &dcb) == false ||
SetupComm(m_hIDComDev, 4096, 4096) ==false ||//버퍼사이즈
m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL) {

if (m_OverlappedRead.hEvent != NULL)
CloseHandle(m_OverlappedRead.hEvent);
if (m_OverlappedWrite.hEvent != NULL)
CloseHandle(m_OverlappedWrite.hEvent);
if(m_hIDComDev !=NULL)
CloseHandle(m_hIDComDev);
return (false);
}

m_bOpened = true;
return (true);
}
 
//------------------------------------------------------------------------------------------------------------------------------------
bool
CSerial::Close( void ){
if( m_bOpened == false || m_hIDComDev == NULL ) 
return (true);

if(m_OverlappedRead.hEvent != NULL) 
CloseHandle( m_OverlappedRead.hEvent );
if(m_OverlappedWrite.hEvent != NULL) 
CloseHandle( m_OverlappedWrite.hEvent );
if (m_hIDComDev != NULL)
CloseHandle(m_hIDComDev);
m_bOpened = false;
m_hIDComDev = NULL;

return (true);
}
//------------------------------------------------------------------------------------------------------------------------------------
bool
CSerial::WriteCommByte( unsigned char ucByte ){
BOOL bWriteStat;
DWORD dwBytesWritten;

bWriteStat = WriteFile( m_hIDComDev, (LPSTR) &ucByte, 1, &dwBytesWritten, &m_OverlappedWrite );
if(!bWriteStat && (GetLastError() == ERROR_IO_PENDING)) {
if(WaitForSingleObject(m_OverlappedWrite.hEvent, 1000))
dwBytesWritten = 0;
else {
GetOverlappedResult(m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE);
m_OverlappedWrite.Offset += dwBytesWritten;
}
}
return (true);
}
//------------------------------------------------------------------------------------------------------------------------------------
size_t 
CSerial::WriteData(  char *buffer, size_t size ){

if( m_bOpened == false || m_hIDComDev == NULL ) 
return (0);

DWORD dwBytesWritten = 0;
unsigned i;
for( i=0; i<size; i++ ){
WriteCommByte( buffer[i] );
dwBytesWritten++;
}
return (size_t) dwBytesWritten;
}
 
//------------------------------------------------------------------------------------------------------------------------------------
size_t 
CSerial::ReadData( void *buffer, size_t limit ){
if (m_bOpened == false || m_hIDComDev == NULL)
return (0);

BOOL bReadStatus;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat;

ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );
if( !ComStat.cbInQue ) 
return (0);

dwBytesRead = (DWORD) ComStat.cbInQue;
if( limit < (int) dwBytesRead ) 
dwBytesRead = (DWORD) limit;

bReadStatus = ReadFile( m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );

if( !bReadStatus ){
if( GetLastError() == ERROR_IO_PENDING ){
WaitForSingleObject( m_OverlappedRead.hEvent, 100 );
return( (int) dwBytesRead );
}
return (0);
}
return (size_t) dwBytesRead;
}
//------------------------------------------------------------------------------------------------------------------------------------ 

serial.cpp

 
// Serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <windows.h>

class CSerial
{

public:
CSerial();
~CSerial();

boolOpen( int nPort = 2, int nBaud = 38400 );
boolClose( void );

size_tReadData( void *, size_t );
size_tWriteData( char *, size_t );
 

boolIsOpened( void ){ return( m_bOpened ); }

boolWriteCommByte( unsigned char );

protected:
HANDLEm_hIDComDev;
OVERLAPPED m_OverlappedRead, m_OverlappedWrite;
boolm_bOpened;

};

#endif

serial.h

 
// SerialTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Serial.h"

int main()
{
CSerialm_cSerial;
char data[1024] = { 0, };
memset(data, 0, sizeof(data));


m_cSerial.Open(4, 38400);
//읽을때
m_cSerial.ReadData(data, 7);

//쓸때
data[0] = 'S';
data[1] = 'T';
data[2] = 0;
m_cSerial.WriteData(data, 3);

    return 0;
}

main.cpp

SerialTest
Visual Studio 2015 CE 버전으로 빌드 테스트 해서 올림.
시리얼 포트도 시리얼 포트 쓰는 장비도 없어서 잘 돌아가는지는 모르겠지만
옛날에 잘 쓰던거니 아마 될듯.


크리에이티브 커먼즈 라이선스Linsoo의 저작물인 이 저작물은(는)크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

댓글 남기기

이메일은 공개되지 않습니다.

This site uses Akismet to reduce spam. Learn how your comment data is processed.