Source code for adafruit_fingerprint

# The MIT License (MIT)
#
# Copyright (c) 2017 ladyada for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_fingerprint`
====================================================

This library will let you use an Adafruit Fingerprint sensor on any UART to get, store,
retreive and query fingerprints! Great for adding bio-sensing security to your next build.

* Author(s): ladyada

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

**Hardware:**

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

**Software and Dependencies:**

* Adafruit CircuitPython firmware (2.2.0+) for the ESP8622 and M0-based boards:
  https://github.com/adafruit/circuitpython/releases
"""

from micropython import const
try:
    import struct
except ImportError:
    import ustruct as struct

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint.git"

_STARTCODE = const(0xEF01)
_COMMANDPACKET = const(0x1)
_DATAPACKET = const(0x2)
_ACKPACKET = const(0x7)
_ENDDATAPACKET = const(0x8)

_GETIMAGE = const(0x01)
_IMAGE2TZ = const(0x02)
_REGMODEL = const(0x05)
_STORE = const(0x06)
_LOAD = const(0x07)
_UPLOAD = const(0x08)
_DELETE = const(0x0C)
_EMPTY = const(0x0D)
_HISPEEDSEARCH = const(0x1B)
_VERIFYPASSWORD = const(0x13)
_TEMPLATECOUNT = const(0x1D)
_TEMPLATEREAD = const(0x1F)

# Packet error code
OK = const(0x0)
PACKETRECIEVEERR = const(0x01)
NOFINGER = const(0x02)
IMAGEFAIL = const(0x03)
IMAGEMESS = const(0x06)
FEATUREFAIL = const(0x07)
NOMATCH = const(0x08)
NOTFOUND = const(0x09)
ENROLLMISMATCH = const(0x0A)
BADLOCATION = const(0x0B)
DBRANGEFAIL = const(0x0C)
UPLOADFEATUREFAIL = const(0x0D)
PACKETRESPONSEFAIL = const(0x0E)
UPLOADFAIL = const(0x0F)
DELETEFAIL = const(0x10)
DBCLEARFAIL = const(0x11)
PASSFAIL = const(0x13)
INVALIDIMAGE = const(0x15)
FLASHERR = const(0x18)
INVALIDREG = const(0x1A)
ADDRCODE = const(0x20)
PASSVERIFY = const(0x21)

[docs]class Adafruit_Fingerprint: """UART based fingerprint sensor.""" _uart = None password = None address = [0xFF, 0xFF, 0xFF, 0xFF] finger_id = None confidence = None templates = [] template_count = None def __init__(self, uart, passwd=(0, 0, 0, 0)): # Create object with UART for interface, and default 32-bit password self.password = passwd self._uart = uart if self.verify_password() != OK: raise RuntimeError('Failed to find sensor, check wiring!')
[docs] def verify_password(self): """Checks if the password/connection is correct, returns True/False""" self._send_packet([_VERIFYPASSWORD] + list(self.password)) return self._get_packet(12)[0]
[docs] def count_templates(self): """Requests the sensor to count the number of templates and stores it in ``self.template_count``. Returns the packet error code or OK success""" self._send_packet([_TEMPLATECOUNT]) r = self._get_packet(14) self.template_count = struct.unpack('>H', bytes(r[1:]))[0] return r[0]
[docs] def get_image(self): """Requests the sensor to take an image and store it memory, returns the packet error code or OK success""" self._send_packet([_GETIMAGE]) return self._get_packet(12)[0]
[docs] def image_2_tz(self, slot): """Requests the sensor convert the image to a template, returns the packet error code or OK success""" self._send_packet([_IMAGE2TZ, slot]) return self._get_packet(12)[0]
[docs] def create_model(self): """Requests the sensor take the template data and turn it into a model returns the packet error code or OK success""" self._send_packet([_REGMODEL]) return self._get_packet(12)[0]
[docs] def store_model(self, location): """Requests the sensor store the model into flash memory and assign a location. Returns the packet error code or OK success""" self._send_packet([_STORE, 1, location >> 8, location & 0xFF]) return self._get_packet(12)[0]
[docs] def delete_model(self, location): """Requests the sensor delete a model from flash memory given by the argument location. Returns the packet error code or OK success""" self._send_packet([_DELETE, location >> 8, location & 0xFF, 0x00, 0x01]) return self._get_packet(12)[0]
[docs] def read_templates(self): """Requests the sensor to list of all template locations in use and stores them in self.templates. Returns the packet error code or OK success""" self._send_packet([_TEMPLATEREAD, 0x00]) r = self._get_packet(44) self.templates = [] for i in range(32): byte = r[i+1] for bit in range(8): if byte & (1 << bit): self.templates.append(i * 8 + bit) return r[0]
################################################## def _get_packet(self, expected): """ Helper to parse out a packet from the UART and check structure. Returns just the data payload from the packet""" res = self._uart.read(expected) #print("Got", res) if (not res) or (len(res) != expected): raise RuntimeError('Failed to read data from sensor') # first two bytes are start code start = struct.unpack('>H', res)[0] if start != _STARTCODE: raise RuntimeError('Incorrect packet data') # next 4 bytes are address addr = [i for i in res[2:6]] if addr != self.address: raise RuntimeError('Incorrect address') packet_type, length = struct.unpack('>BH', res[6:]) if packet_type != _ACKPACKET: raise RuntimeError('Incorrect packet data') reply = [i for i in res[9:9+(length-2)]] #print(reply) return reply def _send_packet(self, data): packet = [_STARTCODE >> 8, _STARTCODE & 0xFF] packet = packet + self.address packet.append(_COMMANDPACKET) # the packet type length = len(data) + 2 packet.append(length >> 8) packet.append(length & 0xFF) packet = packet + data checksum = sum(packet[6:]) packet.append(checksum >> 8) packet.append(checksum & 0xFF) #print("Sending: ", [hex(i) for i in packet]) self._uart.write(bytearray(packet))