[231] | 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 | |
---|