#pragma once // When a camera stream delivers nothing: keep waiting, restart the stream, or // reset the camera. Pure policy, so it is testable without a camera; the Vimba // source measures and acts. // // Why a reset exists at all: on 2026-09-24 tower 111's camera stopped delivering // frames entirely - to the program, to a fresh Vimba session, at a fixed 10 ms // exposure - and survived program restarts and a USB re-authorisation. Only the // camera's own DeviceReset brought it back, and until then production captured // nothing while logging "stream warming up", because a session that had never // delivered was never restarted at all. namespace fgc { enum class StallAction { Wait, // within what this exposure can legitimately take Restart, // stop and start the stream Reset, // DeviceReset: reboot the camera, reopen it, re-apply its profile }; // How long a fresh stream may go without its first frame. Long exposures are // legitimate - tower 111 auto-exposes up to 9 s in the dark - so the limit // grows with the exposure, and never drops below 30 s. long long firstFrameLimitMs(double exposure_us); // A stream that has delivered nothing since it started `waited_ms` ago. // `failed_restarts` counts restarts since the last frame that arrived. StallAction onNoFirstFrame(long long waited_ms, double exposure_us, int failed_restarts); // A stream that delivered before but has gone stale, and a restart has just // failed to bring a fresh frame. Restart again, or reset once restarts have // stopped working. StallAction onRestartFailed(int failed_restarts); // Restarts without a frame, after which the camera is reset instead. constexpr int kRestartsBeforeReset = 2; } // namespace fgc