Guide the enrolment, and take the sample total from the config

Two problems from a real attempt, one mine and one the tool failing to explain
itself.

A sample is taken on the RISING edge only. Holding the finger down produces no
further touch events however long it stays there, so a run with the finger
almost permanently down collects one sample: 55 finger frames across 60, three
touch events, two samples accepted. The loop now says which state it is in on
every line -- press, hold, or LIFT -- shows accepted-of-total as it goes, and
calls out a finger that has been held for several frames, because that is the
state where nothing is happening and nothing on screen said so.

And the total is now read from the config instead of inferred. `rem` is
reported after the sample is processed, so the first reading of a healthy
enrolment is already 9, and a session that takes the first reading as its total
is permanently off by one -- it reported "1 of 9 accepted" when two samples had
been accepted out of ten. common.max_enrolling_samples is stated explicitly in
the generated config so both sides agree on the number rather than one of them
guessing.

Also recorded: not every press is accepted. The third touch of that run
reported the same count as the second, which is the algorithm rejecting a
sample, and is normal.
This commit is contained in:
Jorijn van der Graaf 2026-09-02 21:01:00 +02:00
commit bdd5de21b3
3 changed files with 48 additions and 18 deletions

View file

@ -57,6 +57,7 @@ bool g_auth = false;
bool g_enrol = false;
int g_frames = 40;
int g_frameGapMs = 500;
int g_samples = 10; // common.max_enrolling_samples, as shipped
std::string g_logDir = "/var/log/fingerprintd";
int g_rescan = -1; // -1 = leave the config's value alone
@ -1245,7 +1246,8 @@ int Probe() {
// every held frame instead gives the algorithm near-duplicate images
// from a single press.
en::TouchTracker tracker;
en::EnrolSession enrol;
en::EnrolSession enrol(g_samples);
int heldFrames = 0;
for (int i = 0; i < g_frames && !enrol.Complete(); i++) {
std::vector<std::byte> q(0x10, std::byte{0});
SendCommand(app, ta::Cmd::QueryEventStatus, q);
@ -1255,6 +1257,13 @@ int Probe() {
auto c = SendCommand(app, ta::Cmd::CaptureImage, cap);
bool finger = baseline.IsFinger(c.metric);
// A sample is taken on the RISING edge only. Holding the finger
// down produces no further touch events however long it stays, so
// a run where the finger is never lifted collects exactly one
// sample -- which is what a first attempt at this did, 55 finger
// frames and three touches.
heldFrames = finger ? heldFrames + 1 : 0;
std::string note;
for (ta::Event ev : tracker.Observe(finger, en::Mode::Enrol)) {
std::vector<std::byte> evbuf(ta::EventContextSize);
@ -1273,8 +1282,15 @@ int Probe() {
}
SendCommand(app, ta::Cmd::QueryEventStatus, q);
std::println(" frame {:2}: metric={:<4}{}{}", i + 1, c.metric,
finger ? " FINGER" : " ", note);
std::println(" [{:2}/{}] {:<28} metric={:<4}{}{}",
enrol.Accepted(), enrol.Total(),
enrol.Started()
? (finger ? "hold... then LIFT" : "LIFT -- now press again")
: "press your finger",
c.metric, finger ? " FINGER" : " ", note);
if (heldFrames == 4)
std::println(" *** still held -- LIFT the finger, a sample is only "
"taken when you press again ***");
std::this_thread::sleep_for(std::chrono::milliseconds(g_frameGapMs));
}
@ -1332,6 +1348,7 @@ int main(int argc, char** argv) {
if (a.starts_with("--log-dir=")) g_logDir = a.substr(10);
if (a.starts_with("--rescan=")) g_rescan = std::stoi(std::string(a.substr(9)));
if (a.starts_with("--group-path=")) g_groupPath = a.substr(13);
if (a.starts_with("--samples=")) g_samples = std::stoi(std::string(a.substr(10)));
if (a.starts_with("--sfs-root=")) g_sfsRoot = a.substr(11);
if (a.starts_with("--gid=")) g_gid = static_cast<std::uint32_t>(
std::stoul(std::string(a.substr(6))));