|
|
1.1 root 1: #include "header.h"
2: #include "autofd.h"
3: #include "kevent.h"
4: #include <queue>
5: #include <string>
6: #include <vector>
7: #include <err.h>
8: #include <fcntl.h>
9: #include <stdio.h>
10: #include <stdint.h>
11: #include <stdlib.h>
12: #include <termios.h>
13: #include <time.h>
14: #include <unistd.h>
15:
16:
17: //#define DEFAULT_DEV "/dev/ttyS0"
18: #define DEFAULT_DEV "/dev/dty00"
19:
20: // ナノ秒に対するスケール。
21: // ミリ秒単位になるようなスケール値とする
22: #define DEFAULT_TIMESCALE (1000LL * 1000LL)
23:
1.1.1.2 ! root 24: static long timescale = DEFAULT_TIMESCALE;
! 25: static bool opt_n = false;
1.1 root 26:
27: [[noreturn]]
1.1.1.2 ! root 28: static void
1.1 root 29: usage()
30: {
31: printf(
32: "%s [-d devname] [-t timescale] file\n"
33: " -d devname: tty device (default:" DEFAULT_DEV ")\n"
34: " -t timescale: timescale factor (default:%lld)\n"
35: " -n: no transeive mode\n",
36: getprogname(),
37: DEFAULT_TIMESCALE
38: );
39: exit(1);
40: }
41:
1.1.1.2 ! root 42: static void
1.1 root 43: Do(FILE *fp, int tty_fd)
44: {
45: autofd kq;
46: struct kevent kev;
47: timespec timeout;
48: int msec;
49: int wait;
50: int64 t;
51: int r;
52:
53: std::queue<uint8> sbuf;
54: std::vector<uint8> rbuf;
55:
56: kq = kqueue();
57: if (kq == -1) {
58: err(1, "kqueue");
59: }
60:
61: if (tty_fd >= 0) {
1.1.1.2 ! root 62: r = kevent_add(kq, tty_fd, EVFILT_READ, EV_ADD, 0);
1.1 root 63: if (r == -1) {
1.1.1.2 ! root 64: err(1, "kevent_add(READ)");
1.1 root 65: }
1.1.1.2 ! root 66: r = kevent_add(kq, tty_fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 1);
1.1 root 67: if (r == -1) {
1.1.1.2 ! root 68: err(1, "kevent_add(WRITE)");
1.1 root 69: }
70: }
71:
72: // 受信タイムアウトデフォルト 100msec
73: int64 recv_timeout = 1 * 100 * 1000 * 1000;
74:
75: char buf[1024];
76: bool complete = false;
77: bool prompt = true;
78: bool writable = true;
79:
80: for (;;) {
81: if (prompt && !complete) {
82: if (fgets(buf, sizeof(buf), fp) != NULL) {
83: if (strncmp(buf, "#", 1) == 0) {
84: printf("%s", buf);
85: continue;
86: }
87: // ウェイト時間はデフォルトでミリ秒で指定
88: if (sscanf(buf, "@%d", &wait)) {
89: t = wait * timescale;
90: timeout.tv_sec = t / (1000 * 1000 * 1000);
91: timeout.tv_nsec = t % (1000 * 1000 * 1000);
92: nanosleep(&timeout, NULL);
93: continue;
94: } else if (sscanf(buf, "@R%d", &msec)) {
95: // 受信タイムアウト変更
96: recv_timeout = msec * 1000 * 1000;
97: continue;
98: } else {
99: for (char *p = buf; *p; p++) {
100: if (*p == '\n') {
101: sbuf.push('\r');
102: } else {
103: sbuf.push(*p);
104: }
105: }
106: prompt = false;
107: }
108: } else {
109: complete = true;
110: }
111: }
112:
113: if (writable && sbuf.size() > 0) {
114: buf[0] = sbuf.front();
115: sbuf.pop();
116: r = write(tty_fd, buf, 1);
117: if (r <= 0) {
118: err(1, "tty_fd write");
119: }
120: writable = false;
121: }
122:
123: t = recv_timeout;
124: timeout.tv_sec = t / (1000 * 1000 * 1000);
125: timeout.tv_nsec = t % (1000 * 1000 * 1000);
126:
127: r = kevent_poll(kq, &kev, 1, &timeout);
128: if (r == -1) {
129: err(1, "kevent_poll");
130: }
131: if (r == 0) {
132: break;
133: }
134:
1.1.1.2 ! root 135: int udata = EV_UDATA2INT(kev.udata);
1.1 root 136: if (udata == 0) {
137: r = read(tty_fd, buf, 1);
138: if (r < 0) {
139: err(1, "tty read");
140: }
141: if (r == 0) {
142: break;
143: }
144: // CR -> LF, LF -> discard
145: if (buf[0] == '\n') {
146: rbuf.push_back('\n');
147: fwrite(rbuf.data(), 1, rbuf.size(), stdout);
148: fflush(stdout);
149: rbuf.clear();
150: } else if (buf[0] == '\r') {
151: } else {
152: rbuf.push_back(buf[0]);
153: }
154:
155: if (rbuf.size() == 1 && rbuf[0] == '>') {
156: prompt = true;
157: }
158: writable = true;
159: }
160: }
161:
162: if (!complete) {
163: errx(1, "timeout");
164: }
165: }
166:
167: int
168: main(int ac, char *av[])
169: {
170: int c;
171: std::string dev = DEFAULT_DEV;
172:
173: while ((c = getopt(ac, av, "d:nt:")) >= 0) {
174: switch (c) {
175: case 'd':
176: dev = optarg;
177: break;
178: case 'n':
179: opt_n = true;
180: break;
181: case 't':
182: timescale = atol(optarg);
183: break;
184: default:
185: usage();
186: break;
187: }
188: }
189:
190: ac -= optind;
191: av += optind;
192:
193: if (ac == 0) {
194: usage();
195: }
196:
197: FILE *fp;
198:
199: if (strcmp(av[0], "-") == 0) {
200: fp = stdin;
201: } else {
202: fp = fopen(av[0], "r");
203: if (fp == NULL) {
204: err(1, "fopen %s", av[0]);
205: }
206: }
207:
208: int tty_fd = -1;
209: if (!opt_n) {
210: struct termios t;
211: tty_fd = open(dev.c_str(), O_RDWR);
212: if (tty_fd < 0) {
213: err(1, "open %s", dev.c_str());
214: }
215: tcgetattr(tty_fd, &t);
216: cfmakeraw(&t);
217: cfsetspeed(&t, B9600);
218: t.c_iflag |= IGNBRK;
219: t.c_oflag &= ~(OPOST);
220: t.c_cflag |= CREAD | CLOCAL | HUPCL | CS8;
221: t.c_lflag &= ~(ECHO | ICANON);
222: t.c_cc[VTIME] = 0;
223: t.c_cc[VMIN] = 1;
224: tcsetattr(tty_fd, TCSAFLUSH, &t);
225:
226: }
227:
228: Do(fp, tty_fd);
229:
230: if (tty_fd >= 0) {
231: close(tty_fd);
232: }
233: fclose(fp);
234: return 0;
235: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.