Compare commits

...

37 commits

Author SHA1 Message Date
Limor "Ladyada" Fried
cdb797b039
Merge pull request #21 from jerryneedell/jerryn_fingersearch
add finger_search
2020-07-15 17:41:50 -04:00
Jerry Needell
cedbc6466d add fingerprintsearch -- for R503 sensor 2020-07-14 14:55:39 -04:00
dherrada
1155d89382 Fixed discord invite link 2020-07-08 16:49:04 -04:00
Scott Shawcroft
5ebbb6ca6e
Merge pull request #19 from adafruit/black-update
Black reformatting with Python 3 target.
2020-04-09 09:35:11 -07:00
Kattni Rembor
450d68f200 Black reformatting with Python 3 target. 2020-04-08 15:14:34 -04:00
sommersoft
4e1dbf6552 build.yml: add black formatting check
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-04-07 16:04:49 -05:00
Kattni
870469df24
Merge pull request #18 from adafruit/pylint-update
Ran black, updated to pylint 2.x
2020-03-17 12:31:23 -04:00
sommersoft
06f580c352 update code of coduct: discord moderation contact section
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-15 18:31:58 -05:00
dherrada
e032600513 Ran black, updated to pylint 2.x 2020-03-15 18:00:36 -04:00
Kattni
27f8ce933e
Merge pull request #17 from sommersoft/patch_coc
Update Code of Conduct
2020-03-13 15:58:44 -04:00
sommersoft
7a21e5c3b9 update code of conduct 2020-03-13 13:51:52 -05:00
sommersoft
f94c57e0bf update pylintrc for black
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-08 19:10:13 -05:00
sommersoft
080c594fa2 build.yml: move pylint, black, and Sphinx installs to each repo; add description to 'actions-ci/install.sh'
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-05 10:09:27 -06:00
foamyguy
e68d12103e
Merge pull request #11 from stitchesnburns/stitchesnburns-patch-1
library expansion and compatibility with other ZhianTec fp sensors
2020-02-05 15:44:14 -06:00
stitchesnburns
ff628d14f4 expanded the example to include saving fingerprint image 2020-01-14 11:11:50 +08:00
stitchesnburns
0e3ac3c60e updated to comply with pylint 2020-01-09 17:44:12 +08:00
stitchesnburns
a03e236a03 Added another example based on the default one 2020-01-09 17:29:22 +08:00
stitchesnburns
263b43558f Reverted default example 2020-01-09 17:24:39 +08:00
stitchesnburns
fd74ea720c Merge branch 'master' into stitchesnburns-patch-1 2020-01-09 16:52:39 +08:00
Emmanuel Balintec
8291727c3a code clean up 2019-03-20 09:19:40 +08:00
Emmanuel Balintec
d117944af6 fixed bug when sending last packet of data to fp sensor 2019-03-15 14:55:31 +08:00
Emmanuel Balintec
9513b83ff4 changed 'buffer' variable to 'sensorbuffer' 2019-03-05 18:50:47 +08:00
stitchesnburns
425f4be97f
Merge pull request #3 from stitchesnburns/stitchesnburns-patch-1-1
fixed read_templates() rounding up
2019-03-04 18:03:44 +08:00
Emmanuel Balintec
ef52314dd2 fixed read_templates() rounding up 2019-03-04 17:49:24 +08:00
Emmanuel Balintec
1e343c3ce0 finger_fast_search() based on module's capacity 2019-02-26 11:29:51 +08:00
Emmanuel Balintec
9c4034d0ac some more fixes 2019-02-22 17:31:59 +08:00
Emmanuel Balintec
4971ed2185 some fixes 2019-02-22 17:20:24 +08:00
Emmanuel Balintec
667b492763 implemented additional functionalities 2019-02-22 17:06:18 +08:00
stitchesnburns
2a94c93adc
Update fingerprint_simpletest.py 2019-02-12 19:19:36 +08:00
stitchesnburns
a04f55f8eb
Update fingerprint_simpletest.py 2019-02-12 19:16:55 +08:00
stitchesnburns
98cd938bda
Update adafruit_fingerprint.py 2019-02-12 19:15:51 +08:00
stitchesnburns
c17ed41383
created an empty_library() function 2019-02-12 19:10:55 +08:00
stitchesnburns
c874c423d7
created an empty_lilbrary() function 2019-02-12 19:08:06 +08:00
stitchesnburns
3ef2398891
fixed travis build failure 2019-02-12 19:03:11 +08:00
stitchesnburns
9e3722eb7e
Merge pull request #2 from stitchesnburns/stitchesnburns-patch-2
added additional functionalities
2019-02-12 18:45:48 +08:00
stitchesnburns
358c49afe1
added reset library functionality 2019-02-12 18:41:15 +08:00
stitchesnburns
b7639f9725
hack for other compatible fp sensors
dirty hack for compatible fingerprint sensors with capacity greater than the default, since the function limits reading the templates to 162(?).  an observation: each pass reads 256 templates (0-255) so for sensors with 1000 templates, 4 passes are required.  but there must be a better way to do this.  tested on this hardware: https://circuit-help.com.ph/product/fingerprint-sensor-2/
2019-02-12 18:04:23 +08:00
9 changed files with 645 additions and 123 deletions

