Skip to content

Commit 2d98510

Browse files
structure options
1 parent baca101 commit 2d98510

File tree

1 file changed

+128
-73
lines changed

1 file changed

+128
-73
lines changed

src/main.cpp

Lines changed: 128 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@
33
* This program is free software. You can redistribute it and/or modify it under the terms of the GPLv3 License.
44
*/
55

6+
#include "Modbus_RTU_Client.hpp"
7+
#include "Print_Time.hpp"
8+
#include "generated/version_info.hpp"
9+
#include "license.hpp"
10+
#include "modbus_shm.hpp"
11+
612
#include <csignal>
713
#include <cxxopts.hpp>
814
#include <filesystem>
915
#include <iostream>
10-
#include <memory>
16+
#include <sys/ioctl.h>
17+
#include <sys/resource.h>
18+
#include <sys/signalfd.h>
1119
#include <sysexits.h>
1220
#include <unistd.h>
1321

14-
#include "Modbus_RTU_Client.hpp"
15-
#include "Print_Time.hpp"
16-
#include "license.hpp"
17-
#include "modbus_shm.hpp"
22+
//! Help output line width
23+
static constexpr std::size_t HELP_WIDTH = 120;
1824

1925
//! terminate flag
2026
static volatile bool terminate = false;
@@ -79,94 +85,143 @@ int main(int argc, char **argv) {
7985
#endif
8086

8187
// all command line arguments
82-
options.add_options()("d,device", "mandatory: serial device", cxxopts::value<std::string>());
83-
options.add_options()("i,id", "mandatory: modbus RTU client id", cxxopts::value<int>());
84-
options.add_options()(
88+
options.add_options("serial")("d,device", "mandatory: serial device", cxxopts::value<std::string>());
89+
options.add_options("serial")("i,id", "mandatory: modbus RTU client id", cxxopts::value<int>());
90+
options.add_options("serial")(
8591
"p,parity", "serial parity bit (N(one), E(ven), O(dd))", cxxopts::value<char>()->default_value("N"));
86-
options.add_options()("data-bits", "serial data bits (5-8)", cxxopts::value<int>()->default_value("8"));
87-
options.add_options()("stop-bits", "serial stop bits (1-2)", cxxopts::value<int>()->default_value("1"));
88-
options.add_options()("b,baud", "serial baud", cxxopts::value<int>()->default_value("9600"));
89-
options.add_options()("rs485", "force to use rs485 mode");
90-
options.add_options()("rs232", "force to use rs232 mode");
91-
options.add_options()(
92+
options.add_options("serial")("data-bits", "serial data bits (5-8)", cxxopts::value<int>()->default_value("8"));
93+
options.add_options("serial")("stop-bits", "serial stop bits (1-2)", cxxopts::value<int>()->default_value("1"));
94+
options.add_options("serial")("b,baud", "serial baud", cxxopts::value<int>()->default_value("9600"));
95+
options.add_options("serial")("rs485", "force to use rs485 mode");
96+
options.add_options("serial")("rs232", "force to use rs232 mode");
97+
options.add_options("shared memory")(
9298
"n,name-prefix", "shared memory name prefix", cxxopts::value<std::string>()->default_value("modbus_"));
93-
options.add_options()("do-registers",
94-
"number of digital output registers",
95-
cxxopts::value<std::size_t>()->default_value("65536"));
96-
options.add_options()(
99+
options.add_options("modbus")("do-registers",
100+
"number of digital output registers",
101+
cxxopts::value<std::size_t>()->default_value("65536"));
102+
options.add_options("modbus")(
97103
"di-registers", "number of digital input registers", cxxopts::value<std::size_t>()->default_value("65536"));
98-
options.add_options()(
104+
options.add_options("modbus")(
99105
"ao-registers", "number of analog output registers", cxxopts::value<std::size_t>()->default_value("65536"));
100-
options.add_options()(
106+
options.add_options("modbus")(
101107
"ai-registers", "number of analog input registers", cxxopts::value<std::size_t>()->default_value("65536"));
102-
options.add_options()("m,monitor", "output all incoming and outgoing packets to stdout");
103-
options.add_options()("byte-timeout",
104-
"timeout interval in seconds between two consecutive bytes of the same message. "
105-
"In most cases it is sufficient to set the response timeout. "
106-
"Fractional values are possible.",
107-
cxxopts::value<double>());
108-
options.add_options()("response-timeout",
109-
"set the timeout interval in seconds used to wait for a response. "
110-
"When a byte timeout is set, if the elapsed time for the first byte of response is longer "
111-
"than the given timeout, a timeout is detected. "
112-
"When byte timeout is disabled, the full confirmation response must be received before "
113-
"expiration of the response timeout. "
114-
"Fractional values are possible.",
115-
cxxopts::value<double>());
116-
options.add_options()("force",
117-
"Force the use of the shared memory even if it already exists. "
118-
"Do not use this option per default! "
119-
"It should only be used if the shared memory of an improperly terminated instance continues "
120-
"to exist as an orphan and is no longer used.");
121-
options.add_options()("semaphore",
122-
"protect the shared memory with a named semaphore against simultaneous access",
123-
cxxopts::value<std::string>());
124-
options.add_options()("semaphore-force",
125-
"Force the use of the semaphore even if it already exists. "
126-
"Do not use this option per default! "
127-
"It should only be used if the semaphore of an improperly terminated instance continues "
128-
"to exist as an orphan and is no longer used.");
129-
options.add_options()("b,permissions",
130-
"permission bits that are applied when creating a shared memory.",
131-
cxxopts::value<std::string>()->default_value("0640"));
132-
options.add_options()("h,help", "print usage");
133-
options.add_options()("version", "print version information");
134-
options.add_options()("license", "show licences");
135-
options.add_options()("license-full", "show licences (full license text)");
136-
// clang-format on
108+
options.add_options("modbus")("m,monitor", "output all incoming and outgoing packets to stdout");
109+
options.add_options("modbus")("byte-timeout",
110+
"timeout interval in seconds between two consecutive bytes of the same message. "
111+
"In most cases it is sufficient to set the response timeout. "
112+
"Fractional values are possible.",
113+
cxxopts::value<double>());
114+
options.add_options("modbus")(
115+
"response-timeout",
116+
"set the timeout interval in seconds used to wait for a response. "
117+
"When a byte timeout is set, if the elapsed time for the first byte of response is longer "
118+
"than the given timeout, a timeout is detected. "
119+
"When byte timeout is disabled, the full confirmation response must be received before "
120+
"expiration of the response timeout. "
121+
"Fractional values are possible.",
122+
cxxopts::value<double>());
123+
options.add_options("shared memory")(
124+
"force",
125+
"Force the use of the shared memory even if it already exists. "
126+
"Do not use this option per default! "
127+
"It should only be used if the shared memory of an improperly terminated instance continues "
128+
"to exist as an orphan and is no longer used.");
129+
options.add_options("shared memory")("semaphore",
130+
"protect the shared memory with a named semaphore against simultaneous access",
131+
cxxopts::value<std::string>());
132+
options.add_options("shared memory")(
133+
"semaphore-force",
134+
"Force the use of the semaphore even if it already exists. "
135+
"Do not use this option per default! "
136+
"It should only be used if the semaphore of an improperly terminated instance continues "
137+
"to exist as an orphan and is no longer used.");
138+
options.add_options("shared memory")("permissions",
139+
"permission bits that are applied when creating a shared memory.",
140+
cxxopts::value<std::string>()->default_value("0640"));
141+
options.add_options("other")("h,help", "print usage");
142+
options.add_options("version information")("version", "print version and exit");
143+
options.add_options("version information")("longversion",
144+
"print version (including compiler and system info) and exit");
145+
options.add_options("version information")("shortversion", "print version (only version string) and exit");
146+
options.add_options("version information")("git-hash", "print git hash");
147+
options.add_options("other")("license", "show licences (short)");
148+
options.add_options("other")("license-full", "show licences (full license text)");
137149

138150
// parse arguments
139151
cxxopts::ParseResult args;
140152
try {
141153
args = options.parse(argc, argv);
142154
} catch (cxxopts::OptionParseException &e) {
143-
std::cerr << "Failed to parse arguments: " << e.what() << '.' << std::endl;
155+
std::cerr << Print_Time::iso << " ERROR: Failed to parse arguments: " << e.what() << ".'\n";
144156
return exit_usage();
145157
}
146158

147159
// print usage
148160
if (args.count("help")) {
149-
options.set_width(120);
150-
std::cout << options.help() << std::endl;
151-
std::cout << std::endl;
152-
std::cout << "The modbus registers are mapped to shared memory objects:" << std::endl;
153-
std::cout << " type | name | mb-server-access | shm name" << std::endl;
154-
std::cout << " -----|---------------------------|------------------|----------------" << std::endl;
155-
std::cout << " DO | Discrete Output Coils | read-write | <name-prefix>DO" << std::endl;
156-
std::cout << " DI | Discrete Input Coils | read-only | <name-prefix>DI" << std::endl;
157-
std::cout << " AO | Discrete Output Registers | read-write | <name-prefix>AO" << std::endl;
158-
std::cout << " AI | Discrete Input Registers | read-only | <name-prefix>AI" << std::endl;
159-
std::cout << std::endl;
160-
std::cout << "This application uses the following libraries:" << std::endl;
161-
std::cout << " - cxxopts by jarro2783 (https://github.com/jarro2783/cxxopts)" << std::endl;
162-
std::cout << " - libmodbus by Stéphane Raimbault (https://github.com/stephane/libmodbus)" << std::endl;
163-
exit(EX_OK);
161+
options.set_width(HELP_WIDTH);
162+
#ifdef OS_LINUX
163+
if (isatty(STDIN_FILENO)) {
164+
struct winsize w {};
165+
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) { // NOLINT
166+
static constexpr auto MIN_TTY_SIZE = static_cast<decltype(w.ws_col)>(80);
167+
options.set_width(std::max(MIN_TTY_SIZE, w.ws_col));
168+
}
169+
}
170+
#endif
171+
172+
std::cout << options.help() << '\n';
173+
std::cout << '\n';
174+
std::cout << "The modbus registers are mapped to shared memory objects:" << '\n';
175+
std::cout << " type | name | mb-server-access | shm name" << '\n';
176+
std::cout << " -----|---------------------------|------------------|----------------" << '\n';
177+
std::cout << " DO | Discrete Output Coils | read-write | <name-prefix>DO" << '\n';
178+
std::cout << " DI | Discrete Input Coils | read-only | <name-prefix>DI" << '\n';
179+
std::cout << " AO | Discrete Output Registers | read-write | <name-prefix>AO" << '\n';
180+
std::cout << " AI | Discrete Input Registers | read-only | <name-prefix>AI" << '\n';
181+
std::cout << '\n';
182+
std::cout << "This application uses the following libraries:" << '\n';
183+
std::cout << " - cxxopts by jarro2783 (https://github.com/jarro2783/cxxopts)" << '\n';
184+
std::cout << " - libmodbus by Stéphane Raimbault (https://github.com/stephane/libmodbus)" << '\n';
185+
std::cout << " - cxxshm (https://github.com/NikolasK-source/cxxshm)" << '\n';
186+
std::cout << " - cxxsemaphore (https://github.com/NikolasK-source/cxxsemaphore)" << '\n';
187+
return EX_OK;
164188
}
165189

166190
// print version
167-
if (args.count("version")) {
191+
if (args.count("longversion")) {
168192
std::cout << PROJECT_NAME << ' ' << PROJECT_VERSION << " (compiled with " << COMPILER_INFO << " on "
169-
<< SYSTEM_INFO << ')' << std::endl;
193+
<< SYSTEM_INFO << ')'
194+
#ifndef OS_LINUX
195+
<< "-nonlinux"
196+
#endif
197+
<< '\n';
198+
return EX_OK;
199+
}
200+
201+
if (args.count("shortversion")) {
202+
std::cout << PROJECT_VERSION << '\n';
203+
return EX_OK;
204+
}
205+
206+
if (args.count("version")) {
207+
std::cout << PROJECT_NAME << ' ' << PROJECT_VERSION << '\n';
208+
return EX_OK;
209+
}
210+
211+
if (args.count("longversion")) {
212+
std::cout << PROJECT_NAME << ' ' << PROJECT_VERSION << '\n';
213+
std::cout << " compiled with " << COMPILER_INFO << '\n';
214+
std::cout << " on system " << SYSTEM_INFO
215+
#ifndef OS_LINUX
216+
<< "-nonlinux"
217+
#endif
218+
<< '\n';
219+
std::cout << " from git commit " << RCS_HASH << '\n';
220+
return EX_OK;
221+
}
222+
223+
if (args.count("git-hash")) {
224+
std::cout << RCS_HASH << '\n';
170225
return EX_OK;
171226
}
172227

0 commit comments

Comments
 (0)