1 | /* |
---|
2 | ******************************************************************************* |
---|
3 | * Authors: |
---|
4 | * Maxime Villard, 2017 |
---|
5 | * Jankovic Marco, 01/07/2014 |
---|
6 | ******************************************************************************* |
---|
7 | */ |
---|
8 | |
---|
9 | #include "common.h" |
---|
10 | |
---|
11 | /* |
---|
12 | * tab containing all the slave side of a dev/pts |
---|
13 | * this part is swappable with other device |
---|
14 | */ |
---|
15 | int slave_fd[NB_CHANNELS]; |
---|
16 | |
---|
17 | /* |
---|
18 | * tab containing all the masters that come from /dev/pts/ptmx |
---|
19 | * this part is swappable with other device |
---|
20 | */ |
---|
21 | int master_fd[NB_CHANNELS]; |
---|
22 | |
---|
23 | /* |
---|
24 | * file descriptor of fifo rx and tx |
---|
25 | * file descriptor device_fd |
---|
26 | * nb_channels to multiplex |
---|
27 | */ |
---|
28 | int fifo_rx_fd; |
---|
29 | int fifo_tx_fd; |
---|
30 | |
---|
31 | #if TEST_BENCH |
---|
32 | int test_rx_fd; // file descriptor that simulates RX buffer |
---|
33 | int test_tx_fd; // file descriptor that simulates TX buffer |
---|
34 | #else |
---|
35 | int device_fd; |
---|
36 | #endif |
---|
37 | |
---|
38 | pthread_t tid[3]; |
---|
39 | |
---|
40 | /* |
---|
41 | * Function that opens an xterm. You need a master side and a slave side. |
---|
42 | * master_fd -> contains master fd from /dev/ptmx |
---|
43 | * slavename -> slave name from /dev/pts |
---|
44 | */ |
---|
45 | static int exec_xterm(int *master_fd, char *slavename, int tty_id) |
---|
46 | { |
---|
47 | char buf[64]; |
---|
48 | char tty_name[64]; |
---|
49 | |
---|
50 | *master_fd = posix_openpt(O_RDWR); |
---|
51 | grantpt(*master_fd); |
---|
52 | unlockpt(*master_fd); |
---|
53 | |
---|
54 | if (ptsname_r(*master_fd, slavename, 64) != 0) |
---|
55 | perror("ptsname_r"); |
---|
56 | |
---|
57 | printf("-> master_fd: %d\n", *master_fd); |
---|
58 | printf("-> slavename: %s\n", slavename); |
---|
59 | |
---|
60 | snprintf(buf, sizeof(buf), "-S%s/%d", strrchr(slavename,'/')+1, *master_fd); |
---|
61 | snprintf(tty_name, sizeof(buf), "tty_%d", tty_id); |
---|
62 | if (!fork()) { |
---|
63 | execlp("xterm", "xterm", |
---|
64 | buf, |
---|
65 | "-T", tty_name, |
---|
66 | "-bg", "black", |
---|
67 | "-fg", "green", |
---|
68 | "-geometry", "80x25", |
---|
69 | NULL); |
---|
70 | _exit(1); |
---|
71 | } |
---|
72 | |
---|
73 | return 0; |
---|
74 | } |
---|
75 | |
---|
76 | /* |
---|
77 | * Function that closes all file descriptors, kills all the threads and resets |
---|
78 | * the rs 232 port. |
---|
79 | */ |
---|
80 | void termination_handler(int signum) |
---|
81 | { |
---|
82 | int i; |
---|
83 | printf("termination handler %d \n",signum); |
---|
84 | |
---|
85 | for (i = 0; i < 3; i++) { |
---|
86 | if (pthread_kill(tid[i], SIGTERM) < 0) |
---|
87 | err(1, "pthread_kill"); |
---|
88 | } |
---|
89 | |
---|
90 | if (close(fifo_rx_fd) < 0) |
---|
91 | err(1, "close"); |
---|
92 | if (close(fifo_tx_fd) < 0) |
---|
93 | err(1, "close"); |
---|
94 | |
---|
95 | #if TEST_BENCH |
---|
96 | if (close(test_tx_fd) < 0) |
---|
97 | err(1, "close"); |
---|
98 | if (close(test_rx_fd) < 0) |
---|
99 | err(1, "close"); |
---|
100 | #else |
---|
101 | if (close(device_fd) < 0) |
---|
102 | err(1, "close"); |
---|
103 | #endif |
---|
104 | |
---|
105 | for (i = 0; i < NB_CHANNELS; i++) { |
---|
106 | if (close(slave_fd[i]) < 0) |
---|
107 | err(1, "close"); |
---|
108 | if (close(master_fd[i]) < 0) |
---|
109 | err(1, "close"); |
---|
110 | } |
---|
111 | |
---|
112 | exit(0); |
---|
113 | } |
---|
114 | |
---|
115 | static void init_tio(struct termios *tio) |
---|
116 | { |
---|
117 | // Input flags - Turn off input processing |
---|
118 | // convert break to null byte, no CR to NL translation, |
---|
119 | // no NL to CR translation, don't mark parity errors or breaks |
---|
120 | // no input parity check, don't strip high bit off, |
---|
121 | // no XON/XOFF software flow control |
---|
122 | tio->c_cflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON | CRTSCTS); |
---|
123 | tio->c_cflag |= (CLOCAL | CREAD); |
---|
124 | |
---|
125 | // Output flags - Turn off output processing |
---|
126 | // // no CR to NL translation, no NL to CR-NL translation, |
---|
127 | // // no NL to CR translation, no column 0 CR suppression, |
---|
128 | // // no Ctrl-D suppression, no fill characters, no case mapping, |
---|
129 | // // no local output processing |
---|
130 | tio->c_oflag &=~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OLCUC | OPOST); |
---|
131 | tio->c_oflag = 0; |
---|
132 | |
---|
133 | //// No line processing: |
---|
134 | //// echo off, echo newline off, canonical mode off, |
---|
135 | //// extended input processing off, signal chars off |
---|
136 | //// |
---|
137 | tio->c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); |
---|
138 | |
---|
139 | //// |
---|
140 | //// Turn off character processing |
---|
141 | //// clear current char size mask, no parity checking, |
---|
142 | //// no output processing, force 8 bit input |
---|
143 | //// 8N1 |
---|
144 | //// |
---|
145 | tio->c_cflag &= ~(CSIZE |PARENB|CSTOPB); |
---|
146 | tio->c_cflag |= CS8; |
---|
147 | //// |
---|
148 | |
---|
149 | tio->c_iflag &= ~(IXON | IXOFF | IXANY | INPCK | ISTRIP ); |
---|
150 | |
---|
151 | //// |
---|
152 | //// One input byte is enough to return from read() |
---|
153 | //// Inter-character timer off |
---|
154 | //// |
---|
155 | tio->c_cc[VMIN] = 1; |
---|
156 | tio->c_cc[VTIME] = 0; |
---|
157 | |
---|
158 | /* set baudrate */ |
---|
159 | if (cfsetispeed(tio, BAUDRATE) < 0 || cfsetospeed(tio, BAUDRATE) < 0) |
---|
160 | err(1, "error setting baudrate"); |
---|
161 | } |
---|
162 | |
---|
163 | int main(void) |
---|
164 | { |
---|
165 | char slavename[NB_CHANNELS][64]; |
---|
166 | int i; |
---|
167 | char buf[64]; |
---|
168 | |
---|
169 | pthread_attr_t thread_attr; |
---|
170 | |
---|
171 | /******************** signal handler ****************/ |
---|
172 | sigset_t sig_set; |
---|
173 | sigset_t sig_set_act; |
---|
174 | |
---|
175 | sigemptyset(&sig_set); |
---|
176 | sigfillset(&sig_set); |
---|
177 | sigdelset(&sig_set, SIGINT); |
---|
178 | sigprocmask(SIG_BLOCK, &sig_set, NULL); |
---|
179 | |
---|
180 | sigemptyset(&sig_set_act); |
---|
181 | |
---|
182 | struct sigaction action; |
---|
183 | action.sa_handler = termination_handler; |
---|
184 | action.sa_mask = sig_set_act; |
---|
185 | action.sa_flags = 0; |
---|
186 | sigaction(SIGINT, &action, NULL); |
---|
187 | |
---|
188 | /****************************************************/ |
---|
189 | printf("[+] device path: %s\n", DEVICE_PATH); |
---|
190 | printf("[+] nb_channels: %d\n", NB_CHANNELS); |
---|
191 | |
---|
192 | /* |
---|
193 | * Opening 2 FIFOs: one fifo for input data and the other one for |
---|
194 | * output data. |
---|
195 | */ |
---|
196 | if (mkfifo(FIFO_RX, S_IRWXU) < 0) |
---|
197 | err(1, "mkfifo"); |
---|
198 | if (mkfifo(FIFO_TX, S_IRWXU) < 0) |
---|
199 | err(1, "mkfifo"); |
---|
200 | |
---|
201 | if ((fifo_rx_fd = open(FIFO_RX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) |
---|
202 | err(1, "open"); |
---|
203 | if ((fifo_tx_fd = open(FIFO_TX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) |
---|
204 | err(1, "open"); |
---|
205 | /*******************************************************************/ |
---|
206 | |
---|
207 | printf("[+] Opening the xterms\n"); |
---|
208 | |
---|
209 | for (i = 0; i < NB_CHANNELS; i++) { |
---|
210 | exec_xterm(&master_fd[i], slavename[i], i); |
---|
211 | slave_fd[i] = open(slavename[i], O_RDWR|O_SYNC, 0777); |
---|
212 | do { |
---|
213 | read(slave_fd[i], buf, 1); |
---|
214 | } while (*buf != '\n' && *buf != '\r'); |
---|
215 | } |
---|
216 | |
---|
217 | #if TEST_BENCH |
---|
218 | printf("opening test files\n"); |
---|
219 | if (mkfifo("test_rx.txt", S_IRWXU) < 0) |
---|
220 | err(1, "mkfifo"); |
---|
221 | if (mkfifo("test_tx.txt", S_IRWXU) < 0) |
---|
222 | err(1, "mkfifo"); |
---|
223 | if ((test_rx_fd = open("test_rx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) |
---|
224 | err(1, "open"); |
---|
225 | if ((test_tx_fd = open("test_tx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) |
---|
226 | err(1, "open"); |
---|
227 | #else |
---|
228 | printf("[+] Opening %s\n", DEVICE_PATH); |
---|
229 | if ((device_fd = open(DEVICE_PATH, O_RDWR|O_NOCTTY|O_NDELAY)) < 0) |
---|
230 | err(1, "open"); |
---|
231 | fcntl(device_fd, F_SETFL, 0); |
---|
232 | |
---|
233 | /* |
---|
234 | * Set the rs232 port |
---|
235 | */ |
---|
236 | struct termios newtio; |
---|
237 | |
---|
238 | printf("[+] Setting %s rs232 port\n", DEVICE_PATH); |
---|
239 | |
---|
240 | memset(&newtio, 0, sizeof(newtio)); |
---|
241 | init_tio(&newtio); |
---|
242 | |
---|
243 | if (tcsetattr(device_fd, TCSAFLUSH, &newtio) < 0) |
---|
244 | err(1, "tcsetattr"); |
---|
245 | #endif |
---|
246 | |
---|
247 | printf("[+] Launching the threads\n"); |
---|
248 | |
---|
249 | /* |
---|
250 | * Initialize the thread attributes. |
---|
251 | */ |
---|
252 | if (pthread_attr_init(&thread_attr) != 0) |
---|
253 | err(1, "pthread_attr_init"); |
---|
254 | if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) |
---|
255 | err(1, "pthread_attr_setdetachstate"); |
---|
256 | |
---|
257 | /* |
---|
258 | * Launch the threads. |
---|
259 | */ |
---|
260 | if (pthread_create(tid, &thread_attr, thread_mux_demux, NULL) != 0) |
---|
261 | err(1, "pthread_create"); |
---|
262 | if (pthread_create(tid + 1, &thread_attr, thread_read_rx, NULL) != 0) |
---|
263 | err(1, "pthread_create"); |
---|
264 | if (pthread_create(tid + 2, &thread_attr, thread_write_tx, NULL) != 0) |
---|
265 | err(1, "pthread_create"); |
---|
266 | |
---|
267 | #if TEST_BENCH |
---|
268 | char buftest[2]; |
---|
269 | unsigned char pkt[PACKET_SIZE]; |
---|
270 | |
---|
271 | sleep(1); |
---|
272 | |
---|
273 | while (1) { |
---|
274 | printf("ttyid> "); |
---|
275 | |
---|
276 | buftest[0] = getchar(); |
---|
277 | buftest[1] = '\n'; |
---|
278 | getchar(); |
---|
279 | |
---|
280 | pkt[PKT_TTY] = 0x80 | atoi(buftest); |
---|
281 | |
---|
282 | printf("cmd> "); |
---|
283 | do { |
---|
284 | pkt[PKT_DAT] = getchar(); |
---|
285 | write(test_rx_fd, pkt, PACKET_SIZE); |
---|
286 | } while (pkt[PKT_DAT] != '\n'); |
---|
287 | } |
---|
288 | #else |
---|
289 | while(1) |
---|
290 | sleep(1); |
---|
291 | #endif |
---|
292 | |
---|
293 | return 0; |
---|
294 | } |
---|
295 | |
---|