View file

@ -34,11 +34,18 @@ jobs:
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme
- name: Library version
run: git describe --dirty --always --tags
- name: Check formatting
run: |
black --check --target-version=py35 .
- name: PyLint
run: |
pylint $( find . -path './adafruit*.py' )

View file

@ -52,7 +52,7 @@ confidence=
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

View file

@ -34,13 +34,15 @@ Examples of unacceptable behavior by participants include:
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Promoting or spreading disinformation, lies, or conspiracy theories against
a person, group, organisation, project, or community
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate
The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you dont just aim to be
and maintain a respectful community. We ask that you dont just aim to be
"technically unimpeachable", but rather try to be your best self.
We value many things beyond technical expertise, including collaboration and
@ -72,10 +74,10 @@ You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
to all Community Moderators by tagging @community moderators. You may
also send an open message from any channel, or a direct message to
@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
Email and direct message reports will be kept confidential.
@ -83,7 +85,7 @@ In situations on Discord where the issue is particularly egregious, possibly
illegal, requires immediate action, or violates the Discord terms of service,
you should also report the message directly to Discord.
These are the steps for upholding our communitys standards of conduct.
These are the steps for upholding our communitys standards of conduct.
1. Any member of the community may report any situation that violates the
Adafruit Community Code of Conduct. All reports will be reviewed and
@ -124,4 +126,4 @@ For other projects adopting the Adafruit Community Code of
Conduct, please contact the maintainers of those projects for enforcement.
If you wish to use this code of conduct for your own project, consider
explicitly mentioning your moderation policy or making a copy with your
own moderation policy so as to avoid confusion.
own moderation policy so as to avoid confusion.

View file

@ -7,7 +7,7 @@ Introduction
:alt: Documentation Status
.. image :: https://img.shields.io/discord/327254708534116352.svg
:target: https://discord.gg/nBQh6qu
:target: https://adafru.it/discord
:alt: Discord
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint/workflows/Build%20CI/badge.svg

View file

