지난 시간까지 UI 를 구성 하고, 시리얼 통신 클래스를 등록 하는데 까지 했습니다.

이번 시간에는 실제 CMycomm 클래스의 각 메소드들의 기능 구현부분을 알아 보겠습니다.


1. 먼저 CMycomm 클래스를 다이얼로그 클래스에서 사용 하기 때문에 헤더파일을 추가해 줍니다.

  --> serialDlg.h 파일을 열어 Mycomm.h 파일을 include 합니다.

2. Mycomm.h 파일을 열어 각 메소드 들을 선언 합니다.

#pragma once

 

#include <afxmt.h>

 

#define MAXBUF         50000

#define InBufSize      50000

#define OutBufSize     50000

#define ASCII_XON      0x11

#define ASCII_XOFF     0x13

#define WM_MYRECEIVE   (WM_USER+1) //데이터 수신 메시지

#define WM_MYCLOSE     (WM_USER+2) // 종료 메시지

 

 

// CMycomm command target

//클래스생성자

class CMycomm : public CCmdTarget

{

        DECLARE_DYNAMIC(CMycomm)

 

public:

        CMycomm();

        virtual ~CMycomm();

 

        // Attributes

public:

        HANDLE  m_hComDev;

        HWND    m_hWnd;

 

        BOOL    m_bIsOpenned;

        CString m_sComPort;

        CString m_sBaudRate;

        CString m_sParity;

        CString m_sDataBit;

        CString m_sStopBit;

        BOOL    m_bFlowChk;

 

        OVERLAPPED m_OLR,m_OLW;

        char    m_sInBuf[MAXBUF*2];

        int            m_nLength;

        CEvent* m_pEvent;

 

        // Operations

public:

        void Clear();

        int Receive(LPSTR inbuf, int len);

        BOOL Send(LPCTSTR outbuf, int len);

        BOOL Create(HWND hWnd);

        void HandleClose();

        void Close();

        void ResetSerial();

        CMycomm(CString port,CString baudrate,CString parity,CString databit,CString stopbit);

 

 

protected:

        DECLARE_MESSAGE_MAP()

}; 

  --> 붉은색 글씨로 표시된 코드들을 추가 합니다.


3. Mycomm.cpp 파일을 열어 실제 구현 부를 추가 해 줍니다.

// Mycomm.cpp : implementation file

//

 

#include "stdafx.h"

#include "serial.h"

#include "Mycomm.h"

 

// CMycomm

 

IMPLEMENT_DYNAMIC(CMycomm, CCmdTarget)

 

CMycomm::CMycomm()

{

}

 

CMycomm::~CMycomm()

{

                  if (m_bIsOpenned)

                     Close();

                  delete m_pEvent;

}

 

 

 

CMycomm::CMycomm(CString port,CString baudrate,CString parity,CString databit,CString stopbit)

{

                  m_sComPort = port;

                  m_sBaudRate = baudrate;

                  m_sParity = parity;

                  m_sDataBit = databit;

                  m_sStopBit = stopbit;

                  m_bFlowChk = 1;

                  m_bIsOpenned = FALSE;

                  m_nLength = 0;

                  memset(m_sInBuf,0,MAXBUF*2);

                  m_pEvent = new CEvent(FALSE,TRUE);

}

 

BEGIN_MESSAGE_MAP(CMycomm, CCmdTarget)

END_MESSAGE_MAP()

 

// CMycomm message handlers

void CMycomm::ResetSerial()

