코드만 한번 봐주세요..

leolo의 이미지

이 코드는
/dev/ttyS0에서 쓴 데이터를 /dev/ttyS1에서 읽어 파일에 쓰는
코드입니다.
한번 보시고 문제될 만한 부분이 있는지 봐주세요..

먼저, ttyS0에 쓰는 코드는 다음과 같습니다.
buff에는 '0', '1', '3', '4', ... '9', 'CR', 'LF' 이렇게 해서 데이터를 넣었습니다.

/******************************
 * "/dev/ttyS0"
 * RS232 interface write Data.
 ******************************/

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#include "serial.h"
#include "buf.h"

int serial_open(const char *device, int baud, int flow)
{
    int fd;
    static long baudrate;
    struct termios tio;
    
    fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK , 0644);
    if(fd < 0) {
        dbg("Can't open device %s\n", device);
        return -1;
    } else {
        dbg("Open %s Device, fd %d : \n", device, fd);
        
        bzero(&tio, sizeof(tio));
        
        switch(baud) {
            case 9600:
                baudrate = B9600;
                break;
            case 115200:
                baudrate = B115200;
                break;
            case 19200:
                baudrate = B19200;
                break;
            default :
                dbg("Can't define %d\n", baud);
                close(fd);
                exit(0); 
        }  /* end switch */

        tio.c_cflag &= ~CSIZE; 
        tio.c_cflag |= CS8;                          /* 8 data bit    */
        tio.c_cflag &= ~CSTOPB;                      /* 1 stop bit    */
        tio.c_cflag &= ~(PARENB | PARODD);           /* no parity bit */

        if(flow){
            tio.c_cflag |= CRTSCTS;   /* h/w flow control */
        }
        else{
            tio.c_cflag &= ~CRTSCTS;  /* no flow control */
        }
        
        if((cfsetispeed(&tio, baudrate) < 0 || cfsetospeed(&tio, baudrate) < 0)){  /* baudrate set */
            dbg("Can't set baudrate\n");
            close(fd);
            return -1;
        } else {
            if(tcsetattr(fd, TCSANOW, &tio) < 0){     /* termios set */
                dbg("Can't set Termios struct\n");
                close(fd);
                return -1;
            } else {
                if(tcflush(fd, TCIOFLUSH) < 0){
                    close(fd);
                    return -1;
                }   
            } 
        }
   }
   return fd;
}

int serial_write(int fd, char *buf, int size)
{
    int t = 0;
    int ones;
    int writesize;

    writesize = size;
    while(writesize > 0) {
        ones = write(fd, buf, writesize);
        if(ones <= 0) {
            if(!(errno == EINTR || errno == EAGAIN)){
                dbg("Error write serail : %d\n", errno);
                break;
            }
        } else {
            buf += ones;
            writesize -= ones;
            t += ones;
        }
    }
    return t;   
}
int usage(const char *device)
{
    printf("serial_write - RS232 write Data. copyright(c)2003 by leolo\n");
    printf("description : RS232(%s) write data\n", device);
    printf("serial_write baudrate <flow/none> byte count time\n");
    exit(0);
}
int main(int argc, char *argv[])
{
    int baud;
    int flow;
    int fd;
    int n;
    const char *device = "/dev/ttyS0";
    int size;
    int tdata = 0;
    int cnt;
    int time;

    if(argc != 6)
        usage(device);

    baud = atoi(argv[1]);
    if(strncmp(argv[2], "flow", 4) == 0)
        flow = 1;         /* h/w flow control */
    else 
        flow = 0;         /* no flow  control */
    size = atoi(argv[3]);
    cnt = atoi(argv[4]);
    time = atoi(argv[5]);
    
    fd = serial_open(device, baud, flow);    
    while(cnt){
        usleep(time*1000);
        n = serial_write(fd, buf, size);
        tdata += n;
        dbg("Send data total %d\n", tdata);
        cnt--;
    }
    close(fd); 
    return 0;
}

읽고 파일에 쓰는 코드는 다음과 같습니다.

/******************************
 * "/dev/ttyS1"
 * RS232 interface read Data.
 ******************************/

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#include "serial.h"

int serial_open(const char *device, int baud, int flow)
{
    int fd;
    static long baudrate;
    struct termios tio;
    
    fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK , 0644);
    if(fd < 0) {
        dbg("Can't open device %s\n", device);
        return -1;
    } else {
        dbg("Open %s Device, fd %d : \n", device, fd);
        
        bzero(&tio, sizeof(tio));
        
        switch(baud) {
            case 9600:
                baudrate = B9600;
                break;
            case 115200:
                baudrate = B115200;
                break;
            case 19200:
                baudrate = B19200;
                break;
            default :
                dbg("Can't define %d\n", baud);
                close(fd);
                exit(0); 
        }  /* end switch */

        tio.c_cflag &= ~CSIZE; 
        tio.c_cflag |= CS8;                          /* 8 data bit    */
        tio.c_cflag &= ~CSTOPB;                      /* 1 stop bit    */
        tio.c_cflag &= ~(PARENB | PARODD);           /* no parity bit */
        tio.c_cflag |= CREAD;

        if(flow){
            tio.c_cflag |= CRTSCTS;   /* h/w flow control */
        }
        else{
            tio.c_cflag &= ~CRTSCTS;  /* no flow control */
        }
        
        if((cfsetispeed(&tio, baudrate) < 0 || cfsetospeed(&tio, baudrate) < 0)){  /* baudrate set */
            dbg("Can't set baudrate\n");
            close(fd);
            return -1;
        } else {
            if(tcsetattr(fd, TCSANOW, &tio) < 0){     /* termios set */
                dbg("Can't set Termios struct\n");
                close(fd);
                return -1;
            } else {
                if(tcflush(fd, TCIOFLUSH) < 0){
                    close(fd);
                    return -1;
                }   
            } 
        }
   }
   return fd;
}