@ -34,6 +34,7 @@ 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)
**Software and Dependencies:**
@ -42,6 +43,7 @@ Implementation Notes
"""
from micropython import const
try:
import struct
except ImportError:
@ -58,16 +60,22 @@ _ENDDATAPACKET = const(0x8)
_GETIMAGE = const(0x01)
_IMAGE2TZ = const(0x02)
_FINGERPRINTSEARCH = const(0x04)
_REGMODEL = const(0x05)
_STORE = const(0x06)
_LOAD = const(0x07)
_UPLOAD = const(0x08)
_DOWNLOAD = const(0x09)
_UPLOADIMAGE = const(0x0A)
_DOWNLOADIMAGE = const(0x0B)
_DELETE = const(0x0C)
_EMPTY = const(0x0D)
_READSYSPARA = const(0x0F)
_HISPEEDSEARCH = const(0x1B)
_VERIFYPASSWORD = const(0x13)
_TEMPLATECOUNT = const(0x1D)
_TEMPLATEREAD = const(0x1F)
_GETECHO = const(0x53)
# Packet error code
OK = const(0x0)
@ -92,9 +100,12 @@ FLASHERR = const(0x18)
INVALIDREG = const(0x1A)
ADDRCODE = const(0x20)
PASSVERIFY = const(0x21)
MODULEOK = const(0x55)
# pylint: disable=too-many-instance-attributes
class Adafruit_Fingerprint:
"""UART based fingerprint sensor."""
_uart = None
password = None
@ -103,13 +114,28 @@ class Adafruit_Fingerprint:
confidence = None
templates = []
template_count = None
library_size = None
security_level = None
device_address = None
data_packet_size = None
baudrate = None
system_id = None
status_register = None
def __init__(self, uart, passwd=(0, 0, 0, 0)):
# Create object with UART for interface, and default 32-bit password
# 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!')
raise RuntimeError("Failed to find sensor, check wiring!")
def check_module(self):
"""Checks the state of the fingerprint scanner module.
Returns OK or error."""
self._send_packet([_GETECHO])
if self._get_packet(12)[0] != MODULEOK:
raise RuntimeError("Something is wrong with the sensor.")
return True
def verify_password(self):
"""Checks if the password/connection is correct, returns True/False"""
@ -121,7 +147,22 @@ class Adafruit_Fingerprint:
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:3]))[0]
self.template_count = struct.unpack(">H", bytes(r[1:3]))[0]
return r[0]
def read_sysparam(self):
"""Returns the system parameters on success via attributes."""
self._send_packet([_READSYSPARA])
r = self._get_packet(28)
if r[0] != OK:
raise RuntimeError("Command failed.")
self.status_register = struct.unpack(">H", bytes(r[1:3]))[0]
self.system_id = struct.unpack(">H", bytes(r[3:5]))[0]
self.library_size = struct.unpack(">H", bytes(r[5:7]))[0]
self.security_level = struct.unpack(">H", bytes(r[7:9]))[0]
self.device_address = bytes(r[9:13])
self.data_packet_size = struct.unpack(">H", bytes(r[13:15]))[0]
self.baudrate = struct.unpack(">H", bytes(r[15:17]))[0]
return r[0]
def get_image(self):
@ -130,7 +171,7 @@ class Adafruit_Fingerprint:
self._send_packet([_GETIMAGE])
return self._get_packet(12)[0]
def image_2_tz(self, slot):
def image_2_tz(self, slot=1):
"""Requests the sensor convert the image to a template, returns
the packet error code or OK success"""
self._send_packet([_IMAGE2TZ, slot])
@ -142,10 +183,10 @@ class Adafruit_Fingerprint:
self._send_packet([_REGMODEL])
return self._get_packet(12)[0]
def store_model(self, location):
def store_model(self, location, slot=1):
"""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])
self._send_packet([_STORE, slot, location >> 8, location & 0xFF])
return self._get_packet(12)[0]
def delete_model(self, location):
@ -154,17 +195,77 @@ class Adafruit_Fingerprint:
self._send_packet([_DELETE, location >> 8, location & 0xFF, 0x00, 0x01])
return self._get_packet(12)[0]
def load_model(self, location, slot=1):
"""Requests the sensor to load a model from the given memory location
to the given slot. Returns the packet error code or success"""
self._send_packet([_LOAD, slot, location >> 8, location & 0xFF])
return self._get_packet(12)[0]
def get_fpdata(self, sensorbuffer="char", slot=1):
"""Requests the sensor to transfer the fingerprint image or
template. Returns the data payload only."""
if slot != 1 or slot != 2:
# raise error or use default value?
slot = 2
if sensorbuffer == "image":
self._send_packet([_UPLOADIMAGE])
elif sensorbuffer == "char":
self._send_packet([_UPLOAD, slot])
else:
raise RuntimeError("Uknown sensor buffer type")
if self._get_packet(12)[0] == 0:
res = self._get_data(9)
# print('datasize: ' + str(len(res)))
# print(res)
return res
def send_fpdata(self, data, sensorbuffer="char", slot=1):
"""Requests the sensor to receive data, either a fingerprint image or
a character/template data. Data is the payload only."""
if slot != 1 or slot != 2:
# raise error or use default value?
slot = 2
if sensorbuffer == "image":
self._send_packet([_DOWNLOADIMAGE])
elif sensorbuffer == "char":
self._send_packet([_DOWNLOAD, slot])
else:
raise RuntimeError("Uknown sensor buffer type")
if self._get_packet(12)[0] == 0:
self._send_data(data)
# print('datasize: ' + str(len(res)))
# print(res)
return True
def empty_library(self):
"""Requests the sensor to delete all models from flash memory.
Returns the packet error code or OK success"""
self._send_packet([_EMPTY])
return self._get_packet(12)[0]
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)
stores them in self.templates. Returns the packet error code or
OK success"""
from math import ceil # pylint: disable=import-outside-toplevel
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)
self.read_sysparam()
temp_r = [
0x0C,
]
for j in range(ceil(self.library_size / 256)):
self._send_packet([_TEMPLATEREAD, j])
r = self._get_packet(44)
if r[0] == OK:
for i in range(32):
byte = r[i + 1]
for bit in range(8):
if byte & (1 << bit):
self.templates.append((i * 8) + bit + (j * 256))
temp_r = r
else:
r = temp_r
return r[0]
def finger_fast_search(self):
@ -172,37 +273,110 @@ class Adafruit_Fingerprint:
last model generated. Stores the location and confidence in self.finger_id
and self.confidence. Returns the packet error code or OK success"""
# high speed search of slot #1 starting at page 0x0000 and page #0x00A3
self._send_packet([_HISPEEDSEARCH, 0x01, 0x00, 0x00, 0x00, 0xA3])
# self._send_packet([_HISPEEDSEARCH, 0x01, 0x00, 0x00, 0x00, 0xA3])
# or page #0x03E9 to accommodate modules with up to 1000 capacity
# self._send_packet([_HISPEEDSEARCH, 0x01, 0x00, 0x00, 0x03, 0xE9])
# or base the page on module's capacity
self.read_sysparam()
capacity = self.library_size
self._send_packet(
[_HISPEEDSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF]
)
r = self._get_packet(16)
self.finger_id, self.confidence = struct.unpack('>HH', bytes(r[1:5]))
self.finger_id, self.confidence = struct.unpack(">HH", bytes(r[1:5]))
# print(r)
return r[0]
##################################################
def finger_search(self):
"""Asks the sensor to search for a matching fingerprint starting at
slot 1. Stores the location and confidence in self.finger_id
and self.confidence. Returns the packet error code or OK success"""
self.read_sysparam()
capacity = self.library_size
self._send_packet(
[_FINGERPRINTSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF]
)
r = self._get_packet(16)
self.finger_id, self.confidence = struct.unpack(">HH", bytes(r[1:5]))
# print(r)
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)
# print("Got", res)
if (not res) or (len(res) != expected):
raise RuntimeError('Failed to read data from sensor')
raise RuntimeError("Failed to read data from sensor")
# first two bytes are start code
start = struct.unpack('>H', res[0:2])[0]
start = struct.unpack(">H", res[0:2])[0]
if start != _STARTCODE:
raise RuntimeError('Incorrect packet data')
raise RuntimeError("Incorrect packet data")
# next 4 bytes are address
addr = [i for i in res[2:6]]
addr = list(i for i in res[2:6])
if addr != self.address:
raise RuntimeError('Incorrect address')
raise RuntimeError("Incorrect address")
packet_type, length = struct.unpack('>BH', res[6:9])
packet_type, length = struct.unpack(">BH", res[6:9])
if packet_type != _ACKPACKET:
raise RuntimeError('Incorrect packet data')
raise RuntimeError("Incorrect packet data")
reply = [i for i in res[9:9+(length-2)]]
#print(reply)
# we should check the checksum
# but i don't know how
# not yet anyway
# packet_sum = struct.unpack('>H', res[9+(length-2):9+length])[0]
# print(packet_sum)
# print(packet_type + length + struct.unpack('>HHHH', res[9:9+(length-2)]))
reply = list(i for i in res[9 : 9 + (length - 2)])
# print(reply)
return reply
def _get_data(self, expected):
""" Gets packet from serial and checks structure for _DATAPACKET
and _ENDDATAPACKET. Alternate method for getting data such
as fingerprint image, etc. Returns the data payload."""
res = self._uart.read(expected)
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:2])[0]
# print(start)
if start != _STARTCODE:
raise RuntimeError("Incorrect packet data")
# next 4 bytes are address
addr = list(i for i in res[2:6])
# print(addr)
if addr != self.address:
raise RuntimeError("Incorrect address")
packet_type, length = struct.unpack(">BH", res[6:9])
# print(str(packet_type) + ' ' + str(length))
# todo: check checksum
if packet_type != _DATAPACKET:
if packet_type != _ENDDATAPACKET:
raise RuntimeError("Incorrect packet data")
if packet_type == _DATAPACKET:
res = self._uart.read(length - 2)
# todo: we should really inspect the headers and checksum
reply = list(i for i in res[0:length])
self._uart.read(2) # disregard checksum but we really shouldn't
reply += self._get_data(9)
elif packet_type == _ENDDATAPACKET:
res = self._uart.read(length - 2)
# todo: we should really inspect the headers and checksum
reply = list(i for i in res[0:length])
self._uart.read(2) # disregard checksum but we really shouldn't
# print(len(reply))
# print(reply)
return reply
def _send_packet(self, data):
@ -220,5 +394,72 @@ class Adafruit_Fingerprint:
packet.append(checksum >> 8)
packet.append(checksum & 0xFF)
#print("Sending: ", [hex(i) for i in packet])
# print("Sending: ", [hex(i) for i in packet])
self._uart.write(bytearray(packet))
def _send_data(self, data):
print(len(data))
self.read_sysparam()
if self.data_packet_size == 0:
data_length = 32
elif self.data_packet_size == 1:
data_length = 64
elif self.data_packet_size == 2:
data_length = 128
elif self.data_packet_size == 3:
data_length = 256
i = 0
for i in range(int(len(data) / (data_length - 2))):
start = i * (data_length - 2)
end = (i + 1) * (data_length - 2)
# print(start)
# print(end)
# print(i)
packet = [_STARTCODE >> 8, _STARTCODE & 0xFF]
packet = packet + self.address
packet.append(_DATAPACKET)
length = len(data[start:end]) + 2
# print(length)
packet.append(length >> 8)
packet.append(length & 0xFF)
checksum = _DATAPACKET + (length >> 8) + (length & 0xFF)
for j in range(len(data[start:end])):
packet.append(data[j])
checksum += data[j]
packet.append(checksum >> 8)
packet.append(checksum & 0xFF)
# print("Sending: ", [hex(i) for i in packet])
self._uart.write(packet)
# print(i)
i += 1
start = i * (data_length - 2)
end = (i + 1) * (data_length - 2)
# print(start)
# print(end)
# print(i)
packet = [_STARTCODE >> 8, _STARTCODE & 0xFF]
packet = packet + self.address
packet.append(_ENDDATAPACKET)
length = len(data[start:end]) + 2
# print(length)
packet.append(length >> 8)
packet.append(length & 0xFF)
checksum = _ENDDATAPACKET + (length >> 8) + (length & 0xFF)
for j in range(len(data[start:end])):
packet.append(data[j])
checksum += data[j]
packet.append(checksum >> 8)
packet.append(checksum & 0xFF)
# print("Sending: ", [hex(i) for i in packet])
self._uart.write(packet)
# print(i)

