(linux serial programming 질문) data가 한번에 전송되지않는

iamsjkim의 이미지

리눅스에서 RS-232c로 데이타를 주고받는 코드를 짜고 있습니다.
raw input/output모드로 주고받아야 하고 코드는 대략 다음과 같습니다.
(아래 코드는 read하는 쪽이고 write하는 쪽 코드도 세팅은 완전히 똑같습니다.)

문제는 8bytes이하의 데이타가 전송될때는 문제없이 주고 받는데, 일단 데이타의 크기가 20 bytes정도 이상으로 커지면 한번에 read하질 못하고 8, 9, 3 bytes씩 읽어냅니다.
다시 말하면, 20bytes를 전송하면 반대쪽에서 signal_handler_IO()함수가 세번 불려지고, interrupt_num>0인동안 계속 read()하도록 코드를 작성했기때문에 세번 read()를 하는데, 각각 8 bytes, 9 bytes, 3 bytes씩 읽어들입니다.
printf해보니 결국 세개를 합치면 원래 전송된 데이타가 맞긴한데-_-
문제는 제가 코딩하는 프로그램에서는 반드시 한번에 받아야 에러없이 진행될수 있기에....ㅠ_ㅠ;;;;

포트 세팅도 이것저것 바꿔봤지만 아래와 같은 세팅 외에는 데이타를 받는것조차도 못하게 되곤 해서, 어떻게해야 한번에 읽어낼 수 있을지 모르겠습니다.

아시는 분 계시면 답변 부탁드리겠습니다..
(_ _)~

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/stat.h>

#define _POSIX_SOURCE 1
#define MODEMDEVICE "/dev/ttyS1" 

int interrupt_num = 0;

void signal_handler_IO(int stat);

int main()
{
		int res;
		unsigned char buf[MAXDATASIZE];
		
		int fd;
		struct termios newtio;
		struct sigaction saio; /* signal action */

		/* Port OPEN */
		fd = open(MODEMDEVICE,O_RDWR|O_NOCTTY|O_NDELAY);
		if(fd<0)
		{
			printf("fd open ERROR!\n");
			return 0;
		}
printf("port open seccess : fd = %d\n",fd);

		/* install the signal handler */
		saio.sa_handler = signal_handler_IO;
		sigemptyset(&saio.sa_mask);
		saio.sa_flags = 0;
		saio.sa_restorer = NULL;
		sigaction(SIGIO,&saio,NULL);

		/* signal SIGIO ON */
		fcntl(fd,F_SETOWN,getpid());
		/* make fd async */
		fcntl(fd,F_SETFL,FASYNC);

		/* port setting */
		tcgetattr(fd,&newtio);
		cfsetispeed(&newtio,B9600);
		cfsetospeed(&newtio,B9600);
		newtio.c_cflag |= (CLOCAL|CREAD|CS8);
		newtio.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
		tcflush(fd,TCIFLUSH);
		tcsetattr(fd,TCSANOW,&newtio);

                                ..................
                                ..................
              while(1)
               {
               while(interrupt_num > 0){
							res = read(fd,buf,MAXDATASIZE);
                     interrupt_num -= 1;
                                     .................
                 }
                 ................
                }
}
/*****************************************************************************************
 * 								signal_handler_IO()
 *****************************************************************************************/
void signal_handler_IO(int stat)
{
	printf("received SIGIO signal.\n");
	interrupt_num += 1;
}

bugiii의 이미지

아마도 소켓과 비슷하게 read 가 되는 모양입니다.
일정량까지 받는 함수를 하나 만드시는 것이 어떨까요?
만약 반대쪽을 수정할 수 있는 상황이라면 패킷 구조로 가는 것이 좋을 것이고 이렇게 해야 에러에도 대응할 수 있을 것입니다.
그럼, 이만...

vacancy의 이미지

앞에 패킷 길이를 달아 보내는 정도만 해주셔도 괜찮잖을까요. ;;

지리즈의 이미지

문제는 통신딜레이입니다.

전송이 다 돼지 않은 상태에서 버퍼에서 계속 읽어드려서 그렇지요...

여러 해결방법이 있는데..
feed back방식일 경우(이쪽에서 어떤 것에 대해 질의를 하고 응답을 기다리는 방식)일 경우 딜레이를 주어서 버퍼에서 읽어오는 겁니다.
경험에 의존하면 되는데... 상대 장치의 응답시간까지 고려해야 함으로 딜레이가 길어질 수도 있습니다. 보통(300밀리세컨드)

다른 방법은 stx etx를 이용하는 방법입니다.
뭐 소프트웨어 흐름제어의 일종이라고 할까..
패킷의 시작을 의미하는 stx 문자열(보통 ASC 2)과
패킷의 끝을 의미하는 etx문자열(보통 ASC 3)사이에 패킷을 보내는 것지요.
받는 쪽에서는
무한 루프를 돌면서 버퍼에서 계속 읽어 드리는 쓰레드가 있고
이 쓰레드는 메세지 내용을 감시하다가
stx를 만나서 etx로 끝나면 메세지가 도착한 걸로 하고 다음 루프로 점프하거나
콜백함수를 호출하는 방식이지요...
stx는 사용하지 않고 etx만 사용하는 경우도 많지요(ex, Cr+Lf= 13,10 or 10,13)

리눅스에서는 코딩을 잘 안해서 모르겠는데...
하드웨어 흐름제어를 이용하거나 운영체제에서 지원하는 소프트웨어 흐름제어를 이용하는 방법도 있을 겁니다. 아마 콜백함수로 메세지를 받아 올 겁니다.

아 참 또 한가지는 좀 위험하긴 한데...
stx,etx없이 메세지를 보내고...
버퍼를 계속읽어 들이다가 버퍼에서 읽어 온 메세지의 길이가 0이면,
메세지가 다 도착한 걸로 여기고 다음 단계로 넘어가는 겁니다.
단 메세지를 다 읽어드리기 전에 다음 메세지가 도착하면,
메세지 여러개가 붙어 올 수도 있는 문제가 발생하는데...
메세지의 발생빈도가 통식속도 및 처리속도에 훨씬 못 미친다면...
약간은 간단하게 구현할 수 있지요...

serial 통신 코딩하다 보면... 늘 느끼는 건데...
정말 tcp/ip 편리하다는 겁니다.

There is no spoon. Neo from the Matrix 1999.

iamsjkim의 이미지

답변주신 분들 정말 감사드립니다..ㅠ.ㅠ

read()하기전에 usleep(300000)정도 줬더니 8bytes정도까지는 문제가 없고 usleep(700000)정도 맞췄더니 20bytes정도까지 받네요.
너무 기뻐서 눈물이 주루룩ToT

정말이지.. tcp/ip소켓이 얼마나 편한건지 절실히 느끼는 중입니다.

다시한번 감사드립니다..
(_ _)(^0^)꾸벅

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.