adafruit / Adafruit_CircuitPython_Fingerprint

CircuitPython library for talking to UART-based Fingerprint sensors
MIT License
54 stars 52 forks source link

template_compare fails on PID4750 #30

Open jerryneedell opened 3 years ago

jerryneedell commented 3 years ago

I tried the fingerprint_template_file compare on one of the new fingerprint sensors https://www.adafruit.com/product/4750 and it fails with this result. I have not looked into it yet and don't have a datasheet for this sensor :-(

The "simpletest" works ok.

INFO: Sensor les not support LED. Error: Failed to read data from sensor
----------------
Fingerprint templates:  [1, 2]
Number of templates found:  2
Traceback (most recent call last):
  File "fingerprint_test.py", line 179, in <module>
    if finger.read_sysparam() != adafruit_fingerprint.OK:
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 147, in read_sysparam
    r = self._get_packet(28)
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 342, in _get_packet
    raise RuntimeError("Failed to read data from sensor")
RuntimeError: Failed to read data from sensor
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
`fingerprint_template_file_compare.py`
====================================================

This is an example program to demo storing fingerprint templates in a file. It also allows
comparing a newly obtained print with one stored in the file in previous step. This is helpful
when fingerprint templates are stored centrally (not on sensor's flash memory) and shared
between multiple sensors.

* Author(s): admiralmaggie

Implementation Notes
--------------------

**Hardware:**

* `Fingerprint sensor <https://www.adafruit.com/product/751>`_ (Product ID: 751)
* `Panel Mount Fingerprint sensor <https://www.adafruit.com/product/4651>`_ (Product ID: 4651)
"""

import serial
import adafruit_fingerprint

# import board (if you are using a micropython board)
# uart = busio.UART(board.TX, board.RX, baudrate=57600)

# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter:
uart = serial.Serial("/dev/ttyUSB0", baudrate=115200, timeout=1)

# If using with Linux/Raspberry Pi and hardware UART:
# uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1)

# If using with Linux/Raspberry Pi 3 with pi3-disable-bte
# uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1)

finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)

##################################################

def sensor_reset():
    """Reset sensor"""
    print("Resetting sensor...")
    if finger.soft_reset() != adafruit_fingerprint.OK:
        print("Unable to reset sensor!")
    print("Sensor is reset.")

# pylint: disable=too-many-branches
def fingerprint_check_file():
    """Compares a new fingerprint template to an existing template stored in a file
    This is useful when templates are stored centrally (i.e. in a database)"""
    print("Waiting for finger print...")
    set_led_local(color=3, mode=1)
    while finger.get_image() != adafruit_fingerprint.OK:
        pass
    print("Templating...")
    if finger.image_2_tz(1) != adafruit_fingerprint.OK:
        return False

    print("Loading file template...", end="", flush=True)
    with open("template0.dat", "rb") as file:
        data = file.read()
    finger.send_fpdata(list(data), "char", 2)

    i = finger.compare_templates()
    if i == adafruit_fingerprint.OK:
        set_led_local(color=2, speed=150, mode=6)
        print("Fingerprint match template in file.")
        return True
    if i == adafruit_fingerprint.NOMATCH:
        set_led_local(color=1, mode=2, speed=20, cycles=10)
        print("Templates do not match!")
    else:
        print("Other error!")
    return False

# pylint: disable=too-many-statements
def enroll_save_to_file():
    """Take a 2 finger images and template it, then store it in a file"""
    set_led_local(color=3, mode=1)
    for fingerimg in range(1, 3):
        if fingerimg == 1:
            print("Place finger on sensor...", end="", flush=True)
        else:
            print("Place same finger again...", end="", flush=True)

        while True:
            i = finger.get_image()
            if i == adafruit_fingerprint.OK:
                print("Image taken")
                break
            if i == adafruit_fingerprint.NOFINGER:
                print(".", end="", flush=True)
            elif i == adafruit_fingerprint.IMAGEFAIL:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Imaging error")
                return False
            else:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Other error")
                return False

        print("Templating...", end="", flush=True)
        i = finger.image_2_tz(fingerimg)
        if i == adafruit_fingerprint.OK:
            print("Templated")
        else:
            if i == adafruit_fingerprint.IMAGEMESS:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Image too messy")
            elif i == adafruit_fingerprint.FEATUREFAIL:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Could not identify features")
            elif i == adafruit_fingerprint.INVALIDIMAGE:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Image invalid")
            else:
                set_led_local(color=1, mode=2, speed=20, cycles=10)
                print("Other error")
            return False

        if fingerimg == 1:
            print("Remove finger")
            while i != adafruit_fingerprint.NOFINGER:
                i = finger.get_image()

    print("Creating model...", end="", flush=True)
    i = finger.create_model()
    if i == adafruit_fingerprint.OK:
        print("Created")
    else:
        if i == adafruit_fingerprint.ENROLLMISMATCH:
            set_led_local(color=1, mode=2, speed=20, cycles=10)
            print("Prints did not match")
        else:
            set_led_local(color=1, mode=2, speed=20, cycles=10)
            print("Other error")
        return False

    print("Downloading template...")
    data = finger.get_fpdata("char", 1)
    with open("template0.dat", "wb") as file:
        file.write(bytearray(data))
    set_led_local(color=2, speed=150, mode=6)
    print("Template is saved in template0.dat file.")

    return True

# pylint: disable=broad-except
def set_led_local(color=1, mode=3, speed=0x80, cycles=0):
    """this is to make sure LED doesn't interfer with example
    running on models without LED support - needs testing"""
    try:
        finger.set_led(color, mode, speed, cycles)
    except Exception as exc:
        print("INFO: Sensor les not support LED. Error:", str(exc))

set_led_local(color=3, mode=2, speed=10, cycles=10)

while True:
    print("----------------")
    if finger.read_templates() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to read templates")
    print("Fingerprint templates: ", finger.templates)
    if finger.count_templates() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to read templates")
    print("Number of templates found: ", finger.template_count)
    if finger.set_sysparam(6, 2) != adafruit_fingerprint.OK:
        raise RuntimeError("Unable to set package size to 128!")
    if finger.read_sysparam() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to get system parameters")
    print("Package size (x128):", finger.data_packet_size)
    print("Size of template library: ", finger.library_size)
    print("e) enroll print and save to file")
    print("c) compare print to file")
    print("r) soft reset")
    print("x) quit")
    print("----------------")
    c = input("> ")

    if c in ("x", "q"):
        print("Exiting fingerprint example program")
        # turn off LED
        set_led_local(mode=4)
        raise SystemExit
    if c == "e":
        enroll_save_to_file()
    elif c == "c":
        fingerprint_check_file()
    elif c == "r":
        sensor_reset()
    else:
        print("Invalid choice: Try again")
admiralmaggie commented 3 years ago

@jerryneedell I don't have this sensor. This might be related to #31. Can you please put a return in set_led_local to disabled it and try again with Debug enabled when you get a chance?

jerryneedell commented 3 years ago

@admiralmaggie The issue was not due to the LED, it was catching that but I did dummy it out with a return,-- here is the result with _debug=True

pi@gjnpi4desk:~/projects/fingerprint $ python3 fingerprint_test.py 
----------------
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c', '04', '77']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c']
*** DEBUG ==> _send_packet length: 13
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '04', '1f', '00', '00', '24']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '23', '00', '0f', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '39']
*** DEBUG ==> _get_packet reply: ['00', '0f', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00']
Fingerprint templates:  [0, 1, 2, 3]
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '1d', '00', '21']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '05', '00', '00', '04', '00', '10']
*** DEBUG ==> _get_packet reply: ['00', '00', '04']
Number of templates found:  4
*** DEBUG ==> _send_packet length: 14
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '05', '0e', '06', '02', '00', '1c']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '03', '00', '00', '0a']
*** DEBUG ==> _get_packet reply: ['00']
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: []
Traceback (most recent call last):
  File "fingerprint_test.py", line 179, in <module>
    if finger.read_sysparam() != adafruit_fingerprint.OK:
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 147, in read_sysparam
    r = self._get_packet(28)
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 343, in _get_packet
    raise RuntimeError("Failed to read data from sensor")
RuntimeError: Failed to read data from sensor
jerryneedell commented 3 years ago

The problem has something to do with setting sysparam 6 I simplified the code to jusst read the sysparam twice then set the sysparam 6 to 2 and read the sysparam again and it fails the same way Note that sysparam 6 is already reading as 2 before the set_sysparam is even called...

pi@gjnpi4desk:~/projects/fingerprint $ python3 fingerprint_sys.py 
----------------
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c', '04', '77']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c']
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c', '04', '77']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c']
*** DEBUG ==> _send_packet length: 14
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '05', '0e', '06', '02', '00', '1c']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '03', '00', '00', '0a']
*** DEBUG ==> _get_packet reply: ['00']
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: []
Traceback (most recent call last):
  File "fingerprint_sys.py", line 35, in <module>
    if finger.read_sysparam() != adafruit_fingerprint.OK:
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 147, in read_sysparam
    r = self._get_packet(28)
  File "/home/pi/projects/fingerprint/adafruit_fingerprint.py", line 343, in _get_packet
    raise RuntimeError("Failed to read data from sensor")
RuntimeError: Failed to read data from sensor

here is the code run

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import serial
import adafruit_fingerprint

# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter:
uart = serial.Serial("/dev/ttyUSB0", baudrate=115200, timeout=1)

finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)
finger._debug = True
##################################################

def sensor_reset():
    """Reset sensor"""
    print("Resetting sensor...")
    if finger.soft_reset() != adafruit_fingerprint.OK:
        print("Unable to reset sensor!")
    print("Sensor is reset.")

while True:
    print("----------------")
    if finger.read_sysparam() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to get system parameters")
    if finger.read_sysparam() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to get system parameters")
    if finger.set_sysparam(6, 2) != adafruit_fingerprint.OK:
        raise RuntimeError("Unable to set package size to 128!")
    if finger.read_sysparam() != adafruit_fingerprint.OK:
        raise RuntimeError("Failed to get system parameters")
    print("Package size (x128):", finger.data_packet_size)
    print("Size of template library: ", finger.library_size)
    print("r) soft reset")
    print("x) quit")
    print("----------------")
    c = input("> ")

    if c in ("x", "q"):
        print("Exiting fingerprint example program")
        # turn off LED
        set_led_local(mode=4)
        raise SystemExit
    elif c == "r":
        sensor_reset()
    else:
        print("Invalid choice: Try again")
jerryneedell commented 3 years ago

ah -- adding a time.sleep(1) between the set_sysparam and read_ssyparam fixes it

pi@gjnpi4desk:~/projects/fingerprint $ python3 fingerprint_sys.py 
----------------
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '01', '00', '0c', '04', '76']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '01', '00', '0c']
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '01', '00', '0c', '04', '76']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '01', '00', '0c']
*** DEBUG ==> _send_packet length: 14
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '05', '0e', '06', '02', '00', '1c']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '03', '00', '00', '0a']
*** DEBUG ==> _get_packet reply: ['00']
*** DEBUG ==> _send_packet length: 12
*** DEBUG ==> _send_packet data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '01', '00', '03', '0f', '00', '13']
*** DEBUG ==> _get_packet received data: ['ef', '01', 'ff', 'ff', 'ff', 'ff', '07', '00', '13', '00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c', '04', '77']
*** DEBUG ==> _get_packet reply: ['00', '00', '00', '00', '00', '00', '50', '00', '03', 'ff', 'ff', 'ff', 'ff', '00', '02', '00', '0c']
Package size (x128): 2
Size of template library:  80
r) soft reset
x) quit
----------------
> 
jerryneedell commented 3 years ago

OK -- I deleted my last post -- the template compare test now works ok (I forgot to save the fingerprint file first) if I add the time.sleep(1) between the set_sysparam and read_sysparam...

I expect the delay can be less than 1 second, not sure why it is needed at all... or how to best accommodate this. Pehaps we could add a delay in the library after executing set_sysparam

edited to add... that works -- I added a time.sleep(.25) to set_sysparam just before the return and now the template_compare example works

admiralmaggie commented 3 years ago

@jerryneedell Good news! The delay makes sense. Changing the package size probably causes some sort of soft reboot on the device.