View file

@ -2,7 +2,8 @@
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath(".."))
# -- General configuration ------------------------------------------------
@ -10,9 +11,9 @@ sys.path.insert(0, os.path.abspath('..'))
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.viewcode",
]
# Uncomment the below if you use native CircuitPython modules such as
@ -20,29 +21,32 @@ extensions = [
# autodoc module docs will fail to generate with a warning.
# autodoc_mock_imports = ["micropython"]
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}
intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
source_suffix = '.rst'
source_suffix = ".rst"
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = u'Adafruit Fingerprint Library'
copyright = u'2017 ladyada'
author = u'ladyada'
project = "Adafruit Fingerprint Library"
copyright = "2017 ladyada"
author = "ladyada"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'1.0'
version = "1.0"
# The full version, including alpha/beta/rc tags.
release = u'1.0'
release = "1.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -54,7 +58,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -66,7 +70,7 @@ default_role = "any"
add_function_parentheses = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -80,59 +84,62 @@ todo_emit_warnings = True
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.']
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
except:
html_theme = 'default'
html_theme_path = ['.']
html_theme = "default"
html_theme_path = ["."]
else:
html_theme_path = ['.']
html_theme_path = ["."]
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
html_favicon = '_static/favicon.ico'
html_favicon = "_static/favicon.ico"
# Output file base name for HTML help builder.
htmlhelp_basename = 'AdafruitFingerprintLibrarydoc'
htmlhelp_basename = "AdafruitFingerprintLibrarydoc"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'AdafruitFingerprintLibrary.tex', u'AdafruitFingerprint Library Documentation',
author, 'manual'),
(
master_doc,
"AdafruitFingerprintLibrary.tex",
"AdafruitFingerprint Library Documentation",
author,
"manual",
),
]
# -- Options for manual page output ---------------------------------------
@ -140,8 +147,13 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'AdafruitFingerprintlibrary', u'Adafruit Fingerprint Library Documentation',
[author], 1)
(
master_doc,
"AdafruitFingerprintlibrary",
"Adafruit Fingerprint Library Documentation",
[author],
1,
)
]
# -- Options for Texinfo output -------------------------------------------
@ -150,7 +162,13 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'AdafruitFingerprintLibrary', u'Adafruit Fingerprint Library Documentation',
author, 'AdafruitFingerprintLibrary', 'One line description of project.',
'Miscellaneous'),
(
master_doc,
"AdafruitFingerprintLibrary",
"Adafruit Fingerprint Library Documentation",
author,
"AdafruitFingerprintLibrary",
"One line description of project.",
"Miscellaneous",
),
]

