본문 바로가기

Software/Network

[serial] Serial 통신 WIN프로그래밍[3]

직렬 설정들
DCB 설정

직렬통신 프로그래밍에서 아주 중요한 것은 장치 제어 블록 구조체 (Device-Control Block, DCB)를 설정하는 것이다. 직렬 통신 프로그래밍의 대부분의 공통적인 오류는 이것을 잘못 설정한 것에 기인한다. 직렬 통신이 원하는데로 잘 동작하지 않으면 DCB구조체가 잘되어 있는지 문제점을 찾아 본다.

DCB구조체를 초기화 하는 방법은 3가지가 있다. 첫 번째 방법은 GetCommState펑션을 사용하는 방법으로 이 펑션은 통신 포트의 현재 DCB를 돌려준다. 다음 코드는 GetCommState펑션의 사용법을 보인다.

 

   DCB dcb = {0};

   if (!GetCommState(hComm, &dcb))
      // Error getting current DCB settings
   else
      // DCB is ready for use.

 
두 번째 방법은 BuildCommDCB를 사용하여 DCB를 초기화 하는 방법이다. 이 펑션은 DCB에 통신 속도, 패리티 종류, 스톱 비트 수, 데이터 비트의 수를 채워준다. 흐름제어 항목들은 기본 값으로 설정한다. BuildCommDCB펑션의 흐름제어에 대한 기본 값은 BuildCommDCB펑션에 대한 설명 문서를 참조한다. DCB의 다른 항목들은 이 펑션에 의하여 영향받지 않으므로 프로그램짜는 것을 난잡하게 한다. 아래에 사용법에 대한 소스이다.
 
   DCB dcb;

   FillMemory(&dcb, sizeof(dcb), 0);
   dcb.DCBlength = sizeof(dcb);
   if (!BuildCommDCB("9600,n,8,1", &dcb)) {
      // Couldn't build the DCB. Usually a problem
      // with the communications specification string.
      return FALSE;
   }
   else
      // DCB is ready for use.


세 번째 방법은 DCB 구조체를 수작업으로 하는 것이다. DCB구조체의 메모리 를 할당하고 각 항목들을 설정한다. 이 방법은 향후 DCB가 변경될 소지가 있으므로 Win32에서는 권장할 것이 못된다.

응용프로그램은 일반적으로 DCB의 항목을 실행 도중에라도 변경해야 할 필요가 있다.DCB 구조체의 멤버를 수정하여도 SetCommState를 호출하기 전까지는 아무런 효과가 없다. 여기 예제에는 현재의 DCB를 구하여 통신 속도를 변경하여 적용시키는 것이다.

   DCB dcb;

   FillMemory(&dcb, sizeof(dcb), 0);
   if (!GetCommState(hComm, &dcb))     // get current DCB
      // Error in GetCommState
      return FALSE;

   //  DCB 속도 갱신.
   dcb.BaudRate = CBR_9600 ;

   // 새로운 상태로 설정
   if (!SetCommState(hComm, &dcb))
/P>

 

여기에 DCB의 각 멤버가 어떠한 의미를 갖는지에 대한 설명이 있다.

주의사항 : 대부분의 정보는 Win32 SDK 문서에 있다. 이 표는 운영체제의 변경이 일어나면 예고없이 변경될 수 있다.

   

DCB 구조체 항목들

Member Description
DCBlength 바이트 단위의 크기. 이 구조체. SetCommState를 호출하기 이전에 세트되어야 한다.
BaudRate 통신 포트의 전송 속도를 지정한다. 이 항목은 실제적인 속 도 이거나 속도의 인덱스이다.(CBR_9600이면 9600BPS)
fBinary 이진(binary)모드 가능함을 지정. Win32 API는 이진모드만 을 지원하므로 이 항목은 반드시 TRUE이어야만 한다. FALSE로 해보면 동작하지 않는다.
fParity 패리티 검사 여부를 지정한다. 이를 TRUE로 하면 패리티 검 사가 수행되고 오류가 발생하면 알려지게 된다. Parity와 혼돈하기 쉬운데 이것은 통신에서 패리티 타입을 지정한 다.
fOutxCtsFlow 송신 흐름 제어를 위하여 CTS신호를 주시할 것을 지정한다. 이 항목이 TRUE이고 CTS가 저위이면 고위가 될 때까지 송 신은 억제된다. The CTS signal is under control of the DCE (usually a modem), the DTE (usually the PC) simply monitors the status of this signal, the DTE does not change it.
fOutxDsrFlow 송신 흐름 제어를 위하여 DSR (data-set-ready) 신호를 주 시할 것을 지정한다. 이 항목이 TRUE이고 DSR이 저위일 경 우 고위가 될 때까지 송신은 억제된다. Once again, this signal is under the control of the DCE; the DTE only monitors this signal.
fDtrControl 수신 흐름 제어를 위하여 DTR (data-terminal-ready)을 사 용한다. 이 항목은 다음 중의 하나가 될 수 있다.
 

