시리얼 통신 프로그램을 한번 짜봤습니다.
ttyS0(COM1)을 이용하여 상대방 터미널과 서로 문자를 주고 받는 것입니다.
이른바 Full-duplex 통신입니다.

콘솔에서의 문자입력은 thread로 돌리고, COM port쪽의 입력이 메인에 들어가 있습니다.
나중에는 이부분도 thread로 빼야하지 않나 싶습니다.
일단 콘솔입력은 blocking이 되는 문제 때문에 일단, thread에서 queue로 값을 넣어주고,
메인 부분에서 queue를 검사해서 값을 가져옵니다.

수신 확인은 SIGIO의 메시지를 통한 처리를 하였습니다.
그리고 여기서 주의 할 것이 있는데.

Asyncmode로 해서 아래 설정을 쓰면, 두자보내고 죽어버립니다.
fcntl( fd, F_SETFL, FASYNC ); //Program stall
근데 알아보니 signal 을 사용하려면은 반드시 ASYNC로 해야한다는군요.
때문에 죽어버리는 이유를 분석했습니다.
결과는, 수신 시그널뿐만 아니라 송신 시그널도 같이 잡아버린다는 것입니다.
아직까지 시그널 자체가 송신인지 수신인지를 구별할 방법이 없어서,
시그널이 들어오면 수신이 아니라도 read에서 blocking이 안되도록 변경하였습니다.
나중에 수신인지 송신인지 구별해주는 변수나 함수를 찾아봐야겠습니다.


그리고, tty상에 글자를 뿌릴 때 주의사항입니다.
아무래도 라인프린터 개념이기 때문에, '\n'이 없으면 화면에 뿌려지지 않게 됩니다.
내부에 버퍼링만 하는 것이지요.

때문에 라인피드가 없는 상황에서 화면에 글자를 표시하려면, 'fflush(stdout)'을 해주어야 합니다.
매 캐랙터마다 한다면 성능이 많이 떨어지겠지요.

이란 아래 소스는 잘 동작하는 것 까지 확인하였습니다.

p.s. 노란바탕의 주의할 부분입니다.
saio.sa_mask=0; 으로 하는 것은 이후 버젼에서 에러를 발생합니다.
뒷 버젼에서 확장되면서, 단순히 정수가 아닌 다른 사이즈로 변경된 듯 합니다.
때문에 sigemptyset()이라는 함수를 써서 클리어 시켜줘야만합니다.

int tt_serial(void)
{
int fd;
int res;
char buf[255];
struct sigaction saio;
struct termios oldtio,newtio;
fd=open(MODEMDEVICE,O_RDWR | O_NOCTTY); // | O_NONBLOCK);
if(fd<0) {
perror( MODEMDEVICE );
exit(-1);
}
saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask); //saio.sa_mask =0;
saio.sa_flags=0;
saio.sa_restorer=NULL;
sigaction( SIGIO, &saio, NULL );
fcntl( fd, F_SETOWN, getpid() );
fcntl( fd, F_SETFL, FASYNC ); //Program stall. but mandatory when using SIGIO.
tcgetattr( fd, &oldtio );
newtio.c_cflag=BAUDRATE|CRTSCTS|CS8|CLOCAL|CREAD;
newtio.c_iflag=IGNPAR|ICRNL;
newtio.c_oflag=0;
newtio.c_lflag=0; //ICANON; -if ICANON,receive not available
newtio.c_cc[VMIN] =1;
newtio.c_cc[VTIME]=0;
tcflush( fd, TCIFLUSH );
tcsetattr( fd, TCSANOW, &newtio );
while(STOP==FALSE) {
int ch;
if(wait_flag==FALSE) {
int i;
{
#if 0
res=read(fd,buf,255); <--송신 signal에 의해 정지해버림
#else
newtio.c_cc[VMIN] = 0; <--최소 '0'글자를 받을 수 있도록
newtio.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &newtio);
res = read(fd, buf, 255); <--수신의 경우에 처리하나 송신이 발생해도 패스해버림
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &newtio);
#endif
}
for(i=0;i<res;i++) {
ch=buf[i];
printf("%c",ch);
}
wait_flag=TRUE;
}
ch=qout(&uartq);
if(ch>0) {
buf[0]=ch;
if(write(fd,buf,1)<=0) {
printf("Write Error!!!!\n");
break;
}
usleep(1000);
}
else {
printf(".");
fflush(stdout);
usleep(100000);
}
}
tcsetattr( fd, TCSANOW, &oldtio );
return 0;
}


Posted by 벅스바니
,