The contextual help was on by default, so a first run met a window with a "?" beside every surface it had not asked to have explained; `contextual_help` now defaults to false and the layer is asked for from the Help menu, from the chooser's new help menu, or with Ctrl+H. The source chooser runs before `App` exists, which makes it the window a user who does not know how to start is looking at, so it now carries the same three help affordances the window's Help view does: Documentation (the manual is another process and needs nothing of the app), Enable contextual help (a row whose check *is* the setting, written to the file the app reads a moment later), and Guided tour. The tour is drawn on the app's own window, so the chooser can only record the wish: it sets `Config::tour_pending` -- the value `main()` owns and hands to both `choose_source()` and `run_ui()` -- and `on_activate()` starts it once the window is up and laid out, through its own callback so the readings can tell a request from the first-run auto-start. The rows are the window's own `menu_button()`/`menu_toggle()`; `install_css()` therefore runs from `choose_source()` (it is idempotent now) so the popover gets the `.udpscope-menu` rules before it is shown. Opening the manual could also fail with a message that blamed the handler whatever was missing. `help_installed_path()` now resolves `help:<id>` the way the specification does and the failure alert says which of the two it is: with the set installed it names the viewer, without it it names the identifier, the expected installed path and the install command. `show_help()` gained an optional reporter, which `UDPSCOPE_PROBE_HELP_MS` uses for a new reading -- `[help] launch attempted= done= ok= error='' installed=` -- since a successful launch leaves no window of ours to observe. Tested: clean --clean-first build, three warnings as documented; test-ui 13/13 and test-help pass; no Gtk-CRITICAL in the help, helpui and chooser runs.
79 lines
3.8 KiB
C++
79 lines
3.8 KiB
C++
// SPDX-License-Identifier: MIT
|
|
// SPDX-FileCopyrightText: 2026 Martino Ferrari
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
namespace udpscope {
|
|
|
|
/// Everything the command line can say. Defaults are the ones the spec names
|
|
/// (200 MB per buffer, 10 ms trigger hold-off) unless the user overrides them.
|
|
struct Config {
|
|
std::string server = "127.0.0.1"; ///< IPv4 dotted quad of the stream source.
|
|
std::uint16_t port = 8000; ///< UDP port (unicast) or TCP port (multicast).
|
|
std::string multicast; ///< Empty selects unicast.
|
|
std::string interface_addr; ///< Local IPv4 to join the group on; empty = default route.
|
|
|
|
/// Whether `--server` was given. Absent, the application asks which source to open rather
|
|
/// than silently taking the default above -- so this is "did the user choose", not "is
|
|
/// `server` valid". The default stays a usable value for every other path.
|
|
bool server_specified = false;
|
|
|
|
/// Size of *each* of the two sample buffers, in megabytes. The application
|
|
/// always allocates two identical buffers (spec item 1).
|
|
double buffer_mb = 200.0;
|
|
/// Whether `--buffer-mb` was given. A stored configuration's buffer size fills in only when the
|
|
/// flag was *absent*: an explicit flag beats a saved setting, and "not asked" is not the same
|
|
/// question as "asked for 200".
|
|
bool buffer_mb_specified = false;
|
|
|
|
/// Largest time window the toolbar offers, in seconds. The buffer partition is
|
|
/// sized to hold at least this much time (spec: decimation).
|
|
double max_window_s = 600.0;
|
|
|
|
double trigger_holdoff_s = 0.010;
|
|
int recv_buffer_bytes = 8 * 1024 * 1024;
|
|
|
|
/// Number of stacked plots (rows) to start with, 1..`RowSet::kMaxRows`. Only the
|
|
/// starting point: rows are added and removed from the layout editor.
|
|
int plots = 1;
|
|
|
|
/// Take the plot's time from the packet counter and the declared sample rate rather than
|
|
/// from the stream's own time signal, so arrival and producer-clock jitter cannot move a
|
|
/// sample's x. Absolute stream time is still recorded, for export only (`todo.md` item 2).
|
|
bool relative_time = false;
|
|
|
|
/// Whether relative time was *stated* rather than left at its default -- by `--relative-time`, or
|
|
/// by the preferences, which the source chooser can reach before this run is planned. A source's
|
|
/// stored configuration is a statement from an *older* session, so it only fills in the gap.
|
|
bool relative_time_specified = false;
|
|
|
|
/// `--capture-packets N`: the ring size of the raw-datagram capture, 1..100000.
|
|
/// 0 means the flag was absent: the capture is off, and the popover button then
|
|
/// uses the 1000-slot default when the user toggles it.
|
|
std::uint32_t capture_packets = 0;
|
|
|
|
/// `--open FILE`: a `.npy` an earlier run exported, opened for viewing and analysis instead of a
|
|
/// live source. File mode and source mode are exclusive -- there is no acquisition behind a file,
|
|
/// and the chooser's Waveforms page sets this rather than the connection fields.
|
|
std::string open_waveform;
|
|
|
|
/// The source chooser's "Guided tour" entry. The tour is drawn on the application's own window,
|
|
/// which does not exist while the chooser runs, so the request rides on the one value `main()`
|
|
/// owns and hands to both the chooser and the front end (`open_waveform` and the preferences'
|
|
/// relative time cross the same way) and the window starts the tour once it is up and laid out.
|
|
/// It is *not* a preference: it describes this request and nothing else, so nothing persists it.
|
|
bool tour_pending = false;
|
|
};
|
|
|
|
/// Parses argv. On `--help` prints usage to stdout and exits(0); on a bad
|
|
/// argument prints a diagnostic to stderr and exits(2).
|
|
Config parse_args(int argc, char** argv);
|
|
|
|
/// Writes the usage text to `out`.
|
|
void print_usage(std::FILE* out, const char* argv0);
|
|
|
|
} // namespace udpscope
|