|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2021 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // シリアルポートの標準入出力ドライバ ! 9: // ! 10: ! 11: #include "comdriver_stdio.h" ! 12: #include "hostcom.h" ! 13: #include <csignal> ! 14: ! 15: // コンストラクタ ! 16: COMDriverStdio::COMDriverStdio(HostDevice *hostdev_) ! 17: : inherited(hostdev_, "Stdio") ! 18: { ! 19: // 現在の端末属性を取得 ! 20: tcgetattr(STDIN_FILENO, &oldtc); ! 21: } ! 22: ! 23: // デストラクタ ! 24: COMDriverStdio::~COMDriverStdio() ! 25: { ! 26: // 端末属性を元に戻す ! 27: tcsetattr(STDIN_FILENO, TCSANOW, &oldtc); ! 28: } ! 29: ! 30: // ドライバ初期化 ! 31: bool ! 32: COMDriverStdio::InitDriver() ! 33: { ! 34: struct termios tc; ! 35: int fds[2]; ! 36: ! 37: // 端末の設定を変更 ! 38: tc = oldtc; ! 39: ! 40: // 入力時の変換は無し ! 41: tc.c_iflag = 0; ! 42: ! 43: tc.c_lflag &= ~ECHO; // エコーオフ ! 44: tc.c_lflag &= ~ICANON; // 非カノニカルモード ! 45: tc.c_lflag &= ~IEXTEN; // DISCARD(^O)と LNEXT をオフ? ! 46: tc.c_cc[VTIME] = 0; ! 47: tc.c_cc[VMIN] = 1; ! 48: ! 49: if (tcsetattr(STDIN_FILENO, TCSANOW, &tc) < 0) { ! 50: putmsg(0, "tcsetattr: %s", strerror(errno)); ! 51: return false; ! 52: } ! 53: ! 54: // シグナルを受け取る ! 55: if (pipe(fds) < 0) { ! 56: putmsg(0, "pipe: %s", strerror(errno)); ! 57: return false; ! 58: } ! 59: if (hostdev->AddSignal(fds[0], fds[1]) < 0) { ! 60: putmsg(0, "AddSignal: %s", strerror(errno)); ! 61: close(fds[0]); ! 62: close(fds[1]); ! 63: return false; ! 64: } ! 65: sigfd = fds[0]; ! 66: ! 67: if (hostdev->AddOuter(STDIN_FILENO) < 0) { ! 68: putmsg(0, "AddOuter: %s", strerror(errno)); ! 69: sigfd.Close(); ! 70: close(fds[1]); ! 71: return false; ! 72: } ! 73: ! 74: char_from_signal = 0; ! 75: ! 76: return true; ! 77: } ! 78: ! 79: // Driver の Dispatch() は udata を返す。 ! 80: int ! 81: COMDriverStdio::Dispatch(int udata) ! 82: { ! 83: if (udata == HostDevice::DATA_FROM_SIGNAL) { ! 84: char buf[1]; ! 85: if (read(sigfd, buf, sizeof(buf)) < 0) { ! 86: putmsg(0, "read(sigfd=%d): %s", (int)sigfd, strerror(errno)); ! 87: return HostDevice::DONE; ! 88: } ! 89: int signo = buf[0]; ! 90: switch (signo) { ! 91: case SIGINT: ! 92: // ^C が入力されたのでシリアルに '\x03' を送り込む ! 93: char_from_signal = 0x03; ! 94: break; ! 95: case SIGTSTP: ! 96: // ^Z が入力されたのでシリアルに '\x1a' を送り込む ! 97: char_from_signal = 0x1a; ! 98: break; ! 99: case SIGQUIT: ! 100: // ^\ が入力されたのでシリアルに '\x1e' を送り込む ! 101: char_from_signal = 0x1e; ! 102: break; ! 103: default: ! 104: return HostDevice::DONE; ! 105: } ! 106: ! 107: // シグナルで来た文字を Read で読める文字が外から来たことにする ! 108: return HostDevice::DATA_FROM_OUTER; ! 109: } ! 110: ! 111: return udata; ! 112: } ! 113: ! 114: // 外部への1バイト書き出し ! 115: void ! 116: COMDriverStdio::Write(uint32 data) ! 117: { ! 118: uint8 buf[1]; ! 119: int r; ! 120: ! 121: buf[0] = data; ! 122: r = write(STDOUT_FILENO, buf, sizeof(buf)); ! 123: if (r < 0) { ! 124: putmsg(0, "write: %s", strerror(errno)); ! 125: return; ! 126: } ! 127: if (r < sizeof(buf)) { ! 128: putmsg(0, "write: short"); ! 129: return; ! 130: } ! 131: } ! 132: ! 133: // 外部からの1バイト読み込み ! 134: int ! 135: COMDriverStdio::Read() ! 136: { ! 137: uint8 buf[1]; ! 138: int r; ! 139: ! 140: // シグナルで来た文字があればそちらを返す ! 141: if (char_from_signal) { ! 142: r = char_from_signal; ! 143: char_from_signal = 0; ! 144: return r; ! 145: } ! 146: ! 147: r = read(STDIN_FILENO, buf, sizeof(buf)); ! 148: if (r < 0) { ! 149: putmsg(0, "read: %s", strerror(errno)); ! 150: return NODATA; ! 151: } ! 152: if (r == 0) { ! 153: return NODATA; ! 154: } ! 155: return buf[0]; ! 156: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.