int serial_write(int fd, char *buf, int size)
{
    int t = 0;
    int ones;
    int writesize;

    writesize = size;
    while(writesize > 0) {
        ones = write(fd, buf, writesize);
        if(ones <= 0) {
            if(errno == EINTR || errno == EAGAIN){
                dbg("Error write serail : %d\n", errno);
                exit(0);
            }
        } else {
            buf += ones;
            writesize -= ones;
            t += ones;
        }
    }
    return t;   
}

int serial_read(int fd, char *buff, int size)
{
    fd_set rfds;    
    int filefd;
    int result, isread, readsize;

    char buffer[2048];

    filefd = open("./serial.out", O_RDWR | O_CREAT | O_TRUNC, 0644);
    while(1){
        FD_ZERO(&rfds); 
        FD_SET(fd, &rfds); 
        printf("select pending\n");
        result = select(fd + 1, &rfds, (fd_set *)0, (fd_set *)0, NULL); 
        if(result <= 0){
            dbg("select error\n");
            exit(0);
        }

        isread = FD_ISSET(fd, &rfds); 
        if(result > 0 && isread != 0){ 
            memset(buffer, '\0', sizeof(buffer));
            readsize = read(fd, buffer, size); 
            if(readsize > 0) { 
                printf("read data %d byte ->  %s\n", readsize,  buffer); 
                write(filefd, buffer, readsize);
            } else { 
                if(readsize <= 0){
                    dbg("Can't read\n"); 
                    exit(0);
                 }
                break; 
            } 
        } else {
            close(filefd);
            break; 
        }
    }
    return -1;
}

int main(int argc, char *argv[])
{
    int baud;
    int flow;
    int fd;
    int n;
    char *buf;

    const char *device = "/dev/ttyS1";
    int size = 2048;
    bzero(buf, sizeof(buf));

    flow = 0;      /* h/w flow control */
    baud = 9600;   /* baud rate        */
 
    fd = serial_open(device, baud, flow);   
    n = serial_read(fd, buf, size);    
    close(fd); 
    return 0;
}

/dev/ttyS0에 쓰는 코드를 보시면,
일정한 간격으로 usleep하면서 쓰고 있습니다.
이렇게 하면 일정한 간격으로 데이타가 써지는지 알고 싶습니다.
다음으로 읽고 파일(serial.out)에 쓰는 코드가 정확한지 알고 싶습니다.

위와 같이 코드를 짜고 돌리면.. 잘 돌아갑니다.
아무 문제 없이.. 그런데.. 한가지 의문이 있습니다.
baud rate를 9600으로 한 것과 115200으로 한 것이 차이가 납니다.
물론, 당연히 나겠죠..
./serial_write 9600 none 20000 10 1000 으로 실행하면, 즉, 9600, none flow control, 2000byte, 10번, 1000(1초) 간격으로 쓰는거와.
115200으로 쓰는 것의 차이가 좀 이상합니다.

9600은 중간에 데이터가 손실 되는데.. 115200은 중간에 데이터 손실이 없습니다. 참고로, 저는 이것을 무선 통신을 통해 데이터를 전송했습니다.
baud rate가 정확히 어떻게 동작하는지.. 알고 싶습니다.

leolo의 이미지

struct termios tio;
static long baudrate;
bzero(&tio, sizeof(tio));

.....
tio.c_cflag |= B115200;
....

이렇게 세팅하고..
올바른지 확인하기 위해..
printf("%d\n", cfgetispeed(&tio))
이렇게 하고 찍어보니까? 4098이 나오네요..
원래 이런건가요.. 제대로 된건지.. 통.. 모르겠네요..

실력이 있으면 삶이 편하다... 영차 영차...

mach의 이미지

leolo wrote:

./serial_write 9600 none 20000 10 1000 으로 실행하면, 즉, 9600, none flow control, 2000byte, 10번, 1000(1초) 간격으로 쓰는거와.
115200으로 쓰는 것의 차이가 좀 이상합니다.

9600은 중간에 데이터가 손실 되는데.. 115200은 중간에 데이터 손실이 없습니다.

다음 2가지가를 고려해봅니다.
1) 9600bps에서 최대 CPS(초당 전송 문자수)를 고려보셨나요? DTE수준에서 압축프로토콜등을 지원한다면 모르지만, 2000바이트라......

2) 읽을때는 select()를 사용하여 이벤트에 기반해서 프로그램했는데, 쓸때도 해보심이 좋을 듯 합니다..

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.