리눅스에서 serial programming

The Linux Serial Programming HOWTO

리눅스 시리얼 프로그래밍 하우투

Peter H. Baumann, Peter.Baumann@dir.de

v1.0, 22 January 1998 전성민, schun@crypto.pe.kr 2000년 2월 24일
이 문서는 리눅스 시스템에서 시리얼 통신을 어떻게 프로그래밍하는가를 설명하는 하우투 문서이다.

1. 소개

이 문서는 리눅스 시스템에서 시리얼 통신을 어떻게 프로그래밍하는가를 설명하는 하우투 문서이다. 다양한 시리얼 통신 프로그램 기법들(Canonical I/O, 비동기 I/O, I/O 멀티플렉싱)을 설명한다.

시리얼 포트를 셋업하는 방법에 대해서는 Greg Hankins의 Serial-HOWTO 문서를 읽어보기 바란다.

나는 이 분야의 전문가가 아님을 먼저 밝혀둔다. 그러나 프로젝트를 하면서 많은 문제들에 부딪혔다. 이 문서에 소개된 코드 예제들은 LDP(Linux Document Project) 프로그래머 가이드( ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz 및 미러 사이트들)에서 구할 수 있는 miniterm code에 근거하여 만들었다.

1997 년 6월에 이 문서를 작성한 뒤에 나는 고객의 요구에 의해 Win NT 환경으로 옮기게 되어서 더 이상 깊은 지식을 얻을 수 없었다. 누구든지 커맨트가 있으면 이 문서를 관리하는데에 기꺼이 활용하겠다.(Feedback 부분을 볼 것) 또한 이 문서의 유지 및 관리를 맡고 싶거나 version UP을 원한다면 e-mail을 주기 바란다.

이 문서의 모든 예제는 i386 Linux Kernel 2.0.29에서 테스트를 하였다.

1.1 저작권

The Linux Serial-Programming-HOWTO is copyright (C) 1997 by Peter Baumann. Linux HOWTO documents may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice si retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions.

All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to thes rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below.

In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs.

If you have questions, please contact Tim Bynum, the Linux HOWTO coordinator, at linux-howto@sunsite.unc.edu via email.

1.2 이 문서의 최신 버전

이 문서의 최신 버전은 ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO 와 미러 사이트에서 찾을 수 있다. PostScript 및 DVI 버전도 다른 포맷들을 갖고 있는 디렉토리에 있다. http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html 에서도 구할 수 있으며, comp.os.linux.answers에 매달 포스팅 될 것이다.

1.3 Feedback

오 류, 질문, 커맨트, 건의사항이나 그 외 추가할 사항이 있다면 알려주기 바란다. 이 HOWTO를 계속적으로 업데이트 하기를 원한다. 당신이 정확히 이해하지 못하는 부분이 있거나 더 명확해야 할 부분이 있다면 알려줘라. 내 e-mail 주소는 Peter.Baumann@dir.de 이다. 이 문서에 관한 e-mail을 보낼 때는 문서의 버전도 같이 알려줘라. 이 문서 버전은 1.0이다.

2. 시작하기

2.1 디버깅

코 드를 디버깅하는 가장 좋은 방법은 또 하나의 리눅스 박스를 셋업하고 두 리눅스 박스를 null-modem 케이블로 연결하는 것이다. Miniterm 프로그램을 이용하여 문자들을 전송해보라. Miniterm은 컴파일하기도 쉽고, 키보드에서 입력되는 문자들(특수문자 포함)을 시리얼 포트로 전송할 수 있다. 컴파일할 때 체크해야 할 것은

#define MODEMDEVICE "/dev/ttyS0"

문장이 제대로 설정되어 있는가 하는 것이다. COM1으로 맞추려면 /dev/ttyS0, COM2로 하려면 /dev/ttyS1으 로 수정한다. 테스팅을 할 때 가장 중요한 것은 문자가 시리얼 포트로 출력될 때 데이터가 출력 데이터 처리(output processing)을 하지 않고 그대로(raw) 전송이 되는가를 확인하는 것이다. 테스트 과정은 다음과 같다. 두 대의 리눅스 박스에서 각각 miniterm 프로그램을 실행시키고 키보드를 쳐본다. 한 곳에서 타이핑한 문자가 다른 곳에서 그대로 나타나는 지 확인한다.

Null-modem 케이블의 TxD와 RxD가 서로 cross 연결이 되어야 한다. 잘 모르겠으면 Serial-HOWTO 문서의 7장을 본다.

위의 테스트는 한 대의 컴퓨터만 갖고도 가능하다. 사용할 수 있는 시리얼 포트가 두 개 있다면 케이블을 각각의 시리얼 포트에 연결하고 miniterm을 두 개 실행하여 테스트하면 된다.

2.2 포트 세팅

장치 파일인 /dev/ttyS*는 리눅스에서 터미널을 연결하기 위한 목적으로 사용된다. 이 사실은 시리얼 통신 프로그래밍을 하는데 반드시 기억해야 할 사항이다. 예를 들어, 시리얼 포트도 문자 에코를 하도록 설정되어 있다. 이 설정은 보통 데이터 전송시에 바꿔야 할 사항이다. (역자 주: 시리얼 장치 파일도 터미널 장치로 분류되기 때문에 초기 설정은 일반 터미널에서 사용되는 에코가 되도록 설정되어 있는 것이다.)