View file

@ -10,12 +10,12 @@ led.direction = Direction.OUTPUT
uart = busio.UART(board.TX, board.RX, baudrate=57600)
# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter:
#import serial
#uart = serial.Serial("/dev/ttyUSB0", baudrate=57600, timeout=1)
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=57600, timeout=1)
# If using with Linux/Raspberry Pi and hardware UART:
#import serial
#uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1)
# import serial
# uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)
@ -31,10 +31,11 @@ def get_fingerprint():
if finger.image_2_tz(1) != adafruit_fingerprint.OK:
return False
print("Searching...")
if finger.finger_fast_search() != adafruit_fingerprint.OK:
if finger.finger_search() != adafruit_fingerprint.OK:
return False
return True
# pylint: disable=too-many-branches
def get_fingerprint_detail():
"""Get a finger print image, template it, and see if it matches!
@ -81,6 +82,7 @@ def get_fingerprint_detail():
print("Other error")
return False
# pylint: disable=too-many-statements
def enroll_finger(location):
"""Take a 2 finger images and template it, then store in 'location'"""
@ -95,7 +97,7 @@ def enroll_finger(location):
if i == adafruit_fingerprint.OK:
print("Image taken")
break
elif i == adafruit_fingerprint.NOFINGER:
if i == adafruit_fingerprint.NOFINGER:
print(".", end="", flush=True)
elif i == adafruit_fingerprint.IMAGEFAIL:
print("Imaging error")
@ -154,6 +156,7 @@ def enroll_finger(location):
##################################################
def get_num():
"""Use input() to get a valid number from 1 to 127. Retry till success!"""
i = 0
@ -168,7 +171,7 @@ def get_num():
while True:
print("----------------")
if finger.read_templates() != adafruit_fingerprint.OK:
raise RuntimeError('Failed to read templates')
raise RuntimeError("Failed to read templates")
print("Fingerprint templates:", finger.templates)
print("e) enroll print")
print("f) find print")
@ -176,14 +179,14 @@ while True:
print("----------------")
c = input("> ")
if c == 'e':
if c == "e":
enroll_finger(get_num())
if c == 'f':
if c == "f":
if get_fingerprint():
print("Detected #", finger.finger_id, "with confidence", finger.confidence)
else:
print("Finger not found")
if c == 'd':
if c == "d":
if finger.delete_model(get_num()) == adafruit_fingerprint.OK:
print("Deleted!")
else:

View file

@ -0,0 +1,259 @@
import time
import serial
import board
# import busio
from digitalio import DigitalInOut, Direction
import adafruit_fingerprint
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT
# uart = busio.UART(board.TX, board.RX, baudrate=57600)
# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter:
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=57600, timeout=1)
# If using with Linux/Raspberry Pi and hardware UART:
# import serial
# uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1)
# If using with Linux/Raspberry Pi 3 with pi3-disable-bt
# import serial
uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)
##################################################
def get_fingerprint():
"""Get a finger print image, template it, and see if it matches!"""
print("Waiting for image...")
while finger.get_image() != adafruit_fingerprint.OK:
pass
print("Templating...")
if finger.image_2_tz(1) != adafruit_fingerprint.OK:
return False
print("Searching...")
if finger.finger_search() != adafruit_fingerprint.OK:
return False
return True
# pylint: disable=too-many-branches
def get_fingerprint_detail():
"""Get a finger print image, template it, and see if it matches!
This time, print out each error instead of just returning on failure"""
print("Getting image...", end="", flush=True)
i = finger.get_image()
if i == adafruit_fingerprint.OK:
print("Image taken")
else:
if i == adafruit_fingerprint.NOFINGER:
print("No finger detected")
elif i == adafruit_fingerprint.IMAGEFAIL:
print("Imaging error")
else:
print("Other error")
return False
print("Templating...", end="", flush=True)
i = finger.image_2_tz(1)
if i == adafruit_fingerprint.OK:
print("Templated")
else:
if i == adafruit_fingerprint.IMAGEMESS:
print("Image too messy")
elif i == adafruit_fingerprint.FEATUREFAIL:
print("Could not identify features")
elif i == adafruit_fingerprint.INVALIDIMAGE:
print("Image invalid")
else:
print("Other error")
return False
print("Searching...", end="", flush=True)
i = finger.finger_fast_search()
# pylint: disable=no-else-return
# This block needs to be refactored when it can be tested.
if i == adafruit_fingerprint.OK:
print("Found fingerprint!")
return True
else:
if i == adafruit_fingerprint.NOTFOUND:
print("No match found")
else:
print("Other error")
return False
# pylint: disable=too-many-statements
def enroll_finger(location):
"""Take a 2 finger images and template it, then store in 'location'"""
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:
print("Imaging error")
return False
else:
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:
print("Image too messy")
elif i == adafruit_fingerprint.FEATUREFAIL:
print("Could not identify features")
elif i == adafruit_fingerprint.INVALIDIMAGE:
print("Image invalid")
else:
print("Other error")
return False
if fingerimg == 1:
print("Remove finger")
time.sleep(1)
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:
print("Prints did not match")
else:
print("Other error")
return False
print("Storing model #%d..." % location, end="", flush=True)
i = finger.store_model(location)
if i == adafruit_fingerprint.OK:
print("Stored")
else:
if i == adafruit_fingerprint.BADLOCATION:
print("Bad storage location")
elif i == adafruit_fingerprint.FLASHERR:
print("Flash storage error")
else:
print("Other error")
return False
return True
def save_fingerprint_image(filename):
"""Scan fingerprint then save image to filename."""
while finger.get_image():
pass
# let PIL take care of the image headers and file structure
from PIL import Image # pylint: disable=import-outside-toplevel
img = Image.new("L", (256, 288), "white")
pixeldata = img.load()
mask = 0b00001111
result = finger.get_fpdata(sensorbuffer="image")
# this block "unpacks" the data received from the fingerprint
# module then copies the image data to the image placeholder "img"
# pixel by pixel. please refer to section 4.2.1 of the manual for
# more details. thanks to Bastian Raschke and Danylo Esterman.
# pylint: disable=invalid-name
x = 0
# pylint: disable=invalid-name
y = 0
# pylint: disable=consider-using-enumerate
for i in range(len(result)):
pixeldata[x, y] = (int(result[i]) >> 4) * 17
x += 1
pixeldata[x, y] = (int(result[i]) & mask) * 17
if x == 255:
x = 0
y += 1
else:
x += 1
if not img.save(filename):
return True
return False
##################################################
def get_num(max_number):
"""Use input() to get a valid number from 0 to the maximum size
of the library. Retry till success!"""
i = -1
while (i > max_number - 1) or (i < 0):
try:
i = int(input("Enter ID # from 0-{}: ".format(max_number - 1)))
except ValueError:
pass
return i
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.read_sysparam() != adafruit_fingerprint.OK:
raise RuntimeError("Failed to get system parameters")
print("Size of template library: ", finger.library_size)
print("e) enroll print")
print("f) find print")
print("d) delete print")
print("s) save fingerprint image")
print("r) reset library")
print("q) quit")
print("----------------")
c = input("> ")
if c == "e":
enroll_finger(get_num(finger.library_size))
if c == "f":
if get_fingerprint():
print("Detected #", finger.finger_id, "with confidence", finger.confidence)
else:
print("Finger not found")
if c == "d":
if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK:
print("Deleted!")
else:
print("Failed to delete")
if c == "s":
if save_fingerprint_image("fingerprint.png"):
print("Fingerprint image saved")
else:
print("Failed to save fingerprint image")
if c == "r":
if finger.empty_library() == adafruit_fingerprint.OK:
print("Library empty!")
else:
print("Failed to empty library")
if c == "q":
print("Exiting fingerprint example program")
raise SystemExit

View file

@ -7,6 +7,7 @@ https://github.com/pypa/sampleproject
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
@ -14,47 +15,38 @@ from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name='adafruit-circuitpython-fingerprint',
name="adafruit-circuitpython-fingerprint",
use_scm_version=True,
setup_requires=['setuptools_scm'],
description='CircuitPython library for UART fingerprint sensor.',
setup_requires=["setuptools_scm"],
description="CircuitPython library for UART fingerprint sensor.",
long_description=long_description,
long_description_content_type='text/x-rst',
long_description_content_type="text/x-rst",
# The project's main homepage.
url='https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint',
url="https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint",
# Author details
author='Adafruit Industries',
author_email='circuitpython@adafruit.com',
install_requires=['Adafruit-Blinka', 'pyserial'],
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=["Adafruit-Blinka", "pyserial"],
# Choose your license
license='MIT',
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Libraries',
'Topic :: System :: Hardware',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords='adafruit uart fingerprint finger print sensor hardware micropython circuitpython',
keywords="adafruit uart fingerprint finger print sensor hardware micropython circuitpython",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
py_modules=['adafruit_fingerprint'],
py_modules=["adafruit_fingerprint"],
)