DTR_CONTROL_DISABLE 장치를 열었을 때 DTR 라인을 저위로 한다. 응용프로그램은 EscapeCommFunction으로 조정할 수 있다. DTR_CONTROL_ENABLE 장치를 열었을 때 DTR 라인을 고위로 한다. 응용프로그램은 EscapeCommFunction으로 조정할 수 있다. DTR_CONTROL_HANDSHAKE DTR 흐름제어 신호 변경 가능하도록 한다. 이 값이 사용되면 EscapeCommFunction으로 조정할 때 오류가 발생한다.


fDsrSensitivity 통신 제어기가 DSR신호에 민감하게 한다. 이 항목이 TRUE 이면 제어기는 수신된 모든 바이트를 무시하고, 그렇지 않 다면 DSR 모뎀 입력 라인이 고위가 된다.
fTXContinueOnXoff 수신 버퍼가 가득 찼을 때 송신을 중단하고 제어기는 XOFF문자를 송신할 것을 지정한다. 이 항목이 TRUE이면 XOFF문자가 송신되고 송신이 계속된다. 이 항목이 FALSE이 면 수신 버퍼가 XonLim 바이트 이하가 될 때까지 송신은 멈추고 XonLim 바이트 이하가 되면 제어기는 XON 문자를 전송한다.
fOutX 송신 중에 XON/XOFF 흐름제어를 할것인지를 지정한다. TRUE 이면 XOFF 문자가 수신되었을 때 송신을 중단하고 XON문자 가 수신되면 송신을 재개한다.
fInX 수신중에 XON/XOFF 흐름제어를 할것인지를 지정한다. 만약 이 항목이 TRUE이면 XoffLim 바이트로 버퍼가 가득 찼을 때 XOFF 문자를 송신하고 XonLim 바이트 이하로 비었을 때 XON 문자를 송신한다.
fErrorChar 수신도중에 패리티 오류가 발생하면 이 문자로 ErrorChar 항목에서 지정한 문자로 대치할 것인가를 지정한다. 이 항 목이 TRUE이고 fParity 항목이 TRUE이면 오류가 발생하였 을 경우에 대체된다.
fNull NULL 바이트를 제외할 것인지 지정한다. TRUE이면 NULL이 수신되었을 때 무시한다.
fRtsControl RTS (request-to-send) 입력 흐름 제어. 이 값이 0이면 기 본 값인 RTS_CONTROL_HANDSHAKE가 된다. 이 항목은 다음 중 하나가 될 수 있다.
 

RTS_CONTROL_DISABLE 장치가 열리면 RTS 라인은 저위가 된다. 응용프로그램은 EscapeCommFunction으로 조정할 수 있다. RTS_CONTROL_ENABLE 장치가 열리면 RTS 라인은 고위가 된다. 응용프로그램은 EscapeCommFunction으로 조정할 수 있다. RTS_CONTROL_HANDSHAKE RTS 흐름제어를 자동으로 하게 한다. 제어기는 입력 버퍼가 데이터를 받아들이기에 충분한 공간을 가지고 있을 때 RTS를 고위로 하고 DCE를 enabling한다. 입력 버퍼가 충분한 공간을 가지고 있지 않을 때 RTS라인을 저위로하고, 송신을 위해 DCE를 Prevening한다. 이 값을 사용하면 응용프로그램은 EscapeCommFunction으로 조정할 때 오류가 발생한다. RTS_CONTROL_TOGGLE 송신할 것이 있으면 RTS라인은 고위가 되고 송신이 모두 끝나면 RTS라인은 저위가 된다. 이 값을 사용하면 응용프로그램은 EscapeCommFunction으로 조정할 때 오류가 발생한다. 이 값은 윈도우 95에서 는 무시되어 RTS_CONTROL_ENABLE 지정한 상태가 된다.

 
fAbortOnError 오류가 발생하면 읽기와 쓰기 작업이 종료될 것인가를 정한 다. 이 항목이 TRUE이면 오류(ERROR_IO_ABORTED)가 발생하 였을 때 제어기는 읽기와 쓰기 작업을 중지하고 오류 상태 와 함께 종료된다. 제어기는 응용프로그램에서 ClearCommError 펑션으로 오류가 발생한 상황을 알아챌 때 까지 모든 통신 작업을 중지한다.
fDummy2 Reserved; do not use.
wReserved Not used; must be set to zero.
XonLim XON문자를 보내기 전에 입력 버퍼에 놓일 수 있는 최소 바 이트 수를 지정한다.
XoffLim XOFF문자를 보내기 전에 입력 버퍼 안에 놓일 수 있는 최대 바이트 수를 지정한다.
Parity 사용하고자 하는 패리티 방식을 지정한다. 이 항목은 다음 값들 중의 하나가 될 수 있다.
EVENPARITY 짝수
MARKPARITY 마크
NOPARITY 패리티 없음
ODDPARITY 홀수
StopBits 사용하고자 하는 스톱 비트 수를 지정한다. 이 항목은 다음 값들 중의 하나가 될 수 있다.
ONESTOPBIT 1개의 스톱비트
ONE5STOPBITS 1.5개의 스톱비트
TWOSTOPBITS 2개의 스톱비트
XonChar 송신과 수신에서 사용되는 XON 문자 값을 지정한다.
XonChar 송신과 수신에서 사용되는 XON 문자 값을 지정한다.
ErrorChar 패리티 오류가 발생할 때 대치하여 사용할 문자를 지정한다.
EofChar 데이터의 끝 신호로 사용할 문자의 값을 지정한다.
EvtChar EV_RXFLAG 이벤트가 발생함을 알리는 문자값을 지정한다. 이 설정은 SetCommMask 펑션과 WaitCommEvent를 사용하는 중에 EV_RXFLAG 없이 사용한다면 아무런 일도 발생하지 않 는다.
wReserved1 Reserved; do not use.
 
