|
1 | | - |
2 | | -// Copyright 2018 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
| 1 | +// Copyright 2017-present Proyectos y Sistemas de Mantenimiento SL (eProsima). |
3 | 2 | // |
4 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 4 | // you may not use this file except in compliance with the License. |
|
13 | 12 | // See the License for the specific language governing permissions and |
14 | 13 | // limitations under the License. |
15 | 14 |
|
16 | | -#ifdef _WIN32 |
17 | | -#include <uxr/agent/transport/udp/UDPServerWindows.hpp> |
18 | | -#include <uxr/agent/transport/tcp/TCPServerWindows.hpp> |
19 | | - |
20 | | -#elif __unix__ |
21 | | -#include <unistd.h> |
22 | | -#include <libgen.h> |
23 | | - |
24 | | -#include <uxr/agent/transport/serial/SerialServerLinux.hpp> |
25 | | -#include <uxr/agent/transport/udp/UDPServerLinux.hpp> |
26 | | -#include <uxr/agent/transport/tcp/TCPServerLinux.hpp> |
27 | | -#include <termios.h> |
28 | | -#include <fcntl.h> |
29 | | -#endif |
30 | | - |
31 | | -#include <iterator> |
32 | | -#include <iostream> |
33 | | -#include <string> |
34 | | -#include <limits> |
35 | | -#include "rclcpp/rclcpp.hpp" |
36 | | - |
37 | | -void showHelp() |
38 | | -{ |
39 | | - std::cout << "Usage: program <command>" << std::endl; |
40 | | - std::cout << "List of commands:" << std::endl; |
41 | | -#ifdef _WIN32 |
42 | | - std::cout << " udp <local_port>" << std::endl; |
43 | | - std::cout << " tcp <local_port>" << std::endl; |
44 | | -#else |
45 | | - std::cout << " serial <device_name>" << std::endl; |
46 | | - std::cout << " pseudo-serial" << std::endl; |
47 | | - std::cout << " udp <local_port> [<discovery_port>]" << std::endl; |
48 | | - std::cout << " tcp <local_port> [<discovery_port>]" << std::endl; |
49 | | -#endif |
50 | | -} |
51 | | - |
52 | | -void initializationError() |
53 | | -{ |
54 | | - std::cout << "Error: Invalid arguments." << std::endl; |
55 | | - showHelp(); |
56 | | - std::exit(EXIT_FAILURE); |
57 | | -} |
58 | | - |
59 | | -uint16_t parsePort(const std::string& str_port) |
60 | | -{ |
61 | | - uint16_t valid_port = 0; |
62 | | - try |
63 | | - { |
64 | | - int port = std::stoi(str_port); |
65 | | - if(port > (std::numeric_limits<uint16_t>::max)()) |
66 | | - { |
67 | | - std::cout << "Error: port number '" << port << "out of range." << std::endl; |
68 | | - initializationError(); |
69 | | - } |
70 | | - valid_port = uint16_t(port); |
71 | | - } |
72 | | - catch (const std::invalid_argument& ) |
73 | | - { |
74 | | - initializationError(); |
75 | | - } |
76 | | - return valid_port; |
77 | | -} |
| 15 | +#include <uxr/agent/utils/CLI.hpp> |
| 16 | +#include <csignal> |
78 | 17 |
|
79 | 18 | int main(int argc, char** argv) |
80 | 19 | { |
81 | | - eprosima::uxr::Server* server = nullptr; |
82 | | - std::vector<std::string> cl(0); |
83 | | - |
84 | | - if (1 == argc) |
85 | | - { |
86 | | - showHelp(); |
87 | | - std::cout << std::endl; |
88 | | - std::cout << "Enter command: "; |
89 | | - |
90 | | - std::string raw_cl; |
91 | | - std::getline(std::cin, raw_cl); |
92 | | - std::istringstream iss(raw_cl); |
93 | | - cl.insert(cl.begin(), std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>()); |
94 | | - std::cout << raw_cl << std::endl; |
95 | | - } |
96 | | - else |
97 | | - { |
98 | | - for (int i = 1; i < argc; ++i) |
99 | | - { |
100 | | - cl.push_back(argv[i]); |
101 | | - } |
102 | | - } |
103 | | - |
104 | | - if((1 == cl.size()) && (("-h" == cl[0]) || ("--help" == cl[0]))) |
105 | | - { |
106 | | - showHelp(); |
107 | | - } |
108 | | - else if((2 <= cl.size()) && ("udp" == cl[0])) |
| 20 | +#ifndef _WIN32 |
| 21 | + sigset_t signals; |
| 22 | + sigemptyset(&signals); |
| 23 | + if(sigaddset(&signals, SIGINT) && sigaddset(&signals, SIGTERM)) |
109 | 24 | { |
110 | | - std::cout << "UDP agent initialization... "; |
111 | | - uint16_t port = parsePort(cl[1]); |
112 | | -#ifdef _WIN32 |
113 | | - server = new eprosima::uxr::UDPServer(port); |
114 | | -#else |
115 | | - server = (3 == cl.size()) //discovery port |
116 | | - ? new eprosima::uxr::UDPServer(port, parsePort(cl[2])) |
117 | | - : new eprosima::uxr::UDPServer(port); |
118 | | -#endif |
| 25 | + std::cerr << "Wrong signalset" << std::endl; |
| 26 | + std::exit(EXIT_FAILURE); |
119 | 27 | } |
120 | | - else if((2 <= cl.size()) && ("tcp" == cl[0])) |
121 | | - { |
122 | | - std::cout << "TCP agent initialization... "; |
123 | | - uint16_t port = parsePort(cl[1]); |
124 | | -#ifdef _WIN32 |
125 | | - server = new eprosima::uxr::TCPServer(port); |
126 | | -#else |
127 | | - server = (3 == cl.size()) //discovery port |
128 | | - ? new eprosima::uxr::TCPServer(port, parsePort(cl[2])) |
129 | | - : new eprosima::uxr::TCPServer(port); |
| 28 | + sigprocmask( SIG_BLOCK, &signals, nullptr ); |
130 | 29 | #endif |
131 | | - } |
132 | | -#ifndef _WIN32 |
133 | | - else if((2 == cl.size()) && ("serial" == cl[0])) |
134 | | - { |
135 | | - std::cout << "Serial agent initialization... "; |
136 | | - |
137 | | - /* Open serial device. */ |
138 | | - int fd = open(cl[1].c_str(), O_RDWR | O_NOCTTY); |
139 | | - if (0 < fd) |
140 | | - { |
141 | | - struct termios tty_config; |
142 | | - memset(&tty_config, 0, sizeof(tty_config)); |
143 | | - if (0 == tcgetattr(fd, &tty_config)) |
144 | | - { |
145 | | - /* Setting CONTROL OPTIONS. */ |
146 | | - tty_config.c_cflag |= CREAD; // Enable read. |
147 | | - tty_config.c_cflag |= CLOCAL; // Set local mode. |
148 | | - tty_config.c_cflag &= ~PARENB; // Disable parity. |
149 | | - tty_config.c_cflag &= ~CSTOPB; // Set one stop bit. |
150 | | - tty_config.c_cflag &= ~CSIZE; // Mask the character size bits. |
151 | | - tty_config.c_cflag |= CS8; // Set 8 data bits. |
152 | | - tty_config.c_cflag &= ~CRTSCTS; // Disable hardware flow control. |
153 | | - |
154 | | - /* Setting LOCAL OPTIONS. */ |
155 | | - tty_config.c_lflag &= ~ICANON; // Set non-canonical input. |
156 | | - tty_config.c_lflag &= ~ECHO; // Disable echoing of input characters. |
157 | | - tty_config.c_lflag &= ~ECHOE; // Disable echoing the erase character. |
158 | | - tty_config.c_lflag &= ~ISIG; // Disable SIGINTR, SIGSUSP, SIGDSUSP and SIGQUIT signals. |
159 | | - |
160 | | - /* Setting INPUT OPTIONS. */ |
161 | | - tty_config.c_iflag &= ~IXON; // Disable output software flow control. |
162 | | - tty_config.c_iflag &= ~IXOFF; // Disable input software flow control. |
163 | | - tty_config.c_iflag &= ~INPCK; // Disable parity check. |
164 | | - tty_config.c_iflag &= ~ISTRIP; // Disable strip parity bits. |
165 | | - tty_config.c_iflag &= ~IGNBRK; // No ignore break condition. |
166 | | - tty_config.c_iflag &= ~IGNCR; // No ignore carrier return. |
167 | | - tty_config.c_iflag &= ~INLCR; // No map NL to CR. |
168 | | - tty_config.c_iflag &= ~ICRNL; // No map CR to NL. |
169 | | - |
170 | | - /* Setting OUTPUT OPTIONS. */ |
171 | | - tty_config.c_oflag &= ~OPOST; // Set raw output. |
172 | 30 |
|
173 | | - /* Setting OUTPUT CHARACTERS. */ |
174 | | - tty_config.c_cc[VMIN] = 10; |
175 | | - tty_config.c_cc[VTIME] = 1; |
176 | 31 |
|
177 | | - /* Setting BAUD RATE. */ |
178 | | - cfsetispeed(&tty_config, B115200); |
179 | | - cfsetospeed(&tty_config, B115200); |
| 32 | + /* CLI application. */ |
| 33 | + CLI::App app("micro-ROS Agent"); |
| 34 | + app.require_subcommand(1, 1); |
| 35 | + app.get_formatter()->column_width(42); |
180 | 36 |
|
181 | | - if (0 == tcsetattr(fd, TCSANOW, &tty_config)) |
182 | | - { |
183 | | - server = new eprosima::uxr::SerialServer(fd, 0); |
184 | | - } |
185 | | - } |
186 | | - } |
187 | | - } |
188 | | - else if ((1 == cl.size()) && ("pseudo-serial" == cl[0])) |
189 | | - { |
190 | | - std::cout << "Pseudo-Serial initialization... "; |
191 | | - |
192 | | - /* Open pseudo-terminal. */ |
193 | | - char* dev = NULL; |
194 | | - int fd = posix_openpt(O_RDWR | O_NOCTTY); |
195 | | - if (-1 != fd) |
196 | | - { |
197 | | - if (grantpt(fd) == 0 && unlockpt(fd) == 0 && (dev = ptsname(fd))) |
198 | | - { |
199 | | - struct termios attr; |
200 | | - tcgetattr(fd, &attr); |
201 | | - cfmakeraw(&attr); |
202 | | - tcflush(fd, TCIOFLUSH); |
203 | | - tcsetattr(fd, TCSANOW, &attr); |
204 | | - std::cout << "Device: " << dev << std::endl; |
205 | | - } |
206 | | - } |
207 | | - server = new eprosima::uxr::SerialServer(fd, 0x00); |
208 | | - } |
| 37 | + /* CLI subcommands. */ |
| 38 | + eprosima::uxr::cli::UDPv4Subcommand udpv4_subcommand(app); |
| 39 | + eprosima::uxr::cli::UDPv6Subcommand udpv6_subcommand(app); |
| 40 | + eprosima::uxr::cli::TCPv4Subcommand tcpv4_subcommand(app); |
| 41 | + eprosima::uxr::cli::TCPv6Subcommand tcpv6_subcommand(app); |
| 42 | +#ifndef _WIN32 |
| 43 | + eprosima::uxr::cli::SerialSubcommand serial_subcommand(app); |
| 44 | + eprosima::uxr::cli::PseudoSerialSubcommand pseudo_serial_subcommand(app); |
209 | 45 | #endif |
210 | | - else |
| 46 | + eprosima::uxr::cli::ExitSubcommand exit_subcommand(app); |
| 47 | + |
| 48 | + /* CLI parse. */ |
| 49 | + std::string cli_input{}; |
| 50 | + for (int i = 1; i < argc; ++i) |
211 | 51 | { |
212 | | - initializationError(); |
| 52 | + cli_input.append(argv[i]); |
| 53 | + cli_input.append(" "); |
213 | 54 | } |
214 | 55 |
|
215 | | - if (nullptr != server) |
| 56 | + while (true) |
216 | 57 | { |
217 | | - /* Launch server. */ |
218 | | - if (server->run()) |
| 58 | + try |
219 | 59 | { |
220 | | - std::cout << "OK" << std::endl; |
221 | | - std::cin.clear(); |
222 | | - char exit_flag = 0; |
223 | | - while ('q' != exit_flag) |
224 | | - { |
225 | | - std::cout << "Enter 'q' for exit" << std::endl; |
226 | | - std::cin >> exit_flag; |
227 | | - } |
228 | | - server->stop(); |
| 60 | + app.parse(cli_input); |
| 61 | + break; |
229 | 62 | } |
230 | | - else |
| 63 | + catch (const CLI::ParseError& e) |
231 | 64 | { |
232 | | - std::cout << "ERROR" << std::endl; |
| 65 | + app.exit(e); |
| 66 | + std::cin.clear(); |
| 67 | + std::cout << std::endl; |
| 68 | + std::cout << "Enter command: "; |
| 69 | + std::getline(std::cin, cli_input); |
233 | 70 | } |
234 | 71 | } |
235 | 72 |
|
| 73 | +#ifdef _WIN32 |
| 74 | + /* Waiting until exit. */ |
| 75 | + std::cin.clear(); |
| 76 | + char exit_flag = 0; |
| 77 | + while ('q' != exit_flag) |
| 78 | + { |
| 79 | + std::cin >> exit_flag; |
| 80 | + } |
| 81 | +#else |
| 82 | + /* Wait for SIGTERM/SIGINT instead, as reading from stdin may be redirected to /dev/null. */ |
| 83 | + int n_signal = 0; |
| 84 | + sigwait(&signals, &n_signal); |
| 85 | +#endif |
236 | 86 | return 0; |
237 | 87 | } |
0 commit comments