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