흐름 제어

흐름제어는 직렬 통신에서 제공되는 메카니즘으로서 하나의 장치가 바쁘거나 어떤 이유로 인하여 어떤 통신도 불가능한 상태에 있는 동안에 통신을 억제하는 것이다. 거기에는 2가지 방식의 흐름제어가 있는데 하드웨어와 소프트웨어이다.

직렬 통신에서 공통적인 문제점은 쓰기 작업인데, 실질적으로 장치에 데이터 쓰기가 되지 않는 것이다. 흔히 프로그램에서 흐름제어에 대한 명시를 하지 않은 경우에 문제점이 있다. A close examination of the DCB structure reveals that one or more of the following members may be TRUE: fOutxCtsFlow, fOutxDsrFlow, or fOutX. Another mechanism to reveal that flow control is enabled is to call ClearCommError and examine the COMSTAT structure. It will reveal when transmission is suspended because of flow control. 흐름제어의 타입들을 설명하기에 앞서 이해를 돕기위한 설명을 하자면. 직렬 통신은 장치와 장치 사이에 있다. 전통적으로 그것들은 PC와 모뎀, PC와 프린터이다. PC는 데이터 터미널 장치(Data Terminal Equipment, DTE)라고 이 름이 붙고, DTE는 때로는 호스트라고도 한다. 모뎀이나 프린터 등은 데이터 통신 장치(Data Communications Equipment,DCE)라고 이름이 붙는다. DCE는 때론 장치(device)이다.

 

하드웨어 흐름 제어

하드웨어 흐름제어는 제어 라인에 전압을 이용하여 송신과 수신의 가능함을 제어하는 것이다. DTE와 DCE는 한 종류의 흐름 제어를 사용하여야만 한다. DCB 구초제에 흐름제어를 가능하도록 DTE에서만 세트하면 된다. 윈32에서는 DCE에 대한 흐름 제어를 하는 메카니즘을 제공하지 않는다. 장치에 있는 딥 스위치들을 이용한다거나 명령을 보낸다.

다음은 제어 라인, 흐름 제어 방향에 대하여 설명한다.

< 하드웨어 흐름제어 라인들 >
CTS(Clear To Send) : Output flow control

DCE는 데이터를 받을 수 있을 때 고위(high, 전압이 높음) 상태로 한다.
DCE는 데이터를 받을 수 없을 때 저위(Low, 전압이 낮음) 상태로 한다.
DCB 의 fOutxCtsFlow 항목이 TRUE이면 라인이 저위일 때 DTE는 데이터를 보내지 않을 것이다. 라인이 고위가 되면 보내기가 계속된다.
만약 DCB의 fOutxCtsFlow항목이 FALSE이면 라인의 상태는 송수신에 영향을 주지 않는다.

 
DSR(Data Set Ready) Output flow control

DCE 는 데이터를 수신할 수 있으면 고위로 한다. DCE 는 데이터를 수신할 수 없으면 저위로 한다. DCB의 fOutxDsrFlow 항목이 TRUE이면 DTE는 이 라인이 저위일 때 데이터를 보내지 않는다.
라인이 고위가 되면 보내기를 계속한다.
만약 DCB의 fOutxDsrFlow항목이 FALSE이면 라인의 상태는 송수신에 영향을 주지 않는다. /FONT>

