
                      The Linux Serial Programming HOWTO
                                       
by Peter H. Baumann, [1]Peter.Baumann@dlr.de
: Ԫ [2]yytseng@ms16.hinet.net

   v1.0, 22 һ 1998
     _________________________________________________________________
   
   ļ Linux ׫двͨѶʽ.
     _________________________________________________________________
   
1. 

     * 1.1 Ȩ
     * 1.2 µİ汾
     * 1.3 
       
2. ʼ

     * 2.1 
     * 2.2 Ӳ趨
     * 2.3 װõ
       
3. ʽ

     * 3.1 ׼
     * 3.2 Ǳ׼
     * 3.3 ͬʽ
     * 3.4 ȴԶѶԴ
       
4. Դ

5. 
     _________________________________________________________________
   
1. 

    Linux вʽ׫д HOWTO. ȫƪ Linux ,
   в װ/ ͨѶĳʽд. ͵ļ: ׼ I/O
   (ֻ߱ / ߵ), ͬ I/O,  ȴԶźԴѶ д
   .
   
   Ĳ趨в, Ϊ Greg Hankins  Serial-HOWTO Ѿ
   ˵.
   
   ұǿҲǴеר, רͨѶ. 
   ᵽġʽ miniterm ĳʽ.  LDP ʽʦָȡ
   
   (ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.ta
   r.gz ӳվ) ڡǸĿ¼.
   
   ҿʼдļ 1997  , Ѿת WinNT ͻ
   , ûѧø֪ʶ. κʲ, Һ
   ڽļ (ο  һ). ܽݹԸĽ, 
   e-mail .
   
   еġ i386 Linux Kernel 2.0.29 ²Թ.
   
1.1 Ȩ

   Linux Serial-Programming-HOWTO İȨ(C) 1997  Peter Baumann .
   Linux HOWTO ļ򲿷ʵʻʽƻɢ, ֻҪȨ
   ܱɢĸ. ҵԵɢɲ; , 
   Դʽɢ Ӧ ֪.
   
   йصķ, Ĺ, Ϻϲκ Linux HOWTO ļԱڴ˰
   Ȩ֮. Ҳ, 㲻 HOWTO Ĺ, ɢļϸ
   Ӷ. Щ֮Կĳ;  Linux
   HOWTO ЭԱ: λַ.
   
   ֮, ϣܵ͸ֹܵٽѶͨ, , ǿ
   ϣȨ HOWTO ļ, κ  ɢ HOWTO , ϣ
   ֪һ.
   
   , 뾭 email  Tim Bynum, Linux HOWTO ЭԱ,
   [3]linux-howto@sunsite.unc.edu.
   
1.2 µİ汾

   Serial-Programming-HOWTO µİ汾
   [4]ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO/Serial-Programming-HOWT
   O ӳվ̨. ĸʽ,  PostScript  DVI İ汾
   other-formats Ŀ¼. Serial-Programming-HOWTO Ҳ
   [5]http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html 
   ÿ°һݵ [6]comp.os.linux.answers.
   
1.3 

   κ, , , , ӵĴ͸. ҸĽ
    HOWTO! ϸĸ˽, 򲻹. 
   email  [7]Peter.Baumann@dlr.de.  Serial-Programming-HOWTO 
   汾븽, İ汾 0.3.
   
2. ʼ

