diff --git a/config/config.example.ini b/config/config.example.ini index e2e3ffc..5f2ce61 100644 --- a/config/config.example.ini +++ b/config/config.example.ini @@ -217,6 +217,8 @@ output_dir = ; Enable/disable subsystems and select mock (simulated) implementations. ; CLI flags (e.g. --no-mqtt, --mock-camera, --mock-serial) override these. enable_mqtt = true +; false: open no camera at all - a mock source stands in, no Vimba X needed and +; no profile XMLs required. For bringing a tower up one subsystem at a time. enable_camera = true enable_serial = true enable_imu = false diff --git a/src/core/Application.cpp b/src/core/Application.cpp index 3bf445f..941b463 100644 --- a/src/core/Application.cpp +++ b/src/core/Application.cpp @@ -340,12 +340,33 @@ struct Application::Impl { std::chrono::milliseconds(cfg.env.period_ms)); } - std::unique_ptr makeCamera() { - bool mock = opts.mock_camera.value_or(cfg.features.mock_camera); + // Does this run drive a real camera? Asked in two places - makeCamera() and + // the startup sequence, which must agree: profiles are meaningful only to + // VimbaCameraSource, so loading them for a mock run demands settings XMLs + // that a tower being brought up one subsystem at a time does not have yet. + // + // enable_camera substitutes the mock source rather than leaving `camera` + // null, because the capture path dereferences it in a dozen places. The + // result is a run with no camera hardware and no Vimba dependency, which is + // what the flag is for; it is not a silent no-op, and says so at startup. + bool realCameraWanted() const { #if !FGC_WITH_VIMBA - if (!mock) { + return false; +#else + if (!cfg.features.enable_camera) return false; + return !opts.mock_camera.value_or(cfg.features.mock_camera); +#endif + } + + std::unique_ptr makeCamera() { + bool mock = !realCameraWanted(); + if (mock && !cfg.features.enable_camera) { + LOG_WARN << "camera disabled ([Features] enable_camera = false); using a mock source " + "- no images come from hardware in this run"; + } +#if !FGC_WITH_VIMBA + if (!opts.mock_camera.value_or(cfg.features.mock_camera) && cfg.features.enable_camera) { LOG_WARN << "Camera requested but binary built without Vimba X; using mock camera"; - mock = true; } #endif const auto active = cfg.camera.active(); @@ -1990,7 +2011,15 @@ struct Application::Impl { if (Logger::categories()) LOG_INFO << "wire trace enabled: " << traceNames(Logger::categories()); - loadProfiles(); // before makeCamera(): the profile is applied at start() + // Before makeCamera(): the profile is applied at start(). Skipped entirely + // for a mock or disabled camera - a settings XML configures a physical + // sensor and nothing else, so requiring one would block bringing a tower + // up in phases (docs/tower-installation.md section 10). + if (realCameraWanted()) { + loadProfiles(); + } else { + LOG_INFO << "camera profiles not loaded: no real camera in this run"; + } channel = makeChannel(); motor = makeMotor();