diff --git a/implementations/main.cpp b/implementations/main.cpp index 189967f..2b31548 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -1280,12 +1280,20 @@ public: out.frames++; std::string note; + bool rising = finger && !inPress; + if (rising) { + inPress = true; pressMatched = false; pressRejected = false; + pressFrames = 0; rescans = 0; pressFid = 0; + out.presses++; + // The frame that detected the finger is the finger LANDING -- + // partial contact, and the frame that rejects most often. + // Capture once more now that it has settled, so the image the + // matcher sees on the first report is a real one. One capture, + // ~50 ms, on the frame that decides every quick tap. + auto c2 = SendCommand(app_, ta::Cmd::CaptureImage, cap); + if (c2.invoked) { c = c2; note += " recap"; } + } for (ta::Event ev : tracker.Observe(finger, en::Mode::Authenticate)) { - if (ev == ta::Event::FingerTouched) { - inPress = true; pressMatched = false; pressRejected = false; - pressFrames = 0; rescans = 0; pressFid = 0; - out.presses++; - } std::vector evbuf(ta::EventContextSize); ta::BuildEventContext(evbuf, { .event = ev }); // A zero-initialised buffer cannot tell "the matcher never diff --git a/interfaces/Fingerprintd-Engine.cppm b/interfaces/Fingerprintd-Engine.cppm index 3750ff9..fb3bdc6 100644 --- a/interfaces/Fingerprintd-Engine.cppm +++ b/interfaces/Fingerprintd-Engine.cppm @@ -88,8 +88,14 @@ export namespace fingerprintd::engine { // trace. Sending event 7 on every held frame instead feeds the algorithm // near-duplicate images from a single press. // - // Authentication does want event 7, which reaches the matcher - // unconditionally; event 5 only reaches it when device+0x10a8 is 1 or 2. + // Authentication wants event 7, which reaches the matcher unconditionally, + // and ONLY event 7. Event 5 reaches it too (when device+0x10a8 is 1 or 2, + // which it is here): measured on the daemon, the rising-edge frame sent + // both and got two verdicts back from one image -- `rej rej`, `-11 -11`, + // `MATCH MATCH`. Each REPORT_EVENT that runs the matcher costs 250-300 ms, + // so the second one is a third of a second of redundant work on every + // press, on the frame where speed matters most. Enrolment keeps event 5: + // there it is the sample trigger, not a duplicate. class TouchTracker { public: // Returns the events to report for this frame, in order. @@ -97,7 +103,7 @@ export namespace fingerprintd::engine { std::vector out; bool rising = finger && !prev_; bool falling = !finger && prev_; - if (rising) + if (rising && mode == Mode::Enrol) out.push_back(Event::FingerTouched); if (finger && mode == Mode::Authenticate) out.push_back(Event::ImageReady); diff --git a/tests/Engine/main.cpp b/tests/Engine/main.cpp index ae2c85f..993af56 100644 --- a/tests/Engine/main.cpp +++ b/tests/Engine/main.cpp @@ -115,11 +115,14 @@ int main() { auto e4 = t.Observe(false, Mode::Enrol); Check(e4.empty(), "enrol: idle reports nothing"); - // Authentication: every frame with a finger reaches the matcher. + // Authentication: every frame with a finger reaches the matcher, ONCE. + // Event 5 also runs the matcher here, so sending it on the rising edge + // produced two verdicts from one image and cost ~300 ms extra on the + // frame where speed matters most. TouchTracker a; auto a1 = a.Observe(true, Mode::Authenticate); - Check(a1.size() == 2 && a1[0] == Event::FingerTouched && a1[1] == Event::ImageReady, - "auth: rising edge reports touched then image-ready"); + Check(a1.size() == 1 && a1[0] == Event::ImageReady, + "auth: rising edge reports image-ready only -- one matcher run, not two"); auto a2 = a.Observe(true, Mode::Authenticate); Check(a2.size() == 1 && a2[0] == Event::ImageReady, "auth: a held frame still reports image-ready"); auto a3 = a.Observe(false, Mode::Authenticate);