DSR(Data Set Ready)   

DSR라인이 저위일 때 포트를 통해 들어온 데이터는 무시된다. DSR라인이 고위일 경우 도착한 데이터는 포트에 수신된다.
DCB의 fDsrSensitivity 가 TRUE일 경우 이렇게 되며, FALSE이면 송수신에 영향을 주지 않는다.

 
RTS (Ready To Send)Input flow control  

RTS라인은 DTE에서 제어된다. DCB의 fRtsControl 항목이 RTS_CONTROL_HANDSHAKE로 되어 있을 때 흐름제어가 된다. 입력 버퍼가 데이터를 받기에 충분하면(적어도 버퍼의 절반이상이 비어야 한다) 장치 제어기는 RTS를 고위로 한다. 입력 버퍼가 데이터를 받기에 적으면(4분의 1보다 적게 버퍼가 비어 있는 경우) 장치 제어기는 RTS라인을 저위로 한다.
DCB의 fRtsControl 항목이 RTS_CONTROL_TOGGLE로 되어 있다면 보낼 데이터가 있으면 장치 제어기는 RTS를 고위로 한다. 보낼 데이터가 없으면 장치 제어기는 이 라인을 저위로 한다. 윈도우 95에서는 이 값이 무시되고 RTS_CONTROL_ENABLE과 같은 값이 된다.
DCB의 fRtsControl 항목이 RTS_CONTROL_ENABLE이나 RTS_CONTROL_DISABLE로 세트되면 응용프로그램은 필요에 따라 라인의 상태를 바꿀 수 있다. 이러한 경우엔 이 라인은 수신에 영향을 주지 않는다.
DCE는 라인이 저위인 동안 송신을 억제한다. 라인이 고위가 되면 송신을 계속한다.

 

DTR(Data Terminal Ready)Input flow control

DTE에 의하여 DTR 라인이 제어된다.
DCB의 fDtrControl항목이 DTR_CONTROL_HANDSHAKE로 설정되어 있다면 흐름제어가 사용된다.입력 버퍼가 충분하면(절반이상 비어있어야 함) 장치 제어기는 DTR라인을 고위로 한다. 만약 입력 버퍼가 작으면(4분의 1 이하만 비어 있는 경우)는 장치 제어기는 DTR를 저위로 한다.
DCB의 fDtrControl 항목이 DTR_CONTROL_ENABLE 이나 DTR_CONTROL_DISABLE로 설정되어 있다면 응용프로그램은 이 라인의 상태를 필요에 따라 자유로이 변경할 수 있다. 이 경우 이 라인의 상태를 수신에 영향을 주지 않는다.
라인이 저위가 되면 DCE는 송신을 억제하고 라인이 고위가 되면 DCE는 송신을 계속한다.
흐름제어가 필요한 것은 CE_RXOVER 오류가 발생했을 때 쉽게 알아내기 위함이다. 이 오류는 수신 버퍼가 넘치고 데이터를 잃어 버렸다는 것을 나타낸다. 데이터를 읽는 것보다 빨리 수신되는 경우에 CE_RXOVER 가 발생할 수 있다. 수신 버퍼의 크기를 늘리는 것은 오류가 발생하는 빈도를 줄인다. 그러나 완벽하게 문제를 해결하는것이 아니다. 장치 제어기가 수신 버퍼가 이미 가득 찼다는 것을 검색하면 제어기는 입력 흐름 제어 라인들을 저위로 할 것이다. 이는 DCE로 하여금 송신을 멈추게 하고, DTE로 하여금 수신 버퍼에서 읽들일 시간을 준다. 수신 버퍼가 비게 되면 흐름제어 라인의 전압이 올라가서 DCE는 보내기를 계속한다.
이와 유사한 오류는 CE_OVERRUN이다. 이 오류는 새로운 데이터가 이전의 데이터 수신을 완료하기 전에 도착하였을 때 발생한다. 이 경우는 전송 속도가 통신 하드웨어나 CPU의 타입에 비해 너무 빠를 경우에 발생한다. 또한 운영체제가 통신 하드웨어를 서비스 하기에 바쁠 경우에도 발생한다. 이 문제점을 해결하는 방법은 통신 속도를 낮추거나 통신 하드웨어를 교체하거나 CPU의 속도를 증가시키는 방법이다. 때로는 (써드 파티)제3의 하드웨어 장치 제어기가 CPU와 매우 비능률적인 방법으로 동작하여 이런 오류가 발생하기도 한다. 흐름제어는 CE_OVERRUN 문제를 완벽하게 해결할 수는 없고 단지 발생 빈도를 줄이는 것이다.