모든 파라미터들은 프로그램 코드에서 쉽게 설정할 수 있다. 파라미터들은 <asm/termbits.h>에 정의되어 있는 struct termios 구조체에 저장되어 있다.

       #define NCCS 19

struct termios {

tcflag_t c_iflag; /* input mode flags */

tcflag_t c_oflag; /* output mode flags */

tcflag_t c_cflag; /* control mode flags */

tcflag_t c_lflag; /* local mode flags */

cc_t c_line; /* line discipline */

cc_t c_cc[NCCS]; /* control characters */

};

이 파일은 모든 flag들을 정의하고 있다. c_iflag(입력 모드 flag)는 모든 입력 처리(input processing)를 정의한다. 입력 처리란 read() 함수에 의해 시리얼 포트로 들어온 데이터를 read에 의해 읽기 전에 데이터들을 c_iflag에 정의한 대로 처리하는 것을 의마한다. c_oflag(출력 모드 flag)는 출력 처리(output processing) 하는 방법을 정의한다. c_cflag(제어 모드 flag)는 baudrate, data bits, stop bits 등의 포트 세팅을 정의한다. c_lflag(local 모드 flag)는 echo를 할 것인지 등을 결정한다. 마지막으로 c_cc(제어 문자) 배열은 EOF(End of File), STOP 등의 제어 동작들을 어떤 문자로 정의할 것인가를 설정한다. 제어 문자의 디폴트 문자는 <asm/termios.h>에 정의되어 있다. 위 flag들에 관한 설명은 termios(3) man page에 나와있다. termios 구조체의 c_line 항목은 POSIX 호환 시스템에서 사용되지 않는다.

2.3 시리얼 장치의 입력 방법

이 섹션에서는 세 가지의 입력 방법을 기술하기로 한다. 응용 분야에 따라서 알맞은 방법을 사용해야 한다. 한 문자씩 읽는 루프를 돌려서 전체 문자열을 받는 방법은 가능하다면 피해야 한다. 내가 이런 방법으로 했을 때, 문자를 잃어버리는 경우가 생긴 반면, 전체 문자열을 한번에 읽을 때는 에러가 발생하지 않았다.

Canonical 입력 처리(Canonical Input Processing)

Canonical 입력 처리는 터미널의 기본 처리 방법이다. 이 방법은 한 줄 단위로 처리하는 다른 프로그램과 통신하는데에 사용할 수 있다. 한 줄은 디폴트로 NL(New Line, ASCII는 LF) 문자, EOF(End of File) 문자, 혹은 EOL(End of Line)에 의해 종료되는 문자열을 의미한다. CR(Carriage Return, DOS/Windows의 디폴트 EOL 문자임) 문자는 디폴트 세팅에서 한 줄의 종료 문자로 인식되지 않는다.

또한 Canonical 입력 처리 모드에서는 ERASE, DELETE WORD, REPRINT CHARACTERS 문자들을 처리할 수 있고, CR 문자를 NL 문자로 변환 처리를 할 수 있다.

Non-Canonical 입력 처리(Non-Canonical Input Processing)

Non-Canonical 입력 처리 모드에서는 한 번 읽을 때마다 정해진 크기의 문자만을 읽어낼 수 있다. 또한 타이머를 두어서 일정 시간까지 read()가 리턴하지 않는 경우 강제 리턴을 할 수 있다. 이 모드는 항상 정해진 크기의 문자들만을 읽어내거나 대량의 문자들을 전송하고자 할 때 사용한다.

비동기 입력

위에서 설명한 두 가지 모드는 동기 방식이나 비동기 방식으로 사용될 수 있다. 동기 방식은 read의 조건이 만족될 때까지 block되는 방식으로서 디폴트로 설정되어 있다. 비동기 방식에서는 read() 함수가 바로 리턴되며, 호출한 프로그램에게 signal을 보낸다. 이 signal은 signal handler(시그널 처리 함수)로 보내진다.

입력장치 멀티플렉싱

위 에서 설명한 입력 모드에 해당하진 않지만 여러 개의 장치들을 다루고자 할 때 유용하다. 예를 들어 내 응용 프로그램에서 TCP/IP 소켓과 시리얼 통신에서 동시에 입력을 받아야 했다. 아래 3.4의 예제는 두 개의 서로 다른 장치로부터 동시에 입력을 기다리는 코드이다. 둘 중 한 개의 장치에서 입력이 들어오면 처리를 하고 또 다시 새로운 입력이 올 때까지 기다린다.

아래 3.4의 예제는 복잡해 보일 수 있지만, 리눅스가 multi-processing OS임을 알고 있기에 매우 중요하다. select() 시스템 호출 함수는 입력을 기다리는 동안 CPU에 부하를 주지 않는다. 반면 입력이 들어왔는지 루프를 돌면서 체크하는 polling 방식은 시스템에 부하를 주게 되어 다른 프로세스의 수행 속도를 저하시키게 된다.