2.1 

   õʽķǽһ̨ Linux box, ̨
   null-modem .  miniterm ( LDP ʽʦָȡ
   (ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.ta
   r.gz ڡǸĿ¼) ԴԪ Linux box. Miniterm ױ
   뵽̵Ԫ͸в. ֻ涨ᱻ
   #define MODEMDEVICE "/dev/ttyS0".  COM1 趨Ϊ ttyS0, 
   COM2 趨Ϊ ttyS1 ȵ.. ǰĲǱҪ, е Ԫ raw ʽ
   (κδ) ֱӴ. Ƿȷ, ̨϶ miniterm
   ȻڼҰ. һ̨ԪӦûʾһ̨Ϸ
   ֮ͬ. ԪӦ֮өĻ.
   
   Ҫ null-modem ĵ, Ҫ TxD ()  RxD () ߶
   . ϸ˵ Serial-HOWTO ĵ 7 .
   
   ȻҲֻһ̨ͬĲ, ֻҪδʹõв.
   ȻҲҪִ miniterm ̨. ǽɰȥȡ
   һв, ǵҪ /dev/mouse װµ, ڵĻ. 
   ʹö಺вƿ, ȷ趨ȷ. ҵĵϲʱҲ
   Ϊ趨. һ̨, ͨѶʼԪ. 
   Ϊպⲻķͬʽ, Կͬһִ̨ʽ.
   
2.2 Ӳ趨

   /dev/ttyS* װûᱻӵ Linux box ն˻, 
   . д raw װõͨѶʽʱס. Ҳ˵Ӳ
   趨ΪӦװͳԪ, ϴʱͨҪı
   ֹģʽ.
   
   еĲһСʽ򵥵. 趨һṹ
   struct termios, Ķ嵵 <asm/termbits.h>:
   
#define NCCS 19
struct termios {
        tcflag_t c_iflag;               /* ģʽ */
        tcflag_t c_oflag;               /* ģʽ */
        tcflag_t c_cflag;               /* ģʽ */
        tcflag_t c_lflag;               /* ģʽ */
        cc_t c_line;                    /* п (line discipline) */
        cc_t c_cc[NCCS];                /*  */
};

   Ҳе궨. ģʽ c_iflag ƹе봦
   , νװϴԪڻû read ܶȡǰȴ.
   ͬ c_oflag ƹе. c_cflag Ӳ趨,  , ÿ
   ԪλԪ, ֹͣλԪ, ȵ.. ģʽ c_lflag Ԫ
   Ӧ, ѶŻ͵ĳʽ, ȵ..  c_cc ж˵˵Ŀ
   Ԫ, ֹͣ, ȵ.. ԤĿԪֵ <asm/termios.h>. йϸ
   ʹֲ termios(3). termios ṹڵ c_line п (line
   discipline) Ԫ,  POSIX ݵϵͳʹ ע:˵ line
   discipline Ȼҷ п Ǻ˵. ֪뿴
   kernel :( .
   
2.3 װõ

   ĹҪ˵. ҪдӦóʽѡʺϵĹ. ʹ
   ûȦȡһԪִ. , Ԫ, Ҷ read 
   Բʾκδ.
   
  ׼
  
   ն˻ı׼,  dl ʽΪλͨѶҲ
   , Ҳ read ᴫһ. ԤֹԪ NL
   (ASCII LF), , ֹԪ. Ԥ軷, CR ( DOS/Windows Ԥ
   ֹ) ֹһе.
   
   ׼봦򻹿Դ , ɾ, ӡԪ, ת CR Ϊ NL 
   ȹ..
   
  Ǳ׼
  
   Ǳ׼Ҫÿζȡ̶Ԫ, ʹԪ
   ʱļʱ. ģʽڶȡ̶ԪӦóʽ, 
   װûͻȻͳԪ״.
   
  ͬʽ
  
   ģʽڷͬͬĴģʽ. Ԥͬģ
   ʽ¹, Ҳδȡ֮ǰ, read ״̬ᱻ. ͬģʽ
   read ״ֱ̬ӷزͳѶŵõĳʽֱɹ. Ѷſ
   ѶŵĴʽ handler....
   
  ȴԶѶԴ
  
   Ⲣһһģʽ. Ҫ͸вӲװõ
   , õ. ҵӦóʽұڼͬһʱ, ͸ TCP/IP
   socket вԵѶ. ʽȴ
   ͬԴѶ. һźԴ, ͻᱻ, ʽ
   ȴµѶ.
   
   ൱, ס Linux һ๤ҵϵͳ.
   select ϵͳвڵȴѶʱ CPU ؼ, û
   ȦʽȴѶŽʹͬʱִег̱.
   
3. ʽ

   еġԴ miniterm.c. The type ahead ݴ 255 Ԫ,
   ͸׼ִͬ (<linux/limits.h> 
   <posix1_lim.h>).
   
   οʽеעͲͬģʽʹ. ϣЩʽ붼ܱ
   . ׼ĳʽעд, ġֻڲͬ
   ĵطע.
   
   Ǻ, Լʵ, Ӧóʽ
   ѽ.
   
   ҪвȨ趨ȷ (Ҳ: chmod a+rw /dev/ttyS1)!
   
3.1 ׼

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

/* 趨 <asm/termbits.h>,  <termios.h>  */
#define BAUDRATE B38400
/* ȷв */
#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];
/*
  ݻװԶȡдԿ tty ģʽ
  Ϊǲʽͳ CTRL-C ͱɱ.
*/
 fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
 if (fd <0) {perror(MODEMDEVICE); exit(-1); }

 tcgetattr(fd,&oldtio); /* Ŀǰв趨 */
 bzero(&newtio, sizeof(newtio)); /* ṹԷµв趨ֵ */

/*
  BAUDRATE: 趨 bps ٶ. Ҳ cfsetispeed  cfsetospeed 趨.
  CRTSCTS : ϵӲ (ֻھ·¹
            ο Serial-HOWTO ߽)
  CS8     : 8n1 (8 λԪ, ͬλԪ,1 ֹλԪ)
  CLOCAL  : , ݻƹ
  CREAD   : ܽԪ
*/
 newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

/*
  IGNPAR  : ԾͬλԪ, λԪ
  ICRNL   :  CR Ӧ NL (Ѷ CR ʱֹ)
            ڲȻװ趨 raw ģʽ(û봦)
*/
 newtio.c_iflag = IGNPAR | ICRNL;

/*
 Raw ģʽ.
*/
 newtio.c_oflag = 0;

/*
  ICANON  : ܱ׼, ʹлӦͣ, ͳźԽóʽ
*/
 newtio.c_lflag = ICANON;

/*
  ʼеĿ
  Ԥֵ /usr/include/termios.h ҵ, עҲ,
  ⲻҪ
*/
 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;     /* ʹ÷ָԪļʱ */
 newtio.c_cc[VMIN]     = 1;     /* ڶȡ 1 Ԫǰֹͣ */
 newtio.c_cc[VSWTC]    = 0;     /* '\0' */
 newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */
 newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
 newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
 newtio.c_cc[VEOL]     = 0;     /* '\0' */
 newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
 newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
 newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
 newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
 newtio.c_cc[VEOL2]    = 0;     /* '\0' */

/*
  ݻ߲в趨
*/
 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);

/*
  ն˻趨, ڴѶ
  , һеĿʼ 'z' ˳˳ʽ.
*/
 while (STOP==FALSE) {     /* ȦǷֹѶ */
 /* ʹ볬 255 Ԫ, ȡĳʽλǻһֱȵսֲֹͣ.
    ԪȷڵԪ, ʣԪһζȡʱȡ.
    res Ԫ */
    res = read(fd,buf,255);
    buf[res]=0;             /* 趨ִֹԪ,  printf */
    printf(":%s:%d\n", buf, res);
    if (buf[0]=='z') STOP=TRUE;
 }
 /* شɵв趨ֵ */
 tcsetattr(fd,TCSANOW,&oldtio);
}

