WinAPI Serial Port 통신 예제

어제 면접을 보러 갔는데 면접관이 이력서에 적힌 내가 했던 플젝들을 보더니 그동안 해온 작업중 기기통신은 어떤방식으로 했는지 물어봄.
시리얼 통신도 하고 USB통신도 하고 소켓통신도 사용했다고 답했다.

시리얼포트 인터페이스는 직접 만들었는지 아니면 라이브러리 가져다 썼냐고 물어봤는데
내 기억엔 시리얼 통신에 라이브러리 껀덕지가 있었다는 인식이 없어서 그냥 포트 열고 커넥트 해서 썼다고 했는데 면접관은 MFC에는 기본적으로 시리얼 통신 라이브러리가 없다고 함.

그럴리가 없는데 라이브러리 라고 할만한게 없는데.. 라고 생각하면서 면접 망치고 집에 오자마자 예전에 시리얼통신 작업 했던것을 뒤져봄 그리고 알게됨.
면접관 말대로 MFC 내장으로 지원하는건 아니였고 예전에 인터넷에 돌아다니는거 적당히 짜집기 해서 내가 쓰기 좋게 만들어 놓은걸 쓰고 있었음.

이게 딱히 잘 정리된 코드는 아니지만 생각난김에 여기 정리해서 올림.

#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();

	bool	Open( int nPort = 2, int nBaud = 38400 );
	bool	Close( void );

	size_t	ReadData( void *, size_t );
	size_t	WriteData( char *, size_t );
 

	bool	IsOpened( void ){ return( m_bOpened ); }
	
	bool	WriteCommByte( unsigned char );

protected:
	HANDLE	m_hIDComDev;
	OVERLAPPED m_OverlappedRead, m_OverlappedWrite;
	bool	m_bOpened;

};

#endif

serial.h

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

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

int main()
{
	CSerial			m_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

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

댓글 남기기

이메일 주소는 공개되지 않습니다.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.