4. 다른 유용한 정보

  • Serial-HOWTO 문서는 시리얼 포트를 어떻게 셋업하는지를 설명하고 하드웨어 정보를 제공한다.
  • Michael Sweet의 Serial Programming Guide for POSIX Compliant Operating Systems. 이 링크는 옛날 것이고 최신 위치를 찾을 수가 없다. 이거 찾아줄 분 누구 없수? 이 문서는 매우 잘 정리된 것이다. (역자 주: 다시 이 위치가 부활했다. 예전에 잠시 폐쇄된 적이 있었다.)
  • termios(3) man page는 termios 구조체의 모든 flag에 대해 정의되어 있다.



3. 프로그램 예제

여기의 모든 예제는 miniterm.c에서 따왔다. Canonical 입력 처리에서 처리할 수 있는 최대 길이의 문자는 255개(<linux/limits.h> 혹은 <posix1_lim.h>에 정의됨) 로서 버퍼의 최대 길이는 255로 제한된다.

여 러 입력 처리 모드의 사용법에 대한 설명을 원하면 코드 내의 comment를 참조하라. 코드가 이해하기 쉽기를 바란다. Canonical 입력 처리 모드의 예제는 comment를 가장 잘 해놓았다. 다른 예제는 canonical 모드 예제와 다른 부분에만 comment를 달았다.

설명이 완벽하진 않지만, 이 예제로 직접 테스트를 해보면 당신의 프로그램에 적용할 때 최적의 방법을 찾을 수 있을 것이다.

시리얼 포트 장치 파일의 선택을 제대로 했는가를 다시 한 번 확인하고, 파일 접근 허가는 제대로 되어 있는지 보기를 바란다. (예: chmod a+rw /dev/ttyS1)

3.1 Canonical 입력 처리(Canonical Input Processing)



  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <termios.h>
  #include <stdio.h>

  /* Baudrate 설정은 <asm/termbits.h>에 정의되어 있다.
  /* <asm/termbits.h>는 <termios.h>에서 include된다. */
  #define BAUDRATE B38400
  /* 여기의 포트 장치 파일을 바꾼다. COM1="/dev/ttyS1, COM2="/dev/ttyS2 */
  #define MODEMDEVICE "/dev/ttyS1"
  #define _POSIX_SOURCE 1 /* POSIX 호환 소스 */

  #define FALSE 0
  #define TRUE 1

  volatile int STOP=FALSE;

  main()
  {
    int fd,c, res;
    struct termios oldtio,newtio;
    char buf[255];

  /* 읽기/쓰기 모드로 모뎀 장치를 연다.(O_RDWR)
     데이터 전송 시에 <CTRL>-C 문자가 오면 프로그램이 종료되지 않도록
     하기 위해 controlling tty가 안되도록 한다.(O_NOCTTY)
  */
   fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
   if (fd <0) {perror(MODEMDEVICE); exit(-1); }

   tcgetattr(fd,&oldtio); /* save current serial port settings */
   bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */

  /*
    BAUDRATE: 전송 속도. cfsetispeed() 및 cfsetospeed() 함수로도 세팅 가능
    CRTSCTS : 하드웨어 흐름 제어. (시리얼 케이블이 모든 핀에 연결되어 있는
              경우만 사용하도록 한다. Serial-HOWTO의 7장을 참조할 것.)
    CS8     : 8N1 (8bit, no parity, 1 stopbit)
    CLOCAL  : Local connection. 모뎀 제어를 하지 않는다.
    CREAD   : 문자 수신을 가능하게 한다.
  */
   newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

  /*
   IGNPAR   : Parity 에러가 있는 문자 바이트를 무시한다.
   ICRNL    : CR 문자를 NL 문자로 변환 처리한다. (이 설정을 안하면 다른
              컴퓨터는 CR 문자를 한 줄의 종료문자로 인식하지 않을 수 있다.)
    otherwise make device raw (no other input processing)
  */
   newtio.c_iflag = IGNPAR | ICRNL;

  /*
   Raw output.
  */
   newtio.c_oflag = 0;
  /*
   ICANON   : canonical 입력을 가능하게 한다.
    disable all echo functionality, and don't send signals to calling program
  */
   newtio.c_lflag = ICANON;

  /*
    모든 제어 문자들을 초기화한다.
    디폴트 값은 <termios.h> 헤더 파일에서 찾을 수 있다. 여기 comment에도
    추가로 달아놓았다.
  */
   newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */
   newtio.c_cc[VQUIT]    = 0;     /* Ctrl- */
   newtio.c_cc[VERASE]   = 0;     /* del */
   newtio.c_cc[VKILL]    = 0;     /* @ */
   newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
   newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
   newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
   newtio.c_cc[VSWTC]    = 0;     /* '

by 루오니 | 2006/02/17 18:15 | 프로그래밍 | 트랙백 | 덧글(2)

트랙백 주소 : http://katalog.egloos.com/tb/2210615
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 아크몬드 at 2006/02/17 21:38
orz
Commented by 루오니 at 2006/02/17 23:22
;;;;

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