krona-staff/docs/HARDWARE-TEST-SLK20R.md
Ochenstarik 7cf5142678 style: rebuild formatting without sync behavior changes
Recreate the formatting baseline from f5ac179 using only Prettier output. Leave sync and tenant-isolation files byte-identical to the base so Antigravity and Grok retain ownership. Normalized comparison confirms all 19 changed files are formatting-only; npm run check passes. Full format check retains five upstream warnings in excluded files.
2026-09-26 17:16:51 +07:00

8.9 KiB

ZKTeco SLK20R Hardware Integration & Test Report

Document Version: 1.0.0
Test Date: September 2026
Hardware Tested: ZKTeco SLK20R Optical USB Fingerprint Reader
Driver: ZKTeco SLK20R USB Driver (slk20r.sys v2.1.0) / ZKFinger SDK 5.3
Operating Systems: Windows 10 Pro (22H2 x64), Windows 11 Enterprise (24H2 x64), Windows Server 2022 (Session 0)


1. Executive Summary

This report documents empirical hardware testing and architectural findings gathered during the integration of the ZKTeco SLK20R fingerprint scanner into the Krona Staff Terminal ecosystem.

Key Takeaways:

  1. Session 0 Limitation: The ZKTeco USB driver and native SDK (libzkfp.dll) rely on interactive desktop Windows messaging subsystems (WM_DEVICECHANGE) and Win32 user session interfaces. Running biometric capture inside a Windows Service (Session 0) consistently enumerates 0 devices.
  2. Hybrid Solution Adopted: A decoupled dual-process architecture:
    • KronaStaffTerminal.exe (Interactive User Session): Owns hardware USB scanner lifecycle, capture loop, biometric template matching, and multi-finger enrollment.
    • KronaStaffService.exe (Windows Service Session 0): Owns persistent offline sync queue in %ProgramData%, draining records to backend HTTPS endpoints even when no user is logged in.
  3. Ghost Device Elimination: The native ZKFinger SDK frequently enumerates duplicate/phantom device handles when querying zkfp2.GetDeviceCount(). Hardware serial number inspection was implemented to guarantee 1:1 hardware device mapping.
  4. USB Disconnect / Hotplug Resilience: Scanner disconnection mid-session emits negative error codes; an automated reconnection state machine recovers connection within 2.0 seconds of re-plug without data loss or application crash.

2. Session 0 Investigation & Architectural Analysis

The Problem

During development of the headless Windows Service (KronaStaffService), tests were performed to verify whether libzkfp.dll could capture fingerprints in Session 0 (running as NT AUTHORITY\SYSTEM).

Empirical Observations:

  • In Windows Service Session 0, calling zkfp2.Init() returns 0 (ZKFP_ERR_OK).
  • Calling zkfp2.GetDeviceCount() immediately following returns 0, despite the USB scanner being plugged into the machine and operational in Device Manager.
  • Attempting to pass handle 0 to zkfp2.OpenDevice(0) returns error code -1 (device not found).

Root Cause:

The ZKTeco SLK20R driver implementation (slk20r.sys) registers device interfaces that bind specifically to interactive Windows desktop sessions. Because Session 0 in modern Windows (Vista through Windows 11/Server 2022) is isolated from window stations, the native driver cannot establish the USB pipe without an interactive user station (WinSta0).

Architectural Resolution:

Instead of forcing unreliable Session 0 USB hooks or interactive service workarounds (which violate Microsoft Windows Security Guidelines), the architecture cleanly divides responsibilities:

+--------------------------------------------------------------+
|                Interactive User Session                      |
|                                                              |
|   +------------------------------------------------------+   |
|   |         KronaStaffTerminal.exe (WinUI 3 App)         |   |
|   |  - Drives SLK20R via libzkfp.dll (USB capture)      |   |
|   |  - Matches templates locally (1:N biometric engine)  |   |
|   |  - Duplicate scan guard & auto-checkout scheduler   |   |
|   |  - System tray icon with live hardware diagnostics  |   |
|   +---------------------------+--------------------------+   |
+-------------------------------|------------------------------+
                                | Named Pipe IPC /
                                | Machine Store (%ProgramData%)
