본문 바로가기
C++ 200제/코딩 IT 정보

리눅스 Linux 간단한 시리얼 통신 프로그램 예제 소스

by vicddory 2018. 12. 7.

리눅스 Linux 간단한 시리얼 통신 프로그램 예제 소스



윗분이 알려주신 사이트로 이동해 봅시다. 정말 작고 간단한 Linux 시리얼 통신 프로그램 사이트가 보입니다.



이동하면 아래와 같은 글이 보입니다.


Download : com.c [링크]

Building : cc -o com com.c

Usage   : ./com /dev/device [speed]

Example : ./com /dev/ttyS0 [115200]

Keys    : Ctrl-A - exit, Ctrl-X - display control lines status


Tiny serial terminal - 실행 화면[Tiny serial terminal - 실행 화면]


Tiny serial terminal[Tiny serial terminal]

간단한 사용 방법에 대한... 즉, 시리얼 통신 프로그램 메뉴얼에 해당합니다. 

Linux 전용 소스 전문을 살펴봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
 
int transfer_byte(int from, int to, int is_control);
 
typedef struct {char *name; int flag; } speed_spec;
 
 
void print_status(int fd) {
    int status;
    unsigned int arg;
    status = ioctl(fd, TIOCMGET, &arg);
    fprintf(stderr, "[STATUS]: ");
    if(arg & TIOCM_RTS) fprintf(stderr, "RTS ");
    if(arg & TIOCM_CTS) fprintf(stderr, "CTS ");
    if(arg & TIOCM_DSR) fprintf(stderr, "DSR ");
    if(arg & TIOCM_CAR) fprintf(stderr, "DCD ");
    if(arg & TIOCM_DTR) fprintf(stderr, "DTR ");
    if(arg & TIOCM_RNG) fprintf(stderr, "RI ");
    fprintf(stderr, "\r\n");
}
 
int main(int argc, char *argv[])
{
    int comfd;
    struct termios oldtio, newtio;//place for old and new port settings for serial 리눅스 port
    struct termios oldkey, newkey;//place tor old and new port settings for keyboard teletype
    char *devicename = argv[1];
    int need_exit = 0;
    speed_spec speeds[] =
    {
        {"1200", B1200},
        {"2400", B2400},
        {"4800", B4800},
        {"9600", B9600},
        {"19200", B19200},
        {"38400", B38400},
        {"57600", B57600},
        {"115200", B115200},
        {NULL0}
    };
    int speed = B9600;
 
    if(argc < 2) {
        fprintf(stderr, "example: %s /dev/ttyS0 [115200]\n", argv[0]);
        exit(1);
    }
 
    comfd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (comfd < 0)
    {
        perror(devicename);
        exit(-1);
    }
 
    if(argc > 2) {    
        speed_spec *s;
        for(s = speeds; s->name; s++) {
            if(strcmp(s->name, argv[2]) == 0) {
                speed = s->flag;
                fprintf(stderr, "setting speed %s\n", s->name);
                break;
            }
        }
    }
 
    fprintf(stderr, "C-a exit, C-x modem lines status\n");
 
    tcgetattr(STDIN_FILENO,&oldkey);
    newkey.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
    newkey.c_iflag = IGNPAR;
    newkey.c_oflag = 0;
    newkey.c_lflag = 0;
    newkey.c_cc[VMIN]=1;
    newkey.c_cc[VTIME]=0;
    tcflush(STDIN_FILENO, TCIFLUSH);
    tcsetattr(STDIN_FILENO,TCSANOW,&newkey);
 
 
    tcgetattr(comfd,&oldtio); // save current port settings 
    newtio.c_cflag = speed | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;
    newtio.c_cc[VMIN]=1;
    newtio.c_cc[VTIME]=0;
    tcflush(comfd, TCIFLUSH);
    tcsetattr(comfd,TCSANOW,&newtio);
 
    print_status(comfd);
 
    while(!need_exit) {
        fd_set fds;
        int ret;
        
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds);
        FD_SET(comfd, &fds);
 
 
        ret = select(comfd+1&fds, NULLNULLNULL);
        if(ret == -1) {
            perror("select");
        } else if (ret > 0) {
            if(FD_ISSET(STDIN_FILENO, &fds)) {
                need_exit = transfer_byte(STDIN_FILENO, comfd, 1);
            }
            if(FD_ISSET(comfd, &fds)) {
                need_exit = transfer_byte(comfd, STDIN_FILENO, 0);
            }
        }
    }
 
    tcsetattr(comfd,TCSANOW,&oldtio);
    tcsetattr(STDIN_FILENO,TCSANOW,&oldkey);
    close(comfd);
 
    return 0;
}
 
 
int transfer_byte(int from, int to, int is_control) {
    char c;
    int ret;
    do {
        ret = read(from, &c, 1);
    } while (ret < 0 && errno == EINTR);
    if(ret == 1) {
        if(is_control) {
            if(c == '\x01') { // C-a
                return -1;
            } else if(c == '\x18') { // C-x
                print_status(to);
                return 0;
            }
        }
        while(write(to, &c, 1== -1) {
            if(errno!=EAGAIN && errno!=EINTR) { perror("write failed"); break; }
        }
    } else {
        fprintf(stderr, "\nnothing to read. probably port disconnected.\n");
        return -2;
    }
    return 0;
}
cs


다시 정리하면, 


1
2
3
$ gcc -o com com.c (컴파일)
 
$ ./com /dev/ttyUSB0 115200 (실행)
cs


일반적인 리눅스 gcc를 이용하면 됩니다.

시리얼 통신 프로그램을 실행할 땐, Baudrate를 인자로 넘겨주면 됩니다. 그렇지만 하나 아쉬운 게 있는데요. Linux 환경에선 캡쳐가 안 되기에 원래 글을 쓰셨던 분은 아래처럼 수정하셨습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int transfer_byte(int from, int to, int is_control)
{
    char c;
    int ret;
    do
    {
        ret = read(from, &c, 1);
    } while (ret < 0 && errno == EINTR);
    if (ret == 1)
    {
        if (is_control)
        {
            if (c == '\x01')
            { // C-a
                return -1;
            }
            else if (c == '\x18')
            { // C-x
                print_status(to);
                return 0;
            }
        }
        while (write(to, &c, 1== -1)
        {
            if (errno != EAGAIN && errno != EINTR)
            {
                perror("write failed");
                break;
            }
        }
 
        /*
         * send also to stdout.
         */
        if(to == STDIN_FILENO)
        {
            while (write(STDOUT_FILENO, &c, 1== -1)
            {
                if (errno != EAGAIN && errno != EINTR)
                {
                    perror("write failed");
                    break;
                }
            }
        }
    }
    else
    {
        fprintf(stderr, "\nnothing to read. probably port disconnected.\n");
        return -2;
    }
    return 0;
cs


이정도로 간단한 Serial 통신 프로그램 소개합니다. 짧은 소스지만 핵심 부분은 모두 들어가서 간단한 테스트 용도로는 모자람이 없습니다.


리눅스 Linux 간단한 시리얼 통신 프로그램 예제 소스

댓글