{

                  DCB                              dcb;

                  DWORD      DErr;

                  COMMTIMEOUTS           CommTimeOuts;

 

                  if (!m_bIsOpenned)

                                   return;

 

                  ClearCommError(m_hComDev,&DErr,NULL);

                  SetupComm(m_hComDev,InBufSize,OutBufSize);

                  PurgeComm(m_hComDev,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

 

                  // set up for overlapped I/O

                  CommTimeOuts.ReadIntervalTimeout = MAXDWORD ;

                  CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;

                  CommTimeOuts.ReadTotalTimeoutConstant = 0 ;

 

                  // CBR_9600 is approximately 1byte/ms. For our purposes, allow

                  // double the expected time per character for a fudge factor.

                  CommTimeOuts.WriteTotalTimeoutMultiplier = 0;

                  CommTimeOuts.WriteTotalTimeoutConstant = 1000;

                  SetCommTimeouts(m_hComDev, &CommTimeOuts);                

 

 

                  memset(&dcb,0,sizeof(DCB));

                  dcb.DCBlength = sizeof(DCB);

 

                  GetCommState(m_hComDev, &dcb);

 

                  dcb.fBinary = TRUE;

                  dcb.fParity = TRUE;

 

                  if (m_sBaudRate == "300")

                                   dcb.BaudRate = CBR_300;

                  else if (m_sBaudRate == "600")

                                   dcb.BaudRate = CBR_600;

                  else if (m_sBaudRate == "1200")

                                   dcb.BaudRate = CBR_1200;

                  else if (m_sBaudRate == "2400")

                                   dcb.BaudRate = CBR_2400;

                  else if (m_sBaudRate == "4800")

                                   dcb.BaudRate = CBR_4800;

                  else if (m_sBaudRate == "9600")

                                   dcb.BaudRate = CBR_9600;

                  else if (m_sBaudRate == "14400")

                                   dcb.BaudRate = CBR_14400;

                  else if (m_sBaudRate == "19200")

                                   dcb.BaudRate = CBR_19200;

                  else if (m_sBaudRate == "28800")

                                   dcb.BaudRate = CBR_38400;

                  else if (m_sBaudRate == "33600")

                                   dcb.BaudRate = CBR_38400;

                  else if (m_sBaudRate == "38400")

                                   dcb.BaudRate = CBR_38400;

                  else if (m_sBaudRate == "56000")

                                   dcb.BaudRate = CBR_56000;

                  else if (m_sBaudRate == "57600")

                                   dcb.BaudRate = CBR_57600;

                  else if (m_sBaudRate == "115200")

                                   dcb.BaudRate = CBR_115200;

                  else if (m_sBaudRate == "128000")

                                   dcb.BaudRate = CBR_128000;

                  else if (m_sBaudRate == "256000")

                                   dcb.BaudRate = CBR_256000;

                  else if (m_sBaudRate == "PCI_9600")

                                   dcb.BaudRate = 1075;

                  else if (m_sBaudRate == "PCI_19200")

                                   dcb.BaudRate = 2212;

                  else if (m_sBaudRate == "PCI_38400")

                                   dcb.BaudRate = 4300;

                  else if (m_sBaudRate == "PCI_57600")

                                   dcb.BaudRate = 6450;

                  else if (m_sBaudRate == "PCI_500K")

                                   dcb.BaudRate = 56000;

 

 

                  if (m_sParity == "None")

                                   dcb.Parity = NOPARITY;

                  else if (m_sParity == "Even")

                                   dcb.Parity = EVENPARITY;

                  else if (m_sParity == "Odd")

                                   dcb.Parity = ODDPARITY;

 

                  if (m_sDataBit == "7 Bit")

                                   dcb.ByteSize = 7;

                  else if (m_sDataBit == "8 Bit")

                                   dcb.ByteSize = 8;                             

 

                  if (m_sStopBit == "1 Bit")

                                   dcb.StopBits = ONESTOPBIT;

                  else if (m_sStopBit == "1.5 Bit")

                                   dcb.StopBits = ONE5STOPBITS;

                  else if (m_sStopBit == "2 Bit")

                                   dcb.StopBits = TWOSTOPBITS;

 

                  dcb.fRtsControl = RTS_CONTROL_ENABLE;

                  dcb.fDtrControl = DTR_CONTROL_ENABLE;

                  dcb.fOutxDsrFlow = FALSE;

 

                  if (m_bFlowChk) {

                                   dcb.fOutX = FALSE;

                                   dcb.fInX = FALSE;

                                   dcb.XonLim = 2048;

                                   dcb.XoffLim = 1024;

                  }

                  else {

                                   dcb.fOutxCtsFlow = TRUE;

                                   dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;

                  }

 

                  SetCommState(m_hComDev, &dcb);

                  SetCommMask(m_hComDev,EV_RXCHAR);

 

}

 

void CMycomm::Close()

{

                  if (!m_bIsOpenned)

                                   return;

 

                  m_bIsOpenned = FALSE;

                  SetCommMask(m_hComDev, 0);

                  EscapeCommFunction(m_hComDev, CLRDTR);

                  PurgeComm(m_hComDev, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

                  Sleep(500);

 

}

 

UINT CommThread(LPVOID lpData)

{

                  extern short g_nRemoteStatus;

                  DWORD       ErrorFlags;

                  COMSTAT     ComStat;

                  DWORD      EvtMask ;

                  char            buf[MAXBUF];

                  DWORD      Length;

                  int              size;

                  int              insize = 0;

 

                  CMycomm* Comm = (CMycomm*)lpData;

 

                  while (Comm->m_bIsOpenned)

                  {

                                   EvtMask = 0;

                                   Length = 0;

                                   insize = 0;

                                   memset(buf,'\0',MAXBUF);

                                   WaitCommEvent(Comm->m_hComDev,&EvtMask, NULL);

                                   ClearCommError(Comm->m_hComDev, &ErrorFlags, &ComStat);

                                   if ((EvtMask & EV_RXCHAR) && ComStat.cbInQue)

                                   {

                                                     if (ComStat.cbInQue > MAXBUF)

                                                                       size = MAXBUF;

                                                     else

                                                                       size = ComStat.cbInQue;

                                                     do

                                                     {

                                                                       ClearCommError(Comm->m_hComDev, &ErrorFlags, &ComStat);

                                                                       if (!ReadFile(Comm->m_hComDev,buf+insize,size,&Length,&(Comm->m_OLR)))

                                                                       {

                                                                                        // 에러

                                                                                        TRACE("Error in ReadFile\n");

                                                                                        if (GetLastError() == ERROR_IO_PENDING)

                                                                                        {

                                                                                                          if (WaitForSingleObject(Comm->m_OLR.hEvent, 1000) != WAIT_OBJECT_0)

                                                                                                                            Length = 0;

                                                                                                          else

                                                                                                                            GetOverlappedResult(Comm->m_hComDev,&(Comm->m_OLR),&Length,FALSE);

                                                                                        }

                                                                                        else

                                                                                                          Length = 0;

                                                                       }

                                                                       insize += Length;

                                                     } while ((Length!=0) && (insize<size));

                                                     ClearCommError(Comm->m_hComDev, &ErrorFlags, &ComStat);

 

                                                     if (Comm->m_nLength + insize > MAXBUF*2)

                                                                       insize = (Comm->m_nLength + insize) - MAXBUF*2;

 

                                                     Comm->m_pEvent->ResetEvent();

                                                     memcpy(Comm->m_sInBuf+Comm->m_nLength,buf,insize);

                                                     Comm->m_nLength += insize;

                                                     Comm->m_pEvent->SetEvent();

                                                     LPARAM temp=(LPARAM)Comm;

                                                     SendMessage(Comm->m_hWnd,WM_MYRECEIVE,Comm->m_nLength,temp);

                                   }

                  }

                  PurgeComm(Comm->m_hComDev, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

                  LPARAM temp=(LPARAM)Comm;

                  SendMessage(Comm->m_hWnd,WM_MYCLOSE,0,temp);

                  return 0;

}

 

void CMycomm::HandleClose()

{

                  CloseHandle(m_hComDev);

                  CloseHandle(m_OLR.hEvent);

                  CloseHandle(m_OLW.hEvent);

 

}

 

BOOL CMycomm::Create(HWND hWnd)

{

                  m_hWnd = hWnd;

 

                  m_hComDev = CreateFile(m_sComPort, GENERIC_READ | GENERIC_WRITE,

                                   0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,

                                   NULL);

 

                  if (m_hComDev!=INVALID_HANDLE_VALUE)

                                   m_bIsOpenned = TRUE;

                  else

                                   return FALSE;

 

                  ResetSerial();

 

                  m_OLW.Offset = 0;

                  m_OLW.OffsetHigh = 0;

                  m_OLR.Offset = 0;

                  m_OLR.OffsetHigh = 0;

 

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

                  if (m_OLR.hEvent == NULL) {

                                   CloseHandle(m_OLR.hEvent);

                                   return FALSE;

                  }

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

                  if (m_OLW.hEvent == NULL) {

                                   CloseHandle(m_OLW.hEvent);

                                   return FALSE;

                  }

                  AfxBeginThread(CommThread,(LPVOID)this);

                  EscapeCommFunction(m_hComDev, SETDTR);

                  return TRUE;

 

}

 

BOOL CMycomm::Send(LPCTSTR outbuf, int len)

{

                  BOOL          bRet=TRUE;

                  DWORD       ErrorFlags;

                  COMSTAT     ComStat;

 

                  DWORD       BytesWritten;

                  DWORD       BytesSent=0;

 

                  ClearCommError(m_hComDev, &ErrorFlags, &ComStat);

                  if (!WriteFile(m_hComDev, outbuf, len, &BytesWritten, &m_OLW))

                  {

                                   if (GetLastError() == ERROR_IO_PENDING)

                                   {

                                                     if (WaitForSingleObject(m_OLW.hEvent,1000) != WAIT_OBJECT_0)

                                                                       bRet=FALSE;

                                                     else

                                                                       GetOverlappedResult(m_hComDev, &m_OLW, &BytesWritten, FALSE);

                                   }

                                   else /* I/O error */

                                                     bRet=FALSE; /* ignore error */

                  }

 

                  ClearCommError(m_hComDev, &ErrorFlags, &ComStat);

 

                  return bRet;

 

}

 

int CMycomm::Receive(LPSTR inbuf, int len)

{

                  CSingleLock lockObj((CSyncObject*) m_pEvent,FALSE);

                  // argument value is not valid

                  if (len == 0)

                                   return -1;

                  else if  (len > MAXBUF)

                                   return -1;

 

                  if (m_nLength == 0)

                  {

                                   inbuf[0] = '\0';

                                   return 0;

                  }

                  else if (m_nLength <= len)

                  {

                                   lockObj.Lock();

                                   memcpy(inbuf,m_sInBuf,m_nLength);

                                   memset(m_sInBuf,0,MAXBUF*2);

                                   int tmp = m_nLength;

                                   m_nLength = 0;

                                   lockObj.Unlock();

                                   return tmp;

                  }

                  else

                  {

                                   lockObj.Lock();

                                   memcpy(inbuf,m_sInBuf,len);

                                   memmove(m_sInBuf,m_sInBuf+len,MAXBUF*2-len);

                                   m_nLength -= len;

                                   lockObj.Unlock();

                                   return len;

                  }

}

 

void CMycomm::Clear()

{

                  PurgeComm(m_hComDev, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

                  memset(m_sInBuf,0,MAXBUF*2);

                  m_nLength = 0;

 

} 

--> 한번 만들어 보는 것을 목적으로 하기 때문에 자세한 코드 설명은 하지 않겠습니다. 대충 보면 알겠지만, 통신 환경을 설정 하는 부분이 있고, 수신부, 포트 닫기 등의 동작이 구현 되어 있습니다.

--> 데이터 수신은 스레드로 돌리고, 수신되면 데이터를 버퍼에 저장 후 헤더파일에 define 해놓은 메시지를 발생 시킵니다.

물론 스레드를 종료 할때도 메시지를 전달 하는식 입니다.


여기까지 해서 하나의 cpp 파일과 하나의 헤더 파일로 시리얼 통신을 사용 하기 위한 클래스는 완성 되었습니다. 이제 다이얼로그 클래스에서 이 시리얼통신 클래스의 객체를 하나 만들어 위 메소드들을 사용 하기만 하면 됩니다.

다음 시간에는 이 클래스를 사용 하는 방법을 알아 보겠습니다.