|
|
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:
24: long timescale = DEFAULT_TIMESCALE;
25: bool opt_n = false;
26:
27: [[noreturn]]
28: void
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:
42: void
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) {
62: EV_SET(&kev, tty_fd, EVFILT_READ, EV_ADD, 0, 0, 0);
63: r = kevent_set(kq, &kev, 1);
64: if (r == -1) {
65: err(1, "kevent_set");
66: }
67: EV_SET(&kev, tty_fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT,
68: 0, 0, (kevent_udata_t)1);
69: r = kevent_set(kq, &kev, 1);
70: if (r == -1) {
71: err(1, "kevent_set");
72: }
73: }
74:
75: // 受信タイムアウトデフォルト 100msec
76: int64 recv_timeout = 1 * 100 * 1000 * 1000;
77:
78: char buf[1024];
79: bool complete = false;
80: bool prompt = true;
81: bool writable = true;
82:
83: for (;;) {
84: if (prompt && !complete) {
85: if (fgets(buf, sizeof(buf), fp) != NULL) {
86: if (strncmp(buf, "#", 1) == 0) {
87: printf("%s", buf);
88: continue;
89: }
90: // ウェイト時間はデフォルトでミリ秒で指定
91: if (sscanf(buf, "@%d", &wait)) {
92: t = wait * timescale;
93: timeout.tv_sec = t / (1000 * 1000 * 1000);
94: timeout.tv_nsec = t % (1000 * 1000 * 1000);
95: nanosleep(&timeout, NULL);
96: continue;
97: } else if (sscanf(buf, "@R%d", &msec)) {
98: // 受信タイムアウト変更
99: recv_timeout = msec * 1000 * 1000;
100: continue;
101: } else {
102: for (char *p = buf; *p; p++) {
103: if (*p == '\n') {
104: sbuf.push('\r');
105: } else {
106: sbuf.push(*p);
107: }
108: }
109: prompt = false;
110: }
111: } else {
112: complete = true;
113: }
114: }
115:
116: if (writable && sbuf.size() > 0) {
117: buf[0] = sbuf.front();
118: sbuf.pop();
119: r = write(tty_fd, buf, 1);
120: if (r <= 0) {
121: err(1, "tty_fd write");
122: }
123: writable = false;
124: }
125:
126: t = recv_timeout;
127: timeout.tv_sec = t / (1000 * 1000 * 1000);
128: timeout.tv_nsec = t % (1000 * 1000 * 1000);
129:
130: r = kevent_poll(kq, &kev, 1, &timeout);
131: if (r == -1) {
132: err(1, "kevent_poll");
133: }
134: if (r == 0) {
135: break;
136: }
137:
138: int udata = (int)kev.udata;
139: if (udata == 0) {
140: r = read(tty_fd, buf, 1);
141: if (r < 0) {
142: err(1, "tty read");
143: }
144: if (r == 0) {
145: break;
146: }
147: // CR -> LF, LF -> discard
148: if (buf[0] == '\n') {
149: rbuf.push_back('\n');
150: fwrite(rbuf.data(), 1, rbuf.size(), stdout);
151: fflush(stdout);
152: rbuf.clear();
153: } else if (buf[0] == '\r') {
154: } else {
155: rbuf.push_back(buf[0]);
156: }
157:
158: if (rbuf.size() == 1 && rbuf[0] == '>') {
159: prompt = true;
160: }
161: writable = true;
162: }
163: }
164:
165: if (!complete) {
166: errx(1, "timeout");
167: }
168: }
169:
170: int
171: main(int ac, char *av[])
172: {
173: int c;
174: std::string dev = DEFAULT_DEV;
175:
176: while ((c = getopt(ac, av, "d:nt:")) >= 0) {
177: switch (c) {
178: case 'd':
179: dev = optarg;
180: break;
181: case 'n':
182: opt_n = true;
183: break;
184: case 't':
185: timescale = atol(optarg);
186: break;
187: default:
188: usage();
189: break;
190: }
191: }
192:
193: ac -= optind;
194: av += optind;
195:
196: if (ac == 0) {
197: usage();
198: }
199:
200: FILE *fp;
201:
202: if (strcmp(av[0], "-") == 0) {
203: fp = stdin;
204: } else {
205: fp = fopen(av[0], "r");
206: if (fp == NULL) {
207: err(1, "fopen %s", av[0]);
208: }
209: }
210:
211: int tty_fd = -1;
212: if (!opt_n) {
213: struct termios t;
214: tty_fd = open(dev.c_str(), O_RDWR);
215: if (tty_fd < 0) {
216: err(1, "open %s", dev.c_str());
217: }
218: tcgetattr(tty_fd, &t);
219: cfmakeraw(&t);
220: cfsetspeed(&t, B9600);
221: t.c_iflag |= IGNBRK;
222: t.c_oflag &= ~(OPOST);
223: t.c_cflag |= CREAD | CLOCAL | HUPCL | CS8;
224: t.c_lflag &= ~(ECHO | ICANON);
225: t.c_cc[VTIME] = 0;
226: t.c_cc[VMIN] = 1;
227: tcsetattr(tty_fd, TCSAFLUSH, &t);
228:
229: }
230:
231: Do(fp, tty_fd);
232:
233: if (tty_fd >= 0) {
234: close(tty_fd);
235: }
236: fclose(fp);
237: return 0;
238: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.