|
|
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.