diff --git a/implementations/main.cpp b/implementations/main.cpp index d8abc3c..be86315 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -68,7 +68,14 @@ namespace { constexpr const char* Version = "0.1.0"; bool g_verbose = false; -int g_frameGapMs = 500; +// 500 ms was the research harness's pace, chosen so a human could read the +// transcript scroll by. It is not a design. The matcher rejects the early +// frames of a correct press and matches several frames in (frames 3 and 8 in +// the acceptance run), so frames-per-press is what decides a press -- and a +// lift is only noticed on the NEXT frame, so it is also the latency a user +// feels. A frame costs four QTEE round trips regardless; the gap on top is +// pure delay. +int g_frameGapMs = 40; int g_samples = 10; // common.max_enrolling_samples, as shipped std::string g_logDir = "/var/log/fingerprintd"; std::string g_stateDir = "/var/lib/fingerprintd"; @@ -1242,6 +1249,11 @@ public: bool inPress = false, pressMatched = false, pressRejected = false; int pressFrames = 0, rescans = 0; std::uint32_t pressFid = 0; + auto t0 = std::chrono::steady_clock::now(); + auto msSince = [&](auto t) { + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - t).count(); + }; // The reference frame loop is {QUERY, CAPTURE, REPORT, QUERY, REPORT}. // The trailing query acknowledges the trustlet's event state; without @@ -1300,13 +1312,22 @@ public: out.decided = true; out.matched = true; out.fid = pressFid; std::println(" press {}: {} frames -> MATCH fid={}", out.presses, pressFrames, pressFid); } - if (g_verbose) - std::println(" frame {:3}: metric={:<4}{}{}", i + 1, c.metric, - finger ? " FINGER" : " ", note); SendCommand(app_, ta::Cmd::QueryEventStatus, q); + if (g_verbose) { + // The IRQ line alongside the metric: if it tracks the finger + // under an armed session, lift detection can become an edge + // wait instead of a poll. + auto irq = sensor_.ReadIrq(); + std::println(" frame {:3} @{:5}ms: metric={:<4}{} irq={}{}", i + 1, + msSince(t0), c.metric, finger ? " FINGER" : " ", + irq ? std::to_string(*irq) : "?", note); + } std::this_thread::sleep_for(std::chrono::milliseconds(g_frameGapMs)); } fingerPresent_.store(false); + std::println(" verify loop: {} frames in {} ms ({} ms/frame incl. {} ms gap)", + out.frames, msSince(t0), + out.frames ? msSince(t0) / out.frames : 0, g_frameGapMs); if (cancel) { SendCommand(app_, ta::Cmd::Cancel, {}); out.cancelled = true; @@ -2006,6 +2027,7 @@ int main(int argc, char** argv) { if (a == "--enrol") { doEnrol = true; probe = true; } if (a == "--cal-save") { doCalSave = true; probe = true; g_verbose = true; } if (a.starts_with("--frames=")) frames = std::stoi(std::string(a.substr(9))); + if (a.starts_with("--frame-gap=")) g_frameGapMs = std::stoi(std::string(a.substr(12))); if (a.starts_with("--log-dir=")) g_logDir = a.substr(10); if (a.starts_with("--state-dir=")) g_stateDir = a.substr(12); if (a.starts_with("--rescan=")) g_rescan = std::stoi(std::string(a.substr(9)));