+-------------------------------|------------------------------+
|                Session 0 (Background Service)                |
|                                                              |
|   +---------------------------v--------------------------+   |
|   |         KronaStaffService.exe (Windows Service)      |   |
|   |  - Named Pipe Server (SYSTEM ACL)                   |   |
|   |  - Monitors %ProgramData%\Krona\StaffTerminal        |   |
|   |  - HTTPS sync loop with exponential backoff & retry |   |
|   |  - Operates headless even when user logs off        |   |
|   +------------------------------------------------------+   |
+--------------------------------------------------------------+

3. SDK Device Deduplication Analysis

The Problem

Under certain driver configurations and USB 3.0/3.1 xHCI host controllers, zkfp2.GetDeviceCount() reports 2 or more devices even when only a single physical SLK20R reader is connected.

Opening device index 1 resulted in one of two failure modes:

  1. OpenDevice(1) returned error -2 (device already open/busy).
  2. OpenDevice(1) succeeded as a phantom clone that interfered with image acquisition on device index 0, causing dropped frames and degraded capture reliability.

The Solution: Serial Number Deduplication

FingerprintScanner.cs inspects hardware parameters for each enumerated slot:

// Query serial number parameter (parameter codes 1101, 1102, 106)
byte[] serialBuffer = new byte[256];
int size = serialBuffer.Length;
string? serial = null;
if (zkfp2.GetParameters(devHandle, 1101, serialBuffer, ref size) == 0 && size > 0)
{
    serial = Encoding.UTF8.GetString(serialBuffer, 0, size).Trim('\0', ' ', '\r', '\n');
}

If an enumerated slot returns a serial number that has already been registered by slot 0, the terminal skips the duplicate slot and logs a diagnostic warning. This guarantees that only one active capture session exists per physical unit.


4. USB Disconnection & Hotplug Recovery Testing

Test Scenario

  1. Terminal running in kiosk mode with SLK20R connected.
  2. Employee clocks in successfully.
  3. USB cable is physically unplugged or hub power is cycled.

Observed Results

  • The active capture thread in zkfp2.AcquireFingerprint returns negative error code -101 or -102 (ZKFP_ERR_IO / disconnect).
  • Without reconnect logic, earlier versions hung in a tight error loop, pinning the CPU at 100%.
  • With Production Reconnect Logic:
    1. Capture loop catches negative return code and triggers HandleHardwareDisconnect().
    2. Scanner state immediately updates to ScannerState.Disconnected.
    3. System tray icon transitions to TrayState.NoScanner.
    4. Device handle and database handle are safely closed via zkfp2.CloseDevice() and zkfp2.DBFree().
    5. An asynchronous background recovery task initiates a non-blocking 2-second polling loop.
    6. Upon cable re-connection, zkfp2.GetDeviceCount() returns >= 1.
    7. Reader is automatically reinitialized, biometric database reloaded, and scanner state transitions to ScannerState.Connected.
    8. User receives audible/visual confirmation; normal attendance recording resumes without user intervention.

5. Performance & Biometric Accuracy Verification

Metric Target Measured Result Status
Finger placement to verification < 1000 ms ~420 ms PASSED
1:N Biometric Matching (100 templates) < 100 ms 14 ms PASSED
False Rejection Rate (FRR) at threshold 60 < 1.5% 0.8% PASSED
USB Disconnect to UI State Update < 500 ms ~120 ms PASSED
Cable Re-insertion to Active Ready State < 3000 ms 2150 ms PASSED
Duplicate Scan Guard (30s lockout) 100% rejection 100% rejection (0 duplicate punches) PASSED
Windows Service startup persistence after reboot Reliable NOT TESTED YET IN HARDWARE (Requires real service installation test after machine reboot to verify background sync without login) PENDING