main.cpp¶
file src/cli/main.cpp ยท Applications
Entry point of nmeasim, the headless command-line simulator.
Source src/cli/main.cpp
The tool parses its command line with CLI11 and runs on a QCoreApplication, so it needs no display. It links the same engine (nmeasim::core) and transports (nmeasim::io) as the desktop application. Subcommands:
run: loads a profile (the built-in default without--profile), applies the command-line overrides to it and streams the delta simulation, a track or a replayed log to the outputs until the duration elapses, a track or log that does not loop ends, orSIGINTorSIGTERMarrives;ports,interfacesandsentences: print tables of the serial ports, the IPv4 interfaces and the sentence registry;profile initandprofile show: write the default profile to a file, or print a validated and migrated profile as JSON.
-V or --version prints the project name and version. Errors, warnings and the status lines of run go to standard error, and run writes sentences to standard output only through a --stdout output, so nmeasim run --stdout --quiet produces a clean stream. The user-facing description of every option is in docs/reference/cli.md.
Types¶
| Type | Description |
|---|---|
RunOptions |
The options of the run subcommand, as CLI11 parsed them. |
Summary¶
File-local functions
| Name | Description |
|---|---|
on_interrupt() |
Signal handler for SIGINT and SIGTERM, installed by run_simulation. |
list_serial_ports() |
Prints the serial ports present on this machine as a table on standard output. |
list_interfaces() |
Prints every IPv4 address of every interface that is up as a table on standard output. |
list_sentences() |
Prints every sentence of the standard registry as a table on standard output. |
parse_digits() |
Reads a whole string as a decimal number made of digits only. |
split_host_port() |
Splits a --udp argument of the form host:port into the host and the port. |
split_serial() |
Splits a --serial argument of the form device[@baud] into the device and the baud rate. |
is_broadcast_address() |
Returns whether a --udp host is a broadcast address. |
check_finite_options() |
Refuses the non-finite values that CLI11 converts nan and inf to. |
apply_output_overrides() |
Replaces the outputs of profile with the outputs given on the command line, and applies --encoding, --tag-block and --tag-source to the outputs of the run. |
apply_destination() |
Sets the destination of the simulation seed from --destination. |
apply_sentence_overrides() |
Applies --enable, --disable and --rate on top of the profile's sentence settings. |
apply_mode_overrides() |
Applies --track, --replay, their companion options and --record to profile. |
run_simulation() |
Runs the run subcommand: builds the profile, streams it and returns the exit status. |
write_default_profile() |
Runs profile init: writes the built-in default profile to path as indented JSON. |
show_profile() |
Runs profile show: prints a profile as indented JSON on standard output. |
main() |
Entry point of nmeasim: parses the command line and runs the chosen subcommand. |
File-local variables
| Name | Description |
|---|---|
g_interrupted |
Set by on_interrupt when SIGINT or SIGTERM arrives; never reset. |
File-local functions¶
on_interrupt()¶
void on_interrupt(int)
Signal handler for SIGINT and SIGTERM, installed by run_simulation.
Only sets g_interrupted: Qt functions are not async-signal-safe, so the actual stop happens in the event loop, which polls the flag. The signal number is ignored.
Note
std::signal may reset the disposition to the default before the handler runs (the Microsoft C runtime does), in which case a second Ctrl+C terminates the process at once.
Declared in src/cli/main.cpp:69
list_serial_ports()¶
int list_serial_ports()
Prints the serial ports present on this machine as a table on standard output.
The columns are the device path, the driver description and the manufacturer, as the operating system reports them; values it does not provide stay empty. Prints No serial ports found. instead when there are none.
Returns int: Always 0.
See also
Declared in src/cli/main.cpp:81
list_interfaces()¶
int list_interfaces()
Prints every IPv4 address of every interface that is up as a table on standard output.
The columns are the interface name, the address and its subnet broadcast address. The header is printed even when the list is empty.
Returns int: Always 0.
See also
Declared in src/cli/main.cpp:102
list_sentences()¶
int list_sentences()
Prints every sentence of the standard registry as a table on standard output.
The columns are the registry id (the value --enable and --disable take), the formatter, the default talker, the group, whether the sentence is on or off by default, and the description, in registry order.
Returns int: Always 0.
See also
Declared in src/cli/main.cpp:121
parse_digits()¶
std::optional<int> parse_digits(std::string_view text)
Reads a whole string as a decimal number made of digits only.
Unlike std::stoi, it accepts no sign, no white space and no characters after the digits.
Parameters
| Name | Type | Description |
|---|---|---|
text |
std::string_view |
The text to read, for example 10110. |
Returns std::optional<int>: The number, or std::nullopt when the text is empty, contains anything but the digits 0 to 9, or does not fit in an int.
Declared in src/cli/main.cpp:222
split_host_port()¶
std::optional<std::pair<QString, quint16>> split_host_port(const std::string& value)
Splits a --udp argument of the form host:port into the host and the port.
The split is at the last colon. The host must not be empty and is otherwise not checked; the port must be digits only (see parse_digits).
Parameters
| Name | Type | Description |
|---|---|---|
value |
const std::string& |
The argument, for example 192.168.1.20:10110. |
Returns std::optional<std::pair<QString, quint16>>: The host and the port, or std::nullopt when there is no colon, the host is empty or the port is not a whole number in [1, 65535].
Declared in src/cli/main.cpp:243
split_serial()¶
std::optional<std::pair<QString, int>> split_serial(const std::string& value)
Splits a --serial argument of the form device[@baud] into the device and the baud rate.
The split is at the last @. Without one the whole argument is the device and the baud rate is 4800, the standard rate of NMEA 0183 (IEC 61162-1) talkers. The baud rate must be digits only (see parse_digits) and is not checked against the rates the port supports.
Parameters
| Name | Type | Description |
|---|---|---|
value |
const std::string& |
The argument, for example /dev/ttyUSB0@38400 or COM3. |
Returns std::optional<std::pair<QString, int>>: The device and the baud rate, or std::nullopt when the device is empty or the part after the @ is not a positive whole number.
Declared in src/cli/main.cpp:266
is_broadcast_address()¶
bool is_broadcast_address(const QString& host)
Returns whether a --udp host is a broadcast address.
The limited broadcast address 255.255.255.255 is one, and so is the subnet broadcast address of every IPv4 address of the interfaces that are up, such as 192.168.1.255 for 192.168.1.20/24. A host name is never one.
Parameters
| Name | Type | Description |
|---|---|---|
host |
const QString& |
The host part of a --udp argument. |
Returns bool: True when UDP datagrams to host must be sent as broadcasts.
See also
Declared in src/cli/main.cpp:290
check_finite_options()¶
bool check_finite_options(const RunOptions& options, std::string& error)
Refuses the non-finite values that CLI11 converts nan and inf to.
CLI11 reads --duration and --speed as floating-point numbers and accepts nan, inf and infinity, which would make a run endless or overflow the duration timer.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options; duration_s and track_speed_kn are read. |
error (out) |
std::string& |
Set to a message for the user when the function returns false. |
Returns bool: True when both values are finite numbers.
Declared in src/cli/main.cpp:313
apply_output_overrides()¶
bool apply_output_overrides(
const RunOptions& options,
nmeasim::io::Profile& profile,
std::string& error)
Replaces the outputs of profile with the outputs given on the command line, and applies --encoding, --tag-block and --tag-source to the outputs of the run.
When any of --stdout, --tcp-server, --udp, --websocket, --serial and --file is given, it clears the profile's outputs and appends, in this order, the TCP servers, UDP senders, WebSocket servers, serial ports, files and finally standard output. Everything an option does not carry keeps the default of nmeasim::io::OutputConfig: servers listen on every interface, files are appended to, the encoding is nmea0183 and there is no TAG block. Without an output option the profile's outputs stay.
Then every output of the run, except a log output (a recording, which always holds NMEA 0183), gets the --encoding when it is given, a TAG block when --tag-block is given, and the --tag-source identifier when that is not empty. An option that is not given leaves the output's own setting.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options. |
profile (inout) |
nmeasim::io::Profile& |
The profile to change. |
error (out) |
std::string& |
Set to a message for the user when the function returns false. |
Returns bool: True on success; false when --encoding is not an encoding name or a --udp or --serial argument is malformed, in which case profile may be left partly changed.
Declared in src/cli/main.cpp:345
apply_destination()¶
bool apply_destination(
const RunOptions& options,
nmeasim::io::Profile& profile,
std::string& error)
Sets the destination of the simulation seed from --destination.
The argument is LAT,LON[,NAME]: latitude in [-90, 90] positive north and longitude in [-180, 180] positive east, both finite decimal degrees, and an optional waypoint name. White space around each part is ignored, parts after the third are ignored, and an empty name keeps the default WPT. The leg starts at the seed position of the profile, also when the run follows a track. A destination makes the simulation send APB, RMB and XTE and the Signal K course paths.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options; only destination is read. |
profile (inout) |
nmeasim::io::Profile& |
The profile whose delta.seed.destination is set. |
error (out) |
std::string& |
Set to a message for the user when the function returns false. |
Returns bool: True when --destination is empty or valid; false when it has fewer than two parts, a coordinate is not a number, is nan or infinite, or is out of range, in which case profile is unchanged.
See also
Declared in src/cli/main.cpp:452
apply_sentence_overrides()¶
bool apply_sentence_overrides(
const RunOptions& options,
nmeasim::io::Profile& profile,
std::string& error)
Applies --enable, --disable and --rate on top of the profile's sentence settings.
A registry id that the profile has no setting for first gets one with the registry defaults (enabled state, talker and period). The ids of --enable are switched on first, then those of --disable are switched off. A positive --rate then sets the period of every registry sentence, which gives every one of them a setting; custom sentences and the message periods of Signal K and ViewSync outputs are not affected.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options; enable, disable and period_ms are read. |
profile (inout) |
nmeasim::io::Profile& |
The profile whose sentences map is changed. |
error (out) |
std::string& |
Set to a message for the user when the function returns false. |
Returns bool: True on success; false when an id of --enable or --disable is not in the standard registry, in which case the ids before it have already been applied.
Declared in src/cli/main.cpp:491
apply_mode_overrides()¶
void apply_mode_overrides(const RunOptions& options, nmeasim::io::Profile& profile)
Applies --track, --replay, their companion options and --record to profile.
- With
--track, the mode becomesnmeasim::io::SimulationMode::Trackwith the path;--loopsetsloop,--ignore-timestampsclearsuse_timestampsand a positive--speedsets the speed. A flag or option that is not given leaves the profile's setting. - With
--replay, the mode becomesnmeasim::io::SimulationMode::Replaywith the path;--loopsetsloopand a positive--replay-intervalsets the fixed interval, and either one not given leaves the profile's setting. - With neither,
--loopsets the loop flag of both the profile's track and replay settings, so that a profile already in one of those modes loops; without--loopthe profile's flags stay.
--record then appends a log output that truncates its file. run_simulation calls this function after apply_output_overrides, so the log output joins whichever outputs the run has, the profile's or the command line's, and takes neither --encoding nor the TAG block. The paths are made absolute against the working directory, since a relative path held in a loaded profile is resolved against the profile file's directory.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options. |
profile (inout) |
nmeasim::io::Profile& |
The profile to change. |
Note
The track or log file is only read later, by nmeasim::io::SimulationRunner::apply_profile.
Declared in src/cli/main.cpp:554
run_simulation()¶
int run_simulation(const RunOptions& options)
Runs the run subcommand: builds the profile, streams it and returns the exit status.
Checks the numbers with check_finite_options, loads the profile of --profile, or the built-in default, and applies apply_output_overrides, apply_sentence_overrides, apply_destination and apply_mode_overrides in this order. It then applies the profile to a nmeasim::io::SimulationRunner, starts it and runs the Qt event loop until the runner emits stopped, which happens when:
SIGINTorSIGTERMarrives (seeon_interrupt; the flag is polled every 100 ms);--durationelapses, counted in wall-clock time from just before the event loop starts;- a track or log that does not loop reaches its end (the runner emits
finished, then stops itself).
Unless --quiet is given it prints to standard error each output that opened, a line naming the profile, the track or log, its length and the tick, end of the track or log reached when a finite source ends, and when it stops the count of nmeasim::io::SimulationRunner::sentences_emitted, followed by that of nmeasim::io::SimulationRunner::state_messages_sent when there were any. A failure of one output while others work is printed as a warning and the run continues.
Parameters
| Name | Type | Description |
|---|---|---|
options |
const RunOptions& |
The parsed run options. |
Returns int: 0 after a normal stop; 2 when a number is not finite, the profile cannot be loaded or applied, an override is invalid or the run would have no outputs; 3 when none of the outputs could be opened.
Preconditions
- A
QCoreApplicationexists.
Note
Installs on_interrupt for SIGINT and SIGTERM and leaves it installed.
Declared in src/cli/main.cpp:619
write_default_profile()¶
int write_default_profile(const std::string& path, bool force)
Runs profile init: writes the built-in default profile to path as indented JSON.
Prints wrote PATH to standard output on success and an error to standard error otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
path |
const std::string& |
The file to write, as given on the command line. |
force |
bool |
Overwrites an existing file when true (-f or --force); when false an existing file is left untouched and reported as an error. |
Returns int: 0 when the file was written; 2 when it exists and force is false, or when it could not be written.
See also
Declared in src/cli/main.cpp:741
show_profile()¶
int show_profile(const std::string& path)
Runs profile show: prints a profile as indented JSON on standard output.
The file is loaded, validated and migrated to the current schema version, then written out again, so the output shows the profile as the simulator reads it.
Parameters
| Name | Type | Description |
|---|---|---|
path |
const std::string& |
The profile file; empty prints the built-in default profile. |
Returns int: 0 on success; 2 when the file cannot be loaded or is not a valid profile, after printing the reason to standard error.
See also
Declared in src/cli/main.cpp:765
main()¶
int main(int argc, char** argv)
Entry point of nmeasim: parses the command line and runs the chosen subcommand.
Creates the QCoreApplication, declares the subcommands and options with CLI11 (at most one top-level subcommand; profile needs init or show), then dispatches to list_serial_ports, list_interfaces, list_sentences, run_simulation, write_default_profile or show_profile. Without a subcommand it prints the help to standard output.
Parameters
| Name | Type | Description |
|---|---|---|
argc |
int |
Number of command-line arguments, including the program name. |
argv |
char** |
The command-line arguments; argv[0] is the program name. |
Returns int: The exit status:
- 0 on success, after
--helpor--version, and when no subcommand is given; - 2 when the command line cannot be parsed (an unknown option or subcommand, a missing or malformed value, a missing file, a value outside the range an option accepts, options that exclude or need each other), after CLI11 printed the reason to standard error, and when
runorprofilerejects its input (seerun_simulation,write_default_profileandshow_profile); - 3 when
runcould open none of its outputs.
Declared in src/cli/main.cpp:800
File-local variables¶
g_interrupted¶
std::atomic<bool> g_interrupted{false}
Set by on_interrupt when SIGINT or SIGTERM arrives; never reset.
run_simulation polls it from the event loop and stops the runner once it is true. std::atomic makes the write from the handler visible to the event loop, which on Windows runs in a different thread from the Ctrl+C handler.
Declared in src/cli/main.cpp:60