3.2 Ǳ׼

   ڷǱ׼ģʽ, ϲᱻϳһжĴ
   (, ɱ, ɾ, ȵ.) ʹ. ģʽܿƲ:
   c_cc[VTIME] 趨Ԫʱʱ,  c_cc[VMIN] 趨ȡܵ
   Ԫո.
   
    MIN > 0  TIME = 0, MIN 趨ΪȡܵԪո. 
    TIME  , Լʱʹ.
   
    MIN = 0  TIME > 0, TIME ʱ趨ֵ. ȡܵΪ
   ȡһԪ, ߳ TIME ʱ (t = TIME *0.1 s). 
   TIME ʱ, 򲻻ᴫκԪ.
   
    MIN > 0  TIME > 0, TIME һָԪļʱ. ȡ
   ܵΪ յ MIN Ԫ, Ԫļʱ䳬 TIME 
   ֵ. ʱÿһԪ¼ʱ, ֻڵһԪյ
   .
   
    MIN = 0  TIME = 0, ȡܾϱ. ĿǰڵԪ
   ,  شԪ.  Antonino (ο ) ˵, 
   fcntl(fd, F_SETFL, FNDELAY); ڶȡǰõͬĽ.
   
   ޸ newtio.c_cc[VTIME]  newtio.c_cc[VMIN] ģʽͿԲ
   .
   
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B38400
#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];

 fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
 if (fd <0) {perror(MODEMDEVICE); exit(-1); }

 tcgetattr(fd,&oldtio); /* Ŀǰв趨 */

 bzero(&newtio, sizeof(newtio));
 newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
 newtio.c_iflag = IGNPAR;
 newtio.c_oflag = 0;

 /* 趨ģʽ (Ǳ׼, Ӧ,...) */
 newtio.c_lflag = 0;

 newtio.c_cc[VTIME]    = 0;   /* ʹ÷ָԪʱ */
 newtio.c_cc[VMIN]     = 5;   /* ڶȡ 5 Ԫǰֹͣ */

 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);


 while (STOP==FALSE) {       /* Ȧ */
   res = read(fd,buf,255);   /*  5 Ԫἴ */
   buf[res]=0;               /*  printf... */
   printf(":%s:%d\n", buf, res);
   if (buf[0]=='z') STOP=TRUE;
 }
 tcsetattr(fd,TCSANOW,&oldtio);
}

3.3 ͬʽ

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

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX ϵͳ */
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

void signal_handler_IO (int status);   /* ѶŴ */
int wait_flag=TRUE;                    /* ûյѶŵĻͻ TRUE */

main()
{
  int fd,c, res;
  struct termios oldtio,newtio;
  struct sigaction saio;           /* definition of signal action */
  char buf[255];

  /* װΪ non-blocking (ȡܻϽ) */
  fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (fd <0) {perror(MODEMDEVICE); exit(-1); }

  /* ʹװ÷ͬǰ, װѶŴ */
  saio.sa_handler = signal_handler_IO;
  saio.sa_mask = 0;
  saio.sa_flags = 0;
  saio.sa_restorer = NULL;
  sigaction(SIGIO,&saio,NULL);

  /* гȥ SIGIO Ѷ*/
  fcntl(fd, F_SETOWN, getpid());
  /* ʹake the file descriptor ͬ (ʹֲ˵ֻ O_APPEND 
  O_NONBLOCK,  F_SETFL Ҳ...) */
  fcntl(fd, F_SETFL, FASYNC);

  tcgetattr(fd,&oldtio); /* Ŀǰв趨ֵ */
  /* 趨µвΪ׼ */
  newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR | ICRNL;
  newtio.c_oflag = 0;
  newtio.c_lflag = ICANON;
  newtio.c_cc[VMIN]=1;
  newtio.c_cc[VTIME]=0;
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);

  /* ȴѶŵĻȦ. ܶõǽ */
  while (STOP==FALSE) {
    printf(".\n");usleep(100000);
    /* յ SIGIO , wait_flag = FALSE, ѶŴԱȡ */
    if (wait_flag==FALSE) {
      res = read(fd,buf,255);
      buf[res]=0;
      printf(":%s:%d\n", buf, res);
      if (res==1) STOP=TRUE; /* ֻ CR ֹͣȦ */
      wait_flag = TRUE;      /* ȴµѶ */
    }
  }
  /* شɵв趨ֵ */
  tcsetattr(fd,TCSANOW,&oldtio);
}

/***************************************************************************
* ѶŴ. 趨 wait_flag Ϊ FALSE, ʹĻȦܽԪ          *
***************************************************************************/

void signal_handler_IO (int status)
{
  printf("received SIGIO signal.\n");
  wait_flag = FALSE;
}

3.4 ȴԶѶԴ

   һκܶ. ֻܱдʽʱʾ, ʡʽҲܼ. 
   ֻв, ڱɵʹõװ.
   
   select мľ޼ fd_set. fd_set һ λԪ,
   ÿһλԪһЧĵṹ. select нһЧĵ
   ṹ fd_set λԪ, λԪĳһλԪΪ 1, 
   ʾӳĵṹĵ, ¼. Щ޼
   ṩд fd_set Ĺ. ɲοֲ select(2).
   
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

main()
{
   int    fd1, fd2;  /* Դ 1  2 */
   fd_set readfs;    /* ṹ趨 */
   int    maxfd;     /* õĵṹ */
   int    loop=1;    /* Ȧ TRUE ʱ */

   /* open_input_source һװ, ȷ趨в,
      شش˵ṹ */
   fd1 = open_input_source("/dev/ttyS1");   /* COM2 */
   if (fd1<0) exit(0);
   fd2 = open_input_source("/dev/ttyS2");   /* COM3 */
   if (fd2<0) exit(0);
   maxfd = MAX (fd1, fd2)+1;  /* λԪ (fd) */

   /* Ȧ */
   while (loop) {
     FD_SET(fd1, &readfs);  /* Դ 1 */
     FD_SET(fd2, &readfs);  /* Դ 2 */
     /* block until input becomes available */
     select(maxfd, &readfs, NULL, NULL, NULL);
     if (FD_ISSET(fd1))         /* Դ 1 Ѷ */
       handle_input_from_source1();
     if (FD_ISSET(fd2))         /* Դ 2 Ѷ */
       handle_input_from_source2();
   }

}

   ʽڵȴѶųǰ, ȷͣ. Ҫ
   ʱʱ, ֻ select л:
   
int res;
struct timeval Timeout;

/* 趨Ȧʱֵ */
Timeout.tv_usec = 0;  /*  */
Timeout.tv_sec  = 1;  /*  */
res = select(maxfd, &readfs, NULL, NULL, &Timeout);
if (res==0)
/* ṹ input = 0 ʱ, ᷢʱ. */

   ʽ 1 ʱ. ʱ, select ᴫ 0, Ӧ
   Timeout ʱݼ select ȴѶŵʱΪ׼. ʱֵ
    0, select Ͻ.
   
4. Դ

     * Linux Serial-HOWTO 趨вصӲѶ.
     *  Michael Sweet д [8]Serial Programming Guide for POSIX
       Compliant Operating Systems. Ѿķ˵Ҳλ
       ַ. ֪ҵ? Ǻܰļ!
     * termios(3) ʹֲ. й termios ṹ.
       
5. 

   ͸˵һ, Ҳר, Լ, ͸
   ˵İҵ. л European Transonic Windtunnel  Strudthoff
   , Cologne, Michael Carter (mcarter@rocke.electro.swri.edu), 
   Peter Waltenberg (p.waltenberg@karaka.chch.cri.nz)
   
   ͬʱ׼ļ Antonino Ianella (antonino@usa.net ׭д
   Serial-Port-Programming Mini HOWTO. Greg Hankins ҪҰ Antonino's
   Mini-HOWTO һļ.
   
   ļĽṹ SGML ĸʽԴ Greg Hankins  Serial-HOWTO. л
   Dave Pfaltzgraff (Dave_Pfaltzgraff@patapsco.com), Sean Lincolne
   (slincol@tpgi.com.au), Michael Wiedmann (mw@miwie.in-berlin.de), 
   Adrey Bonar (andy@tipas.lt) Э.

References

   1. mailto:Peter.Baumann@dlr.de
   2. mailto:yytseng@ms16.hinet.net
   3. mailto:linux-howto@sunsite.unc.edu
   4. ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO
   5. http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html
   6. news:comp.os.linux.answers
   7. mailto:Peter.Baumann@dlr.de
   8. http://www.easysw.com/~mike/serial
