mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
Compare commits
167 Commits
wip/benzea
...
benzea/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1fdc7b01b | ||
|
|
1e2f19ea3d | ||
|
|
b0effae990 | ||
|
|
ff67bf5a16 | ||
|
|
bac6382f67 | ||
|
|
e12978f402 | ||
|
|
1ba95db379 | ||
|
|
7ec2df2405 | ||
|
|
3ed73aa17c | ||
|
|
0241617713 | ||
|
|
20a52593eb | ||
|
|
42db16364d | ||
|
|
ee606ae49e | ||
|
|
f9b2c7f9c3 | ||
|
|
4115ae7ced | ||
|
|
8cc0fd321f | ||
|
|
a7541b1f76 | ||
|
|
b9ff75c4e9 | ||
|
|
4447a0d183 | ||
|
|
545af23536 | ||
|
|
db905a2048 | ||
|
|
712853d1e3 | ||
|
|
c6298ede72 | ||
|
|
b1d99e7608 | ||
|
|
5927a205e3 | ||
|
|
8c05f3b78c | ||
|
|
92db82e3d4 | ||
|
|
f6f689f9cd | ||
|
|
5dc3edf07c | ||
|
|
71625ec1cf | ||
|
|
c9216cf96c | ||
|
|
53713c0098 | ||
|
|
222c33ec32 | ||
|
|
19a50cfdc3 | ||
|
|
9892eb1c03 | ||
|
|
587131a6bd | ||
|
|
65d0d5e3e0 | ||
|
|
2642fc6560 | ||
|
|
a855c0cc79 | ||
|
|
876924df6a | ||
|
|
519b5acc91 | ||
|
|
e812653acd | ||
|
|
1b23f0efe1 | ||
|
|
f6559ba8b1 | ||
|
|
3b72b925b0 | ||
|
|
15d218a112 | ||
|
|
0a08a24896 | ||
|
|
cca6d3b04b | ||
|
|
be367988ae | ||
|
|
ea4da08af0 | ||
|
|
60ad1ab9e3 | ||
|
|
201b5a9614 | ||
|
|
8b270141f3 | ||
|
|
ceb62d7617 | ||
|
|
099fa9f005 | ||
|
|
dd7d1baece | ||
|
|
d8efa336e5 | ||
|
|
76dd4066f3 | ||
|
|
9b48864c5b | ||
|
|
14a41bdd48 | ||
|
|
25bc89a4f5 | ||
|
|
2f0824ab88 | ||
|
|
8ba6f4dad2 | ||
|
|
ada5d488fa | ||
|
|
b16245ad58 | ||
|
|
8b28133bee | ||
|
|
7a4dd96406 | ||
|
|
81a446db82 | ||
|
|
7bc62821ee | ||
|
|
1319daba54 | ||
|
|
39e3e2b794 | ||
|
|
ab804f7f49 | ||
|
|
f2b932960e | ||
|
|
d1fb1e26f3 | ||
|
|
fd5f511b33 | ||
|
|
cddd0f4653 | ||
|
|
256c7cea07 | ||
|
|
d91ec2d044 | ||
|
|
ad920f9597 | ||
|
|
728335581f | ||
|
|
9b37256175 | ||
|
|
951d482bc6 | ||
|
|
33530d62c7 | ||
|
|
65e602d8c7 | ||
|
|
6a1e7103f6 | ||
|
|
f25d0a0dc9 | ||
|
|
3b480caab1 | ||
|
|
dcc04089d1 | ||
|
|
0b87b21d52 | ||
|
|
b92e6d6acd | ||
|
|
538038867b | ||
|
|
e372311afe | ||
|
|
4a95f795cb | ||
|
|
fcfe82a7b8 | ||
|
|
a8d15bccba | ||
|
|
aec1b7caad | ||
|
|
5eba6067a3 | ||
|
|
664d18836e | ||
|
|
ac65cf455e | ||
|
|
b8bb08649d | ||
|
|
57866c45cd | ||
|
|
fbf4b45e76 | ||
|
|
431ed7210b | ||
|
|
043b31df70 | ||
|
|
2e30572364 | ||
|
|
fd64c46c74 | ||
|
|
61e49c2659 | ||
|
|
441b1238a5 | ||
|
|
0a47df7bb7 | ||
|
|
5e05afecf2 | ||
|
|
7ef64b5f5f | ||
|
|
0169fe8cf6 | ||
|
|
f119c273fd | ||
|
|
dac489b7f6 | ||
|
|
6ec11a2b26 | ||
|
|
4640e3f5b0 | ||
|
|
36777896c2 | ||
|
|
6e25a27870 | ||
|
|
0b4f682233 | ||
|
|
d184a7662c | ||
|
|
3f0a143037 | ||
|
|
b46d336d2b | ||
|
|
7d6b0c1376 | ||
|
|
dd40aeaa79 | ||
|
|
2b6f22b84d | ||
|
|
689aff0232 | ||
|
|
30a449841c | ||
|
|
56543e1311 | ||
|
|
9b175a7681 | ||
|
|
d67a801f1f | ||
|
|
95d7c0e800 | ||
|
|
059fc5ef7d | ||
|
|
7fed33fb49 | ||
|
|
ce9702571b | ||
|
|
01ec1c5777 | ||
|
|
ec8dd6410e | ||
|
|
45d7046f99 | ||
|
|
5fcd41b962 | ||
|
|
6ba8a15d3a | ||
|
|
5b615e33a0 | ||
|
|
823f2c1067 | ||
|
|
19732341d6 | ||
|
|
0e44eb4c1c | ||
|
|
50461b4d7d | ||
|
|
c11126181e | ||
|
|
658c301e3c | ||
|
|
dce52ed081 | ||
|
|
f309f586c9 | ||
|
|
ae1b10dba8 | ||
|
|
860a256f4b | ||
|
|
cb2f46ed08 | ||
|
|
13deaa66fd | ||
|
|
3597a5b0ed | ||
|
|
0352995cb3 | ||
|
|
e9041da7f4 | ||
|
|
252180e088 | ||
|
|
6361c208bd | ||
|
|
2ef8ace543 | ||
|
|
0400bcc85e | ||
|
|
76db6a5a16 | ||
|
|
5b171f9577 | ||
|
|
4cec28416e | ||
|
|
3b32baccf6 | ||
|
|
16875d7776 | ||
|
|
a9600e23a1 | ||
|
|
a4b6813ebf | ||
|
|
ef90938eb9 |
113
.ci/check-abi
Executable file
113
.ci/check-abi
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def format_title(title):
|
||||
box = {
|
||||
'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║',
|
||||
}
|
||||
hline = box['h'] * (len(title) + 2)
|
||||
|
||||
return '\n'.join([
|
||||
f"{box['tl']}{hline}{box['tr']}",
|
||||
f"{box['v']} {title} {box['v']}",
|
||||
f"{box['bl']}{hline}{box['br']}",
|
||||
])
|
||||
|
||||
|
||||
def rm_rf(path):
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def sanitize_path(name):
|
||||
return name.replace('/', '-')
|
||||
|
||||
|
||||
def get_current_revision():
|
||||
revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
|
||||
encoding='utf-8').strip()
|
||||
|
||||
if revision == 'HEAD':
|
||||
# This is a detached HEAD, get the commit hash
|
||||
revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')
|
||||
|
||||
return revision
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def checkout_git_revision(revision):
|
||||
current_revision = get_current_revision()
|
||||
subprocess.check_call(['git', 'checkout', '-q', revision])
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
subprocess.check_call(['git', 'checkout', '-q', current_revision])
|
||||
|
||||
|
||||
def build_install(revision):
|
||||
build_dir = '_build'
|
||||
dest_dir = os.path.abspath(sanitize_path(revision))
|
||||
print(format_title(f'# Building and installing {revision} in {dest_dir}'),
|
||||
end='\n\n', flush=True)
|
||||
|
||||
with checkout_git_revision(revision):
|
||||
rm_rf(build_dir)
|
||||
rm_rf(revision)
|
||||
|
||||
subprocess.check_call(['meson', build_dir,
|
||||
'--prefix=/usr', '--libdir=lib',
|
||||
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
|
||||
subprocess.check_call(['ninja', '-v', '-C', build_dir])
|
||||
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
|
||||
env={'DESTDIR': dest_dir})
|
||||
|
||||
return dest_dir
|
||||
|
||||
|
||||
def compare(old_tree, new_tree):
|
||||
print(format_title(f'# Comparing the two ABIs'), end='\n\n', flush=True)
|
||||
|
||||
old_headers = os.path.join(old_tree, 'usr', 'include')
|
||||
old_lib = os.path.join(old_tree, 'usr', 'lib', 'libfprint.so')
|
||||
|
||||
new_headers = os.path.join(new_tree, 'usr', 'include')
|
||||
new_lib = os.path.join(new_tree, 'usr', 'lib', 'libfprint.so')
|
||||
|
||||
subprocess.check_call([
|
||||
'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers,
|
||||
'--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('old', help='the previous revision, considered the reference')
|
||||
parser.add_argument('new', help='the new revision, to compare to the reference')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.old == args.new:
|
||||
print("Let's not waste time comparing something to itself")
|
||||
sys.exit(0)
|
||||
|
||||
old_tree = build_install(args.old)
|
||||
new_tree = build_install(args.new)
|
||||
|
||||
try:
|
||||
compare(old_tree, new_tree)
|
||||
|
||||
except Exception:
|
||||
sys.exit(1)
|
||||
|
||||
print(f'Hurray! {args.old} and {args.new} are ABI-compatible!')
|
||||
@@ -1,18 +1,22 @@
|
||||
image: fedora:rawhide
|
||||
stages:
|
||||
- check-source
|
||||
- build
|
||||
- test
|
||||
- flatpack
|
||||
|
||||
variables:
|
||||
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
|
||||
DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
|
||||
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
|
||||
gobject-introspection-devel python3-cairo python3-gobject umockdev
|
||||
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||
|
||||
.build_one_driver_template: &build_one_driver
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||
# Build with a driver that doesn't need imaging, or nss
|
||||
- meson -Ddrivers=elan . _build
|
||||
- meson -Ddrivers=$driver . _build
|
||||
- ninja -C _build
|
||||
- rm -rf _build/
|
||||
|
||||
@@ -24,10 +28,40 @@ variables:
|
||||
- ninja -C _build
|
||||
- ninja -C _build install
|
||||
|
||||
.build_template: &check_abi
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES doxygen libabigail git
|
||||
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
|
||||
|
||||
build:
|
||||
stage: build
|
||||
variables:
|
||||
driver: virtual_image
|
||||
<<: *build_one_driver
|
||||
<<: *build
|
||||
# <<: *check_abi
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||
- meson -Ddrivers=all . _build
|
||||
- ninja -C _build
|
||||
- meson test -C _build --verbose --no-stdsplit
|
||||
|
||||
test_valgrind:
|
||||
stage: test
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES valgrind
|
||||
- meson -Ddrivers=all . _build
|
||||
- ninja -C _build
|
||||
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
|
||||
|
||||
test_indent:
|
||||
stage: check-source
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck git uncrustify
|
||||
- scripts/uncrustify.sh --check
|
||||
|
||||
.flatpak_script_template: &flatpak_script
|
||||
script:
|
||||
@@ -53,8 +87,8 @@ build:
|
||||
<<: *flatpak_artifacts
|
||||
|
||||
flatpak master:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
|
||||
stage: test
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
|
||||
stage: flatpack
|
||||
variables:
|
||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||
# From demo/org.freedesktop.libfprint.Demo.json
|
||||
|
||||
25
HACKING.md
25
HACKING.md
@@ -3,8 +3,29 @@
|
||||
## GLib
|
||||
|
||||
Although the library uses GLib internally, libfprint is designed to provide
|
||||
a completely neutral interface to it's application users. So, the public
|
||||
APIs should never return GLib data types or anything like that.
|
||||
a completely neutral interface to its application users. So, the public
|
||||
APIs should never return GLib data types.
|
||||
|
||||
## License clarification
|
||||
|
||||
Although this library's license could allow for shims that hook up into
|
||||
proprietary blobs to add driver support for some unsupported devices, the
|
||||
intent of the original authors, and of current maintainers of the library,
|
||||
was for this license to allow _integration into_ proprietary stacks, not
|
||||
_integration of_ proprietary code in the library.
|
||||
|
||||
As such, no code to integrate proprietary drivers will be accepted in libfprint
|
||||
upstream. Proprietary drivers would make it impossible to debug problems in
|
||||
libfprint, as we wouldn't know what the proprietary driver does behind the
|
||||
library's back. The closed source nature of drivers is usually used to hide
|
||||
parts of the hardware setup, such as encryption keys, or protocols, in order
|
||||
to protect the hardware's integrity. Unfortunately, this is only [security through
|
||||
obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
|
||||
|
||||
We however encourage potential contributors to take advantage of libfprint's
|
||||
source availability to create such shims to make it easier to reverse-engineer
|
||||
proprietary drivers in order to create new free software drivers, to the extent
|
||||
permitted by local laws.
|
||||
|
||||
## Two-faced-ness
|
||||
|
||||
|
||||
48
NEWS
48
NEWS
@@ -1,6 +1,54 @@
|
||||
This file lists notable changes in each release. For the full history of all
|
||||
changes, see ChangeLog.
|
||||
|
||||
2019-11-20: v1.90.0 release
|
||||
|
||||
This release updates the core of the library to use GLib routines and Gio
|
||||
style APIs. While the API both for library users remain similar in most
|
||||
ways, there are some changes and all users will need to be ported.
|
||||
|
||||
A large motivation for the in-depth changes was the requirement to add
|
||||
new API to support sensors that store the prints on the sensor. This
|
||||
support is already used by the new synaptics driver, which will support
|
||||
the current generation of the Prometheus MIS (match-in-sensor) chipset
|
||||
by Synaptics (USB ID 06cb:00bd).
|
||||
|
||||
The current codebase is considered stable at this point. However, due to
|
||||
the lack of wider testing it is only released as a 1.90.0 release which
|
||||
can be considered a beta-release for 2.0.
|
||||
|
||||
With the rewrite, it is now also possible to support devices that are not
|
||||
connected through USB (e.g. I2C). Another major improvement is that the
|
||||
library has now a test suite, testing both the library core and allowing
|
||||
tests of the drivers using umockdev.
|
||||
|
||||
2019-08-08: v1.0 release
|
||||
* Library:
|
||||
- Add guards to the public API and require GLib 2.50
|
||||
- Deprecate print storage API
|
||||
- Better documentation for fp_discover_devs()
|
||||
- Remove unused internal fpi_timeout_cancel_for_dev()
|
||||
- Remove state from fp_img_driver activate handler
|
||||
- Bug fixes related to restarting a failed verification immediately
|
||||
|
||||
* Drivers:
|
||||
- The Elan driver received a lot of bug fixes including a fix for a
|
||||
hang when verifying prints with fprintd, quirks for some devices,
|
||||
a memory leak fix and support for 04f3:0c42
|
||||
- Fix a probable crash in all the AES drivers
|
||||
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
|
||||
- Prevent hang during enroll process in etes603 driver
|
||||
- Fix possible integer overflow in uru4000
|
||||
- Work-around SELinux AVC warnings when uru4000 driver starts
|
||||
- Remove long-unmaintained and broken fdu2000 driver
|
||||
|
||||
* Tools/Examples:
|
||||
- Fix examples not working due to an overly strict check
|
||||
- Fix crash in GTK demo when there's no supported devices
|
||||
- Disable GTK demo until we have a USB Flatpak portal
|
||||
- Remove sleep() in enroll example which caused a crash in some drivers
|
||||
- Add a simple storage implementation example
|
||||
|
||||
2018-12-14: v0.99.0 release
|
||||
* Library:
|
||||
- All the internal API for device driver writers is now covered by the
|
||||
|
||||
3
code-of-conduct.md
Normal file
3
code-of-conduct.md
Normal file
@@ -0,0 +1,3 @@
|
||||
This project and its community follow the [Freedesktop.org code of conduct]
|
||||
|
||||
[Freedesktop.org code of conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/
|
||||
@@ -22,34 +22,36 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
#include "loop.h"
|
||||
|
||||
typedef GtkApplication LibfprintDemo;
|
||||
typedef GtkApplication LibfprintDemo;
|
||||
typedef GtkApplicationClass LibfprintDemoClass;
|
||||
|
||||
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
||||
|
||||
typedef enum {
|
||||
IMAGE_DISPLAY_NONE = 0,
|
||||
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
|
||||
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||
IMAGE_DISPLAY_NONE = 0,
|
||||
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
|
||||
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||
} ImageDisplayFlags;
|
||||
|
||||
typedef struct {
|
||||
GtkApplicationWindow parent_instance;
|
||||
typedef struct
|
||||
{
|
||||
GtkApplicationWindow parent_instance;
|
||||
|
||||
GtkWidget *header_bar;
|
||||
GtkWidget *mode_stack;
|
||||
GtkWidget *capture_button;
|
||||
GtkWidget *capture_image;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *instructions;
|
||||
GtkWidget *header_bar;
|
||||
GtkWidget *mode_stack;
|
||||
GtkWidget *capture_button;
|
||||
GtkWidget *cancel_button;
|
||||
GtkWidget *capture_image;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *instructions;
|
||||
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dev *dev;
|
||||
GCancellable *cancellable;
|
||||
|
||||
struct fp_img *img;
|
||||
ImageDisplayFlags img_flags;
|
||||
gboolean opened;
|
||||
FpDevice *dev;
|
||||
|
||||
FpImage *img;
|
||||
ImageDisplayFlags img_flags;
|
||||
} LibfprintDemoWindow;
|
||||
|
||||
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
|
||||
@@ -57,467 +59,506 @@ typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
|
||||
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
|
||||
typedef enum {
|
||||
EMPTY_MODE,
|
||||
NOIMAGING_MODE,
|
||||
CAPTURE_MODE,
|
||||
SPINNER_MODE,
|
||||
ERROR_MODE
|
||||
EMPTY_MODE,
|
||||
NOIMAGING_MODE,
|
||||
CAPTURE_MODE,
|
||||
SPINNER_MODE,
|
||||
ERROR_MODE,
|
||||
RETRY_MODE
|
||||
} LibfprintDemoMode;
|
||||
|
||||
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||
LibfprintDemoMode mode);
|
||||
|
||||
static void
|
||||
pixbuf_destroy (guchar *pixels, gpointer data)
|
||||
{
|
||||
if (pixels == NULL)
|
||||
return;
|
||||
g_free (pixels);
|
||||
}
|
||||
LibfprintDemoMode mode);
|
||||
|
||||
static unsigned char *
|
||||
img_to_rgbdata (struct fp_img *img,
|
||||
int width,
|
||||
int height)
|
||||
img_to_rgbdata (const guint8 *imgdata,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int size = width * height;
|
||||
unsigned char *imgdata = fp_img_get_data (img);
|
||||
unsigned char *rgbdata = g_malloc (size * 3);
|
||||
size_t i;
|
||||
size_t rgb_offset = 0;
|
||||
int size = width * height;
|
||||
guint8 *rgbdata = g_malloc (size * 3);
|
||||
size_t i;
|
||||
size_t rgb_offset = 0;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
unsigned char pixel = imgdata[i];
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
guint8 pixel = imgdata[i];
|
||||
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
}
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
}
|
||||
|
||||
return rgbdata;
|
||||
return rgbdata;
|
||||
}
|
||||
|
||||
static void
|
||||
plot_minutiae (unsigned char *rgbdata,
|
||||
int width,
|
||||
int height,
|
||||
struct fp_minutia **minlist,
|
||||
int nr_minutiae)
|
||||
plot_minutiae (unsigned char *rgbdata,
|
||||
int width,
|
||||
int height,
|
||||
GPtrArray *minutiae)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
#define write_pixel(num) do { \
|
||||
rgbdata[((num) * 3)] = 0xff; \
|
||||
rgbdata[((num) * 3) + 1] = 0; \
|
||||
rgbdata[((num) * 3) + 2] = 0; \
|
||||
} while(0)
|
||||
rgbdata[((num) * 3)] = 0xff; \
|
||||
rgbdata[((num) * 3) + 1] = 0; \
|
||||
rgbdata[((num) * 3) + 2] = 0; \
|
||||
} while(0)
|
||||
|
||||
for (i = 0; i < nr_minutiae; i++) {
|
||||
struct fp_minutia *min = minlist[i];
|
||||
int x, y;
|
||||
size_t pixel_offset;
|
||||
for (i = 0; i < minutiae->len; i++)
|
||||
{
|
||||
struct fp_minutia *min = g_ptr_array_index (minutiae, i);
|
||||
int x, y;
|
||||
size_t pixel_offset;
|
||||
|
||||
fp_minutia_get_coords(min, &x, &y);
|
||||
pixel_offset = (y * width) + x;
|
||||
write_pixel(pixel_offset - 2);
|
||||
write_pixel(pixel_offset - 1);
|
||||
write_pixel(pixel_offset);
|
||||
write_pixel(pixel_offset + 1);
|
||||
write_pixel(pixel_offset + 2);
|
||||
fp_minutia_get_coords (min, &x, &y);
|
||||
pixel_offset = (y * width) + x;
|
||||
write_pixel (pixel_offset - 2);
|
||||
write_pixel (pixel_offset - 1);
|
||||
write_pixel (pixel_offset);
|
||||
write_pixel (pixel_offset + 1);
|
||||
write_pixel (pixel_offset + 2);
|
||||
|
||||
write_pixel(pixel_offset - (width * 2));
|
||||
write_pixel(pixel_offset - (width * 1) - 1);
|
||||
write_pixel(pixel_offset - (width * 1));
|
||||
write_pixel(pixel_offset - (width * 1) + 1);
|
||||
write_pixel(pixel_offset + (width * 1) - 1);
|
||||
write_pixel(pixel_offset + (width * 1));
|
||||
write_pixel(pixel_offset + (width * 1) + 1);
|
||||
write_pixel(pixel_offset + (width * 2));
|
||||
}
|
||||
write_pixel (pixel_offset - (width * 2));
|
||||
write_pixel (pixel_offset - (width * 1) - 1);
|
||||
write_pixel (pixel_offset - (width * 1));
|
||||
write_pixel (pixel_offset - (width * 1) + 1);
|
||||
write_pixel (pixel_offset + (width * 1) - 1);
|
||||
write_pixel (pixel_offset + (width * 1));
|
||||
write_pixel (pixel_offset + (width * 1) + 1);
|
||||
write_pixel (pixel_offset + (width * 2));
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
img_to_pixbuf (struct fp_img *img,
|
||||
ImageDisplayFlags flags)
|
||||
img_to_pixbuf (FpImage *img,
|
||||
ImageDisplayFlags flags)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
unsigned char *rgbdata;
|
||||
int width;
|
||||
int height;
|
||||
const guint8 *data;
|
||||
unsigned char *rgbdata;
|
||||
|
||||
width = fp_img_get_width (img);
|
||||
height = fp_img_get_height (img);
|
||||
width = fp_image_get_width (img);
|
||||
height = fp_image_get_height (img);
|
||||
|
||||
if (flags & IMAGE_DISPLAY_BINARY) {
|
||||
struct fp_img *binary;
|
||||
binary = fp_img_binarize (img);
|
||||
rgbdata = img_to_rgbdata (binary, width, height);
|
||||
fp_img_free (binary);
|
||||
} else {
|
||||
rgbdata = img_to_rgbdata (img, width, height);
|
||||
}
|
||||
if (flags & IMAGE_DISPLAY_BINARY)
|
||||
data = fp_image_get_binarized (img, NULL);
|
||||
else
|
||||
data = fp_image_get_data (img, NULL);
|
||||
|
||||
if (flags & IMAGE_DISPLAY_MINUTIAE) {
|
||||
struct fp_minutia **minlist;
|
||||
int nr_minutiae;
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
minlist = fp_img_get_minutiae (img, &nr_minutiae);
|
||||
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
|
||||
}
|
||||
rgbdata = img_to_rgbdata (data, width, height);
|
||||
|
||||
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||
FALSE, 8, width, height,
|
||||
width * 3, pixbuf_destroy,
|
||||
NULL);
|
||||
if (flags & IMAGE_DISPLAY_MINUTIAE)
|
||||
{
|
||||
GPtrArray *minutiae;
|
||||
|
||||
minutiae = fp_image_get_minutiae (img);
|
||||
plot_minutiae (rgbdata, width, height, minutiae);
|
||||
}
|
||||
|
||||
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||
FALSE, 8, width, height,
|
||||
width * 3, (GdkPixbufDestroyNotify) g_free,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_image (LibfprintDemoWindow *win)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
if (win->img == NULL) {
|
||||
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||
return;
|
||||
}
|
||||
if (win->img == NULL)
|
||||
{
|
||||
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||
return;
|
||||
}
|
||||
|
||||
g_debug ("Updating image, minutiae %s, binary mode %s",
|
||||
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
|
||||
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
|
||||
pixbuf = img_to_pixbuf (win->img, win->img_flags);
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
g_debug ("Updating image, minutiae %s, binary mode %s",
|
||||
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
|
||||
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
|
||||
pixbuf = img_to_pixbuf (win->img, win->img_flags);
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
|
||||
const char *message)
|
||||
const char *message)
|
||||
{
|
||||
char *label;
|
||||
char *label;
|
||||
|
||||
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
|
||||
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
|
||||
g_free (label);
|
||||
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
|
||||
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||
{
|
||||
struct fp_driver *drv;
|
||||
enum fp_scan_type scan_type;
|
||||
const char *message;
|
||||
FpScanType scan_type;
|
||||
const char *message;
|
||||
|
||||
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||
scan_type = fp_driver_get_scan_type(drv);
|
||||
scan_type = fp_device_get_scan_type (win->dev);
|
||||
|
||||
switch (scan_type) {
|
||||
case FP_SCAN_TYPE_PRESS:
|
||||
message = "Place your finger on the fingerprint reader";
|
||||
break;
|
||||
case FP_SCAN_TYPE_SWIPE:
|
||||
message = "Swipe your finger across the fingerprint reader";
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
switch (scan_type)
|
||||
{
|
||||
case FP_SCAN_TYPE_PRESS:
|
||||
message = "Place your finger on the fingerprint reader";
|
||||
break;
|
||||
|
||||
libfprint_demo_set_spinner_label (win, message);
|
||||
case FP_SCAN_TYPE_SWIPE:
|
||||
message = "Swipe your finger across the fingerprint reader";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
libfprint_demo_set_spinner_label (win, message);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_capture_start_cb (struct fp_dev *dev,
|
||||
int result,
|
||||
struct fp_img *img,
|
||||
void *user_data)
|
||||
dev_capture_start_cb (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
void *user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
g_autoptr(GError) error = NULL;
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
FpImage *image = NULL;
|
||||
|
||||
if (result < 0) {
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
g_clear_object (&win->cancellable);
|
||||
|
||||
fp_async_capture_stop (dev, NULL, NULL);
|
||||
image = fp_device_capture_finish (dev, res, &error);
|
||||
if (!image)
|
||||
{
|
||||
g_warning ("Error capturing data: %s", error->message);
|
||||
if (error->domain == FP_DEVICE_RETRY ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
libfprint_demo_set_mode (win, RETRY_MODE);
|
||||
else
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
win->img = img;
|
||||
update_image (win);
|
||||
g_clear_object (&win->img);
|
||||
win->img = image;
|
||||
update_image (win);
|
||||
|
||||
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
|
||||
dev_start_capture (LibfprintDemoWindow *win)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
int r;
|
||||
libfprint_demo_set_capture_label (win);
|
||||
|
||||
if (status < 0) {
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win);
|
||||
}
|
||||
|
||||
libfprint_demo_set_capture_label (win);
|
||||
static void
|
||||
dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
|
||||
win->dev = dev;
|
||||
r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data);
|
||||
if (r < 0) {
|
||||
g_warning ("fp_async_capture_start failed: %d", r);
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_start_capture (win);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_capture (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
int r;
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
|
||||
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||
g_clear_pointer (&win->img, fp_img_free);
|
||||
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||
g_clear_pointer (&win->img, g_object_unref);
|
||||
|
||||
if (win->dev != NULL) {
|
||||
dev_open_cb (win->dev, 0, user_data);
|
||||
return;
|
||||
}
|
||||
g_clear_object (&win->cancellable);
|
||||
win->cancellable = g_cancellable_new ();
|
||||
|
||||
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||
if (win->opened)
|
||||
{
|
||||
dev_start_capture (win);
|
||||
return;
|
||||
}
|
||||
|
||||
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
|
||||
if (r < 0) {
|
||||
g_warning ("fp_async_dev_open failed: %d", r);
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||
|
||||
win->opened = TRUE;
|
||||
fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_capture (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
|
||||
g_debug ("cancelling %p", win->cancellable);
|
||||
|
||||
if (win->cancellable)
|
||||
g_cancellable_cancel (win->cancellable);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_quit (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkApplication *app = user_data;
|
||||
GtkWidget *win;
|
||||
GList *list, *next;
|
||||
GtkApplication *app = user_data;
|
||||
GtkWidget *win;
|
||||
GList *list, *next;
|
||||
|
||||
list = gtk_application_get_windows (app);
|
||||
while (list)
|
||||
{
|
||||
win = list->data;
|
||||
next = list->next;
|
||||
list = gtk_application_get_windows (app);
|
||||
while (list)
|
||||
{
|
||||
win = list->data;
|
||||
next = list->next;
|
||||
|
||||
gtk_widget_destroy (GTK_WIDGET (win));
|
||||
gtk_widget_destroy (GTK_WIDGET (win));
|
||||
|
||||
list = next;
|
||||
}
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
activate_show_minutiae (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
|
||||
|
||||
update_image (win);
|
||||
update_image (win);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_show_binary (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_BINARY;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_BINARY;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
|
||||
|
||||
update_image (win);
|
||||
update_image (win);
|
||||
}
|
||||
|
||||
static void
|
||||
change_show_minutiae_state (GSimpleAction *action,
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_simple_action_set_state (action, state);
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static void
|
||||
change_show_binary_state (GSimpleAction *action,
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_simple_action_set_state (action, state);
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] = {
|
||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||
{ "capture", activate_capture, NULL, NULL, NULL }
|
||||
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||
{ "capture", activate_capture, NULL, NULL, NULL },
|
||||
{ "cancel", cancel_capture, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
activate (GApplication *app)
|
||||
{
|
||||
LibfprintDemoWindow *window;
|
||||
LibfprintDemoWindow *window;
|
||||
|
||||
window = g_object_new (libfprint_demo_window_get_type (),
|
||||
"application", app,
|
||||
NULL);
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
window = g_object_new (libfprint_demo_window_get_type (),
|
||||
"application", app,
|
||||
NULL);
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||
LibfprintDemoMode mode)
|
||||
LibfprintDemoMode mode)
|
||||
{
|
||||
struct fp_driver *drv;
|
||||
char *title;
|
||||
char *title;
|
||||
|
||||
switch (mode) {
|
||||
case EMPTY_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case NOIMAGING_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case CAPTURE_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||
switch (mode)
|
||||
{
|
||||
case EMPTY_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||
title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv));
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||
g_free (title);
|
||||
case NOIMAGING_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case SPINNER_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case ERROR_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
case CAPTURE_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||
|
||||
title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev));
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||
g_free (title);
|
||||
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
case SPINNER_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, TRUE);
|
||||
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
case ERROR_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
case RETRY_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_init (LibfprintDemo *app)
|
||||
{
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_class_init (LibfprintDemoClass *class)
|
||||
{
|
||||
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
||||
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
||||
|
||||
app_class->activate = activate;
|
||||
app_class->activate = activate;
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||
{
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
FpContext *ctx;
|
||||
GPtrArray *devices;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (window));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||
gtk_widget_init_template (GTK_WIDGET (window));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||
win_entries, G_N_ELEMENTS (win_entries),
|
||||
window);
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||
win_entries, G_N_ELEMENTS (win_entries),
|
||||
window);
|
||||
|
||||
if (fp_init () < 0) {
|
||||
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
ctx = fp_context_new ();
|
||||
|
||||
setup_pollfds ();
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
/* Empty list? */
|
||||
if (devices->len == 0)
|
||||
{
|
||||
libfprint_demo_set_mode (window, EMPTY_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Empty list? */
|
||||
if (discovered_devs[0] == NULL) {
|
||||
fp_dscv_devs_free (discovered_devs);
|
||||
libfprint_demo_set_mode (window, EMPTY_MODE);
|
||||
return;
|
||||
}
|
||||
if (!fp_device_supports_capture (g_ptr_array_index (devices, 0)))
|
||||
{
|
||||
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
|
||||
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
window->ddev = discovered_devs[0];
|
||||
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
||||
window->dev = g_object_ref (g_ptr_array_index (devices, 0));
|
||||
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||
|
||||
//FIXME setup dispose
|
||||
//FIXME setup dispose
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkApplication *app;
|
||||
GtkApplication *app;
|
||||
|
||||
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
|
||||
"application-id", "org.freedesktop.libfprint.Demo",
|
||||
"flags", G_APPLICATION_FLAGS_NONE,
|
||||
NULL));
|
||||
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
|
||||
"application-id", "org.freedesktop.libfprint.Demo",
|
||||
"flags", G_APPLICATION_FLAGS_NONE,
|
||||
NULL));
|
||||
|
||||
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<!-- Generated with glade 3.22.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
||||
@@ -7,59 +7,6 @@
|
||||
<property name="default_width">500</property>
|
||||
<property name="default_height">400</property>
|
||||
<property name="show_menubar">False</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">Fingerprint Reader Test</property>
|
||||
<property name="subtitle">Capture test</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="option-menu-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">options-menu</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="capture_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="action_name">win.capture</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="capture_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Capture</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="mode_stack">
|
||||
<property name="visible">True</property>
|
||||
@@ -104,9 +51,6 @@
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
@@ -116,70 +60,6 @@
|
||||
<property name="title">spinner-mode</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="empty-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">9</property>
|
||||
<property name="pixel_size">192</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">No fingerprint readers found</span></b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">empty-mode</property>
|
||||
<property name="title">empty-mode</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAspectFrame" id="capture-mode">
|
||||
<property name="visible">True</property>
|
||||
@@ -201,7 +81,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="error-mode">
|
||||
<object class="GtkGrid" id="retry-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
@@ -228,7 +108,7 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></property>
|
||||
<property name="label" translatable="yes"><b><span size="large">Device reported a recoverable error. Please retry!</span></b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -236,20 +116,6 @@
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
@@ -261,8 +127,8 @@
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">error-mode</property>
|
||||
<property name="title">error-mode</property>
|
||||
<property name="name">retry-mode</property>
|
||||
<property name="title">retry-mode</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -332,6 +198,216 @@
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="error-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">9</property>
|
||||
<property name="pixel_size">192</property>
|
||||
<property name="icon_name">dialog-warning-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">error-mode</property>
|
||||
<property name="title">error-mode</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="empty-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">9</property>
|
||||
<property name="pixel_size">192</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">No fingerprint readers found</span></b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">empty-mode</property>
|
||||
<property name="title">empty-mode</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">Fingerprint Reader Test</property>
|
||||
<property name="subtitle">Capture test</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="option-menu-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">options-menu</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="action_name">win.cancel</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="cancel_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="capture_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="action_name">win.capture</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="capture_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Capture</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
||||
196
demo/loop.c
196
demo/loop.c
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* fprint D-Bus daemon
|
||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "loop.h"
|
||||
|
||||
struct fdsource {
|
||||
GSource source;
|
||||
GSList *pollfds;
|
||||
};
|
||||
|
||||
static gboolean source_prepare(GSource *source, gint *timeout)
|
||||
{
|
||||
int r;
|
||||
struct timeval tv;
|
||||
|
||||
r = fp_get_next_timeout(&tv);
|
||||
if (r == 0) {
|
||||
*timeout = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!timerisset(&tv))
|
||||
return TRUE;
|
||||
|
||||
*timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean source_check(GSource *source)
|
||||
{
|
||||
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||
GSList *l;
|
||||
struct timeval tv;
|
||||
int r;
|
||||
|
||||
if (!_fdsource->pollfds)
|
||||
return FALSE;
|
||||
|
||||
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||
GPollFD *pollfd = l->data;
|
||||
|
||||
if (pollfd->revents)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
r = fp_get_next_timeout(&tv);
|
||||
if (r == 1 && !timerisset(&tv))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean source_dispatch(GSource *source, GSourceFunc callback,
|
||||
gpointer data)
|
||||
{
|
||||
struct timeval zerotimeout = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
|
||||
/* FIXME error handling */
|
||||
fp_handle_events_timeout(&zerotimeout);
|
||||
|
||||
/* FIXME whats the return value used for? */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void source_finalize(GSource *source)
|
||||
{
|
||||
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||
GSList *l;
|
||||
|
||||
if (!_fdsource->pollfds)
|
||||
return;
|
||||
|
||||
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||
GPollFD *pollfd = l->data;
|
||||
|
||||
g_source_remove_poll((GSource *) _fdsource, pollfd);
|
||||
g_slice_free(GPollFD, pollfd);
|
||||
_fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l);
|
||||
}
|
||||
|
||||
g_slist_free(_fdsource->pollfds);
|
||||
}
|
||||
|
||||
static GSourceFuncs sourcefuncs = {
|
||||
.prepare = source_prepare,
|
||||
.check = source_check,
|
||||
.dispatch = source_dispatch,
|
||||
.finalize = source_finalize,
|
||||
};
|
||||
|
||||
static struct fdsource *fdsource = NULL;
|
||||
|
||||
static void pollfd_add(int fd, short events)
|
||||
{
|
||||
GPollFD *pollfd;
|
||||
|
||||
pollfd = g_slice_new(GPollFD);
|
||||
pollfd->fd = fd;
|
||||
pollfd->events = 0;
|
||||
pollfd->revents = 0;
|
||||
if (events & POLLIN)
|
||||
pollfd->events |= G_IO_IN;
|
||||
if (events & POLLOUT)
|
||||
pollfd->events |= G_IO_OUT;
|
||||
|
||||
fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd);
|
||||
g_source_add_poll((GSource *) fdsource, pollfd);
|
||||
}
|
||||
|
||||
static void pollfd_added_cb(int fd, short events)
|
||||
{
|
||||
g_debug("now monitoring fd %d", fd);
|
||||
pollfd_add(fd, events);
|
||||
}
|
||||
|
||||
static void pollfd_removed_cb(int fd)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
g_debug("no longer monitoring fd %d", fd);
|
||||
|
||||
if (!fdsource->pollfds) {
|
||||
g_debug("cannot remove from list as list is empty?");
|
||||
return;
|
||||
}
|
||||
|
||||
for (l = fdsource->pollfds; l != NULL; l = l->next) {
|
||||
GPollFD *pollfd = l->data;
|
||||
|
||||
if (pollfd->fd != fd)
|
||||
continue;
|
||||
|
||||
g_source_remove_poll((GSource *) fdsource, pollfd);
|
||||
g_slice_free(GPollFD, pollfd);
|
||||
fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l);
|
||||
return;
|
||||
}
|
||||
|
||||
g_error("couldn't find fd %d in list\n", fd);
|
||||
}
|
||||
|
||||
int setup_pollfds(void)
|
||||
{
|
||||
ssize_t numfds;
|
||||
size_t i;
|
||||
struct fp_pollfd *fpfds;
|
||||
GSource *gsource;
|
||||
|
||||
gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource));
|
||||
fdsource = (struct fdsource *) gsource;
|
||||
fdsource->pollfds = NULL;
|
||||
|
||||
numfds = fp_get_pollfds(&fpfds);
|
||||
if (numfds < 0) {
|
||||
if (fpfds)
|
||||
free(fpfds);
|
||||
return (int) numfds;
|
||||
} else if (numfds > 0) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
struct fp_pollfd *fpfd = &fpfds[i];
|
||||
pollfd_add(fpfd->fd, fpfd->events);
|
||||
}
|
||||
}
|
||||
|
||||
free(fpfds);
|
||||
fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb);
|
||||
g_source_attach(gsource, NULL);
|
||||
return 0;
|
||||
}
|
||||
27
demo/loop.h
27
demo/loop.h
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POLL_H
|
||||
|
||||
#define POLL_H
|
||||
|
||||
int setup_pollfds(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml',
|
||||
source_dir : '.',
|
||||
c_name : 'gtk_test')
|
||||
gtk_test_resources = gnome.compile_resources('gtk-test-resources',
|
||||
'gtk-libfprint-test.gresource.xml',
|
||||
source_dir : '.',
|
||||
c_name : 'gtk_test')
|
||||
|
||||
prefix = get_option('prefix')
|
||||
bindir = join_paths(prefix, get_option('bindir'))
|
||||
datadir = join_paths(prefix, get_option('datadir'))
|
||||
|
||||
executable('gtk-libfprint-test',
|
||||
[ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ],
|
||||
dependencies: [ libfprint_dep, gtk_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: [ common_cflags,
|
||||
'-DPACKAGE_VERSION="' + meson.project_version() + '"' ],
|
||||
install: true,
|
||||
install_dir: bindir)
|
||||
[ 'gtk-libfprint-test.c', gtk_test_resources ],
|
||||
dependencies: [ libfprint_dep, gtk_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: [
|
||||
common_cflags,
|
||||
'-DPACKAGE_VERSION="' + meson.project_version() + '"'
|
||||
],
|
||||
install: true,
|
||||
install_dir: bindir)
|
||||
|
||||
appdata = 'org.freedesktop.libfprint.Demo.appdata.xml'
|
||||
install_data(appdata,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"app-id": "org.freedesktop.libfprint.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"runtime-version": "3.32",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk-libfprint-test",
|
||||
"finish-args": [
|
||||
@@ -32,18 +32,30 @@
|
||||
}
|
||||
],
|
||||
"post-install": [
|
||||
"install -Dm644 COPYING /app/share/licenses/libusb/COPYING"
|
||||
"install -Dm644 COPYING /app/share/licenses/libgusb/COPYING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libgusb",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz",
|
||||
"sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libfprint",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ],
|
||||
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
||||
"branch": "wip/hadess/gtk-example"
|
||||
"branch": "wip/benzea/v2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -60,21 +60,18 @@
|
||||
<para>
|
||||
In summary, libfprint represents fingerprints in several internal structures
|
||||
and each representation will offer you a way of determining the
|
||||
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
|
||||
<ulink url="#driver">driver</ulink> and <ulink url="#device-id">device ID</ulink> of the print in
|
||||
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
||||
match. libfprint does offer you some "is this print compatible?" helper
|
||||
functions, so you don't have to worry about these details too much.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="driver_id">
|
||||
<title>Driver IDs</title>
|
||||
<refsect2 id="driver">
|
||||
<title>Driver</title>
|
||||
|
||||
<para>
|
||||
Each driver is assigned a unique ID by the project maintainer. These
|
||||
assignments are
|
||||
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
|
||||
documented in the sources</ulink> and will never change.
|
||||
Each driver is assigned a unique string identifier by the project maintainer.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -89,22 +86,23 @@
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="device-types">
|
||||
<title>Device types</title>
|
||||
<refsect2 id="device-id">
|
||||
<title>Device ID</title>
|
||||
|
||||
<para>
|
||||
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
||||
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
||||
ID for a specific device as many devices under the same range may share
|
||||
the same devtype. The devtype may even be 0 in all cases.
|
||||
Internally, the behind a device assigns a string identifier to the device
|
||||
This cannot be used as a unique ID for a specific device as many devices
|
||||
under the same range may share the same devtype. The device ID may even
|
||||
be the same string in all cases. It is guaranteed to have a non-zero length
|
||||
and be a valid file name. It defaults to "0".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The only reason you may be interested in retrieving the devtype for a
|
||||
The only reason you may be interested in retrieving the device ID for a
|
||||
device is for the purpose of checking if some print data is compatible
|
||||
with a device. libfprint uses the devtype as one way of checking that the
|
||||
with a device. libfprint uses the device ID as one way of checking that the
|
||||
print you are verifying is compatible with the device in question - the
|
||||
devtypes must be equal. This effectively allows drivers to support more
|
||||
device ID must be equal. This effectively allows drivers to support more
|
||||
than one type of device where the data from each one is not compatible with
|
||||
the other. Note that libfprint does provide you with helper functions to
|
||||
determine whether a print is compatible with a device, so under most
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
<para>
|
||||
Usually the first thing you want to do is determine which fingerprint
|
||||
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
|
||||
devices are present. This is done using the <ulink url="fp-context.html">FpContext</ulink> object.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once you have found a device you would like to operate, you should open it.
|
||||
Refer to <ulink url="libfprint-Devices-operations.html">device operations</ulink>. This section also details enrollment,
|
||||
Refer to <ulink url="fp-context.html">device operations</ulink>. This section also details enrollment,
|
||||
image capture, and verification.
|
||||
</para>
|
||||
|
||||
|
||||
@@ -25,41 +25,43 @@
|
||||
|
||||
<part>
|
||||
<title>Library API Documentation</title>
|
||||
<xi:include href="xml/events.xml"/>
|
||||
<xi:include href="xml/discovery.xml"/>
|
||||
|
||||
<xi:include href="xml/drv.xml"/>
|
||||
<xi:include href="xml/dev.xml"/>
|
||||
<xi:include href="xml/print_data.xml"/>
|
||||
<!-- FIXME https://bugs.freedesktop.org/show_bug.cgi?id=106550 -->
|
||||
<xi:include href="xml/dscv_print.xml"/>
|
||||
<xi:include href="xml/img.xml"/>
|
||||
<xi:include href="xml/fp-context.xml"/>
|
||||
<xi:include href="xml/fp-device.xml"/>
|
||||
<xi:include href="xml/fp-image-device.xml"/>
|
||||
<xi:include href="xml/fp-print.xml"/>
|
||||
<xi:include href="xml/fp-image.xml"/>
|
||||
</part>
|
||||
|
||||
<part>
|
||||
<title>Writing Drivers</title>
|
||||
<chapter id="driver-helpers">
|
||||
<title>Logging, and async machinery</title>
|
||||
<xi:include href="xml/fpi-log.xml"/>
|
||||
<xi:include href="xml/fpi-ssm.xml"/>
|
||||
<xi:include href="xml/fpi-poll.xml"/>
|
||||
<chapter id="driver-dev">
|
||||
<title>Device methods for drivers</title>
|
||||
<xi:include href="xml/fpi-device.xml"/>
|
||||
<xi:include href="xml/fpi-image-device.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-dev">
|
||||
<title>Device and driver structures</title>
|
||||
<xi:include href="xml/fpi-dev.xml"/>
|
||||
<xi:include href="xml/fpi-dev-img.xml"/>
|
||||
<xi:include href="xml/fpi-core.xml"/>
|
||||
<xi:include href="xml/fpi-core-img.xml"/>
|
||||
<chapter id="driver-helpers">
|
||||
<title>USB and State Machine helpers</title>
|
||||
<xi:include href="xml/fpi-usb-transfer.xml"/>
|
||||
<xi:include href="xml/fpi-ssm.xml"/>
|
||||
<xi:include href="xml/fpi-log.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-img">
|
||||
<title>Image manipulation</title>
|
||||
<xi:include href="xml/fpi-img.xml"/>
|
||||
<xi:include href="xml/fpi-image.xml"/>
|
||||
<xi:include href="xml/fpi-assembling.xml"/>
|
||||
</chapter>
|
||||
|
||||
<xi:include href="xml/fpi-usb.xml"/>
|
||||
<chapter id="driver-print">
|
||||
<title>Print handling</title>
|
||||
<xi:include href="xml/fpi-print.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-misc">
|
||||
<title>Listing drivers</title>
|
||||
<xi:include href="xml/fpi-context.xml"/>
|
||||
</chapter>
|
||||
</part>
|
||||
|
||||
<index id="api-index">
|
||||
|
||||
@@ -1,146 +1,191 @@
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>events</FILE>
|
||||
<TITLE>Initialisation and events handling</TITLE>
|
||||
LIBFPRINT_DEPRECATED
|
||||
fp_set_debug
|
||||
fp_init
|
||||
fp_exit
|
||||
fp_pollfd
|
||||
fp_handle_events_timeout
|
||||
fp_handle_events
|
||||
fp_get_next_timeout
|
||||
fp_get_pollfds
|
||||
fp_pollfd_added_cb
|
||||
fp_pollfd_removed_cb
|
||||
fp_set_pollfd_notifiers
|
||||
<FILE>drivers_api</FILE>
|
||||
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>discovery</FILE>
|
||||
<TITLE>Device discovery</TITLE>
|
||||
fp_dscv_dev
|
||||
fp_discover_devs
|
||||
fp_dscv_devs_free
|
||||
fp_dscv_dev_get_driver
|
||||
fp_dscv_dev_get_devtype
|
||||
fp_dscv_dev_get_driver_id
|
||||
fp_dscv_dev_supports_print_data
|
||||
fp_dscv_dev_supports_dscv_print
|
||||
fp_dscv_dev_for_print_data
|
||||
fp_dscv_dev_for_dscv_print
|
||||
<FILE>fp-context</FILE>
|
||||
<TITLE>FpContext</TITLE>
|
||||
FP_TYPE_CONTEXT
|
||||
FpContextClass
|
||||
fp_context_new
|
||||
fp_context_enumerate
|
||||
fp_context_get_devices
|
||||
FpContext
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>drv</FILE>
|
||||
fp_driver
|
||||
fp_driver_get_name
|
||||
fp_driver_get_full_name
|
||||
fp_driver_get_driver_id
|
||||
fp_driver_get_scan_type
|
||||
fp_driver_supports_imaging
|
||||
<FILE>fp-device</FILE>
|
||||
FP_TYPE_DEVICE
|
||||
FP_DEVICE_RETRY
|
||||
FP_DEVICE_ERROR
|
||||
FpDeviceType
|
||||
FpScanType
|
||||
FpDeviceRetry
|
||||
FpDeviceError
|
||||
fp_device_retry_quark
|
||||
fp_device_error_quark
|
||||
FpEnrollProgress
|
||||
fp_device_get_driver
|
||||
fp_device_get_device_id
|
||||
fp_device_get_name
|
||||
fp_device_get_scan_type
|
||||
fp_device_get_nr_enroll_stages
|
||||
fp_device_has_storage
|
||||
fp_device_supports_identify
|
||||
fp_device_supports_capture
|
||||
fp_device_open
|
||||
fp_device_close
|
||||
fp_device_enroll
|
||||
fp_device_verify
|
||||
fp_device_identify
|
||||
fp_device_capture
|
||||
fp_device_delete_print
|
||||
fp_device_list_prints
|
||||
fp_device_open_finish
|
||||
fp_device_close_finish
|
||||
fp_device_enroll_finish
|
||||
fp_device_verify_finish
|
||||
fp_device_identify_finish
|
||||
fp_device_capture_finish
|
||||
fp_device_delete_print_finish
|
||||
fp_device_list_prints_finish
|
||||
fp_device_open_sync
|
||||
fp_device_close_sync
|
||||
fp_device_enroll_sync
|
||||
fp_device_verify_sync
|
||||
fp_device_identify_sync
|
||||
fp_device_capture_sync
|
||||
fp_device_delete_print_sync
|
||||
fp_device_list_prints_sync
|
||||
FpDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>dev</FILE>
|
||||
fp_dev
|
||||
fp_scan_type
|
||||
fp_capture_result
|
||||
fp_enroll_result
|
||||
fp_verify_result
|
||||
|
||||
fp_dev_get_driver
|
||||
fp_dev_get_nr_enroll_stages
|
||||
fp_dev_get_devtype
|
||||
fp_dev_supports_print_data
|
||||
fp_dev_supports_imaging
|
||||
fp_dev_supports_identification
|
||||
fp_dev_supports_dscv_print
|
||||
fp_dev_get_img_width
|
||||
fp_dev_get_img_height
|
||||
|
||||
fp_operation_stop_cb
|
||||
fp_img_operation_cb
|
||||
fp_dev_open_cb
|
||||
fp_enroll_stage_cb
|
||||
fp_identify_cb
|
||||
|
||||
fp_dev_open
|
||||
fp_async_dev_open
|
||||
|
||||
fp_dev_close
|
||||
fp_async_dev_close
|
||||
|
||||
fp_enroll_finger
|
||||
fp_enroll_finger_img
|
||||
fp_async_enroll_start
|
||||
fp_async_enroll_stop
|
||||
|
||||
fp_verify_finger
|
||||
fp_verify_finger_img
|
||||
fp_async_verify_start
|
||||
fp_async_verify_stop
|
||||
|
||||
fp_identify_finger
|
||||
fp_identify_finger_img
|
||||
fp_async_identify_start
|
||||
fp_async_identify_stop
|
||||
|
||||
fp_dev_img_capture
|
||||
fp_async_capture_start
|
||||
fp_async_capture_stop
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>print_data</FILE>
|
||||
fp_finger
|
||||
fp_print_data
|
||||
fp_print_data_get_data
|
||||
fp_print_data_from_data
|
||||
fp_print_data_save
|
||||
fp_print_data_load
|
||||
fp_print_data_delete
|
||||
fp_print_data_from_dscv_print
|
||||
fp_print_data_free
|
||||
fp_print_data_get_driver_id
|
||||
fp_print_data_get_devtype
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>dscv_print</FILE>
|
||||
fp_dscv_print
|
||||
fp_discover_prints
|
||||
fp_dscv_prints_free
|
||||
fp_dscv_print_get_driver_id
|
||||
fp_dscv_print_get_devtype
|
||||
fp_dscv_print_get_finger
|
||||
fp_dscv_print_delete
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>img</FILE>
|
||||
fp_img
|
||||
fp_minutia
|
||||
fp_img_free
|
||||
fp_img_get_height
|
||||
fp_img_get_width
|
||||
fp_img_get_data
|
||||
fp_img_save_to_file
|
||||
fp_img_standardize
|
||||
fp_img_binarize
|
||||
fp_img_get_minutiae
|
||||
<FILE>fp-image</FILE>
|
||||
FP_TYPE_IMAGE
|
||||
FpMinutia
|
||||
fp_image_new
|
||||
fp_image_get_width
|
||||
fp_image_get_height
|
||||
fp_image_get_ppmm
|
||||
fp_image_get_minutiae
|
||||
fp_image_detect_minutiae
|
||||
fp_image_detect_minutiae_finish
|
||||
fp_image_get_data
|
||||
fp_image_get_binarized
|
||||
fp_minutia_get_coords
|
||||
FpImage
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-image-device</FILE>
|
||||
FP_TYPE_IMAGE_DEVICE
|
||||
FpImageDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-print</FILE>
|
||||
FP_TYPE_PRINT
|
||||
FpFinger
|
||||
FpPrint
|
||||
fp_print_new
|
||||
fp_print_new_from_data
|
||||
fp_print_to_data
|
||||
fp_print_get_driver
|
||||
fp_print_get_device_id
|
||||
fp_print_get_device_stored
|
||||
fp_print_get_image
|
||||
fp_print_get_finger
|
||||
fp_print_get_username
|
||||
fp_print_get_description
|
||||
fp_print_get_enroll_date
|
||||
fp_print_set_finger
|
||||
fp_print_set_username
|
||||
fp_print_set_description
|
||||
fp_print_set_enroll_date
|
||||
fp_print_compatible
|
||||
fp_print_equal
|
||||
fp_print_serialize
|
||||
fp_print_deserialize
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-assembling</FILE>
|
||||
fpi_frame
|
||||
fpi_frame_asmbl_ctx
|
||||
fpi_do_movement_estimation
|
||||
fpi_assemble_frames
|
||||
fpi_line_asmbl_ctx
|
||||
fpi_assemble_lines
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-context</FILE>
|
||||
fpi_get_driver_types
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-device</FILE>
|
||||
FpDeviceClass
|
||||
FpTimeoutFunc
|
||||
FpDeviceAction
|
||||
FpIdEntry
|
||||
fpi_device_get_usb_device
|
||||
fpi_device_get_virtual_env
|
||||
fpi_device_get_current_action
|
||||
fpi_device_retry_new
|
||||
fpi_device_error_new
|
||||
fpi_device_retry_new_msg
|
||||
fpi_device_error_new_msg
|
||||
fpi_device_get_driver_data
|
||||
fpi_device_get_enroll_data
|
||||
fpi_device_get_capture_data
|
||||
fpi_device_get_verify_data
|
||||
fpi_device_get_identify_data
|
||||
fpi_device_get_delete_data
|
||||
fpi_device_get_cancellable
|
||||
fpi_device_action_is_cancelled
|
||||
fpi_device_add_timeout
|
||||
fpi_device_set_nr_enroll_stages
|
||||
fpi_device_set_scan_type
|
||||
fpi_device_action_error
|
||||
fpi_device_probe_complete
|
||||
fpi_device_open_complete
|
||||
fpi_device_close_complete
|
||||
fpi_device_enroll_complete
|
||||
fpi_device_verify_complete
|
||||
fpi_device_identify_complete
|
||||
fpi_device_capture_complete
|
||||
fpi_device_delete_complete
|
||||
fpi_device_enroll_progress
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-image</FILE>
|
||||
FpiImageFlags
|
||||
FpImage
|
||||
fpi_std_sq_dev
|
||||
fpi_mean_sq_diff_norm
|
||||
fpi_image_resize
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-image-device</FILE>
|
||||
<TITLE>FpImageDevice</TITLE>
|
||||
FpImageDeviceState
|
||||
FpImageDeviceClass
|
||||
fpi_image_device_session_error
|
||||
fpi_image_device_open_complete
|
||||
fpi_image_device_close_complete
|
||||
fpi_image_device_activate_complete
|
||||
fpi_image_device_deactivate_complete
|
||||
fpi_image_device_report_finger_status
|
||||
fpi_image_device_image_captured
|
||||
fpi_image_device_retry_scan
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-log.h</INCLUDE>
|
||||
<FILE>fpi-log</FILE>
|
||||
fp_dbg
|
||||
fp_info
|
||||
@@ -151,121 +196,61 @@ BUG
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-ssm.h</INCLUDE>
|
||||
<FILE>fpi-ssm</FILE>
|
||||
fpi_ssm
|
||||
ssm_completed_fn
|
||||
ssm_handler_fn
|
||||
<FILE>fpi-print</FILE>
|
||||
FpPrintType
|
||||
FpiMatchResult
|
||||
fpi_print_add_print
|
||||
fpi_print_set_type
|
||||
fpi_print_set_device_stored
|
||||
fpi_print_add_from_image
|
||||
fpi_print_bz3_match
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-ssm</FILE>
|
||||
FpiSsmCompletedCallback
|
||||
FpiSsmHandlerCallback
|
||||
fpi_ssm_new
|
||||
fpi_ssm_free
|
||||
fpi_ssm_start
|
||||
fpi_ssm_start_subsm
|
||||
|
||||
fpi_ssm_next_state
|
||||
fpi_ssm_next_state_timeout_cb
|
||||
fpi_ssm_next_state_delayed
|
||||
fpi_ssm_jump_to_state
|
||||
fpi_ssm_jump_to_state_delayed
|
||||
fpi_ssm_cancel_delayed_state_change
|
||||
fpi_ssm_mark_completed
|
||||
fpi_ssm_mark_failed
|
||||
fpi_ssm_get_user_data
|
||||
fpi_ssm_set_data
|
||||
fpi_ssm_get_data
|
||||
fpi_ssm_get_error
|
||||
fpi_ssm_dup_error
|
||||
fpi_ssm_get_cur_state
|
||||
fpi_ssm_next_state_timeout_cb
|
||||
fpi_ssm_usb_transfer_cb
|
||||
FpiSsm
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-poll.h</INCLUDE>
|
||||
<FILE>fpi-poll</FILE>
|
||||
fpi_timeout
|
||||
fpi_timeout_fn
|
||||
fpi_timeout_add
|
||||
fpi_timeout_set_name
|
||||
fpi_timeout_cancel
|
||||
<FILE>fpi-usb-transfer</FILE>
|
||||
FPI_USB_ENDPOINT_IN
|
||||
FPI_USB_ENDPOINT_OUT
|
||||
FpiUsbTransferCallback
|
||||
FpiTransferType
|
||||
FpiUsbTransfer
|
||||
fpi_usb_transfer_new
|
||||
fpi_usb_transfer_ref
|
||||
fpi_usb_transfer_unref
|
||||
fpi_usb_transfer_set_short_error
|
||||
fpi_usb_transfer_fill_bulk
|
||||
fpi_usb_transfer_fill_bulk_full
|
||||
fpi_usb_transfer_fill_control
|
||||
fpi_usb_transfer_fill_interrupt
|
||||
fpi_usb_transfer_fill_interrupt_full
|
||||
fpi_usb_transfer_submit
|
||||
fpi_usb_transfer_submit_sync
|
||||
<SUBSECTION Standard>
|
||||
FPI_TYPE_USB_TRANSFER
|
||||
fpi_usb_transfer_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-dev.h</INCLUDE>
|
||||
<FILE>fpi-dev</FILE>
|
||||
fp_img_dev
|
||||
|
||||
FP_DEV
|
||||
FP_IMG_DEV
|
||||
fp_dev_set_instance_data
|
||||
FP_INSTANCE_DATA
|
||||
|
||||
fpi_dev_get_usb_dev
|
||||
fpi_dev_get_verify_data
|
||||
fpi_dev_set_nr_enroll_stages
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-dev-img.h</INCLUDE>
|
||||
<FILE>fpi-dev-img</FILE>
|
||||
fp_imgdev_action
|
||||
fp_imgdev_state
|
||||
fp_imgdev_enroll_state
|
||||
|
||||
fpi_imgdev_abort_scan
|
||||
fpi_imgdev_activate_complete
|
||||
fpi_imgdev_close_complete
|
||||
fpi_imgdev_deactivate_complete
|
||||
fpi_imgdev_get_action
|
||||
fpi_imgdev_get_action_result
|
||||
fpi_imgdev_get_action_state
|
||||
fpi_imgdev_image_captured
|
||||
fpi_imgdev_open_complete
|
||||
fpi_imgdev_report_finger_status
|
||||
fpi_imgdev_session_error
|
||||
fpi_imgdev_set_action_result
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-core.h</INCLUDE>
|
||||
<FILE>fpi-core</FILE>
|
||||
usb_id
|
||||
fp_driver_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-core.h</INCLUDE>
|
||||
<FILE>fpi-core-img</FILE>
|
||||
FpiImgDriverFlags
|
||||
fp_img_driver
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-img.h</INCLUDE>
|
||||
<FILE>fpi-img</FILE>
|
||||
FpiImgFlags
|
||||
|
||||
fpi_img_new
|
||||
fpi_img_new_for_imgdev
|
||||
fpi_img_realloc
|
||||
fpi_img_resize
|
||||
|
||||
fpi_std_sq_dev
|
||||
fpi_mean_sq_diff_norm
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-assembling.h</INCLUDE>
|
||||
<FILE>fpi-assembling</FILE>
|
||||
fpi_frame
|
||||
fpi_frame_asmbl_ctx
|
||||
fpi_line_asmbl_ctx
|
||||
|
||||
fpi_do_movement_estimation
|
||||
fpi_assemble_frames
|
||||
fpi_assemble_lines
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fpi-usb.h</INCLUDE>
|
||||
<FILE>fpi-usb</FILE>
|
||||
fpi_usb_transfer
|
||||
|
||||
fpi_usb_transfer_cb_fn
|
||||
fpi_usb_alloc
|
||||
fpi_usb_fill_bulk_transfer
|
||||
fpi_usb_submit_transfer
|
||||
fpi_usb_cancel_transfer
|
||||
</SECTION>
|
||||
|
||||
118
doc/libfprint-sections.txt-new-manual
Normal file
118
doc/libfprint-sections.txt-new-manual
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>context</FILE>
|
||||
<TITLE>Device discovery and hotplugging</TITLE>
|
||||
FP_TYPE_CONTEXT
|
||||
FpContext
|
||||
fp_context_new
|
||||
fp_context_enumerate
|
||||
fp_context_get_devices
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>device</FILE>
|
||||
<TITLE>Device</TITLE>
|
||||
FP_TYPE_DEVICE
|
||||
FpDevice
|
||||
FpDeviceType
|
||||
FpScanType
|
||||
FpDeviceRetry
|
||||
FpDeviceError
|
||||
FP_DEVICE_ERROR
|
||||
FP_DEVICE_RETRY
|
||||
fp_device_get_driver
|
||||
fp_device_get_device_id
|
||||
fp_device_get_name
|
||||
fp_device_get_scan_type
|
||||
|
||||
fp_device_open
|
||||
fp_device_open_finish
|
||||
fp_device_open_sync
|
||||
|
||||
fp_device_close
|
||||
fp_device_close_finish
|
||||
fp_device_close_sync
|
||||
|
||||
fp_device_enroll
|
||||
fp_device_enroll_finish
|
||||
fp_device_enroll_sync
|
||||
|
||||
fp_device_identify
|
||||
fp_device_identify_finish
|
||||
fp_device_identify_sync
|
||||
|
||||
fp_device_capture
|
||||
fp_device_capture_finish
|
||||
fp_device_capture_sync
|
||||
|
||||
fp_device_verify
|
||||
fp_device_verify_finish
|
||||
fp_device_verify_sync
|
||||
|
||||
_fp_device_get_cancellable
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>print</FILE>
|
||||
<TITLE>Fingerprint handling</TITLE>
|
||||
FpPrint
|
||||
fp_print_new
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<INCLUDE>fprint.h</INCLUDE>
|
||||
<FILE>image</FILE>
|
||||
<TITLE>Image handling</TITLE>
|
||||
FP_TYPE_IMAGE
|
||||
FpImage
|
||||
fp_image_new
|
||||
fp_image_detect_minutiae
|
||||
fp_image_detect_minutiae_finish
|
||||
fp_image_device_new
|
||||
fp_image_get_binarized
|
||||
fp_image_get_data
|
||||
fp_image_get_height
|
||||
fp_image_get_minutiae
|
||||
fp_image_get_ppmm
|
||||
fp_image_get_width
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<FILE>internal-image-device</FILE>
|
||||
<INCLUDE>drivers_api.h</INCLUDE>
|
||||
<TITLE>Base class for image devices</TITLE>
|
||||
FpImageDevice
|
||||
FpImageDeviceClass
|
||||
FpImageDeviceState
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>internal-usb-transfers</FILE>
|
||||
<INCLUDE>drivers_api.h</INCLUDE>
|
||||
<TITLE>USB Transfers</TITLE>
|
||||
FpUsbTransfer
|
||||
fp_usb_transfer_fill_bulk
|
||||
fp_usb_transfer_fill_bulk_full
|
||||
fp_usb_transfer_fill_control
|
||||
fp_usb_transfer_fill_interrupt
|
||||
fp_usb_transfer_fill_interrupt_full
|
||||
fp_usb_transfer_get_type
|
||||
fp_usb_transfer_new
|
||||
fp_usb_transfer_ref
|
||||
fp_usb_transfer_set_short_error
|
||||
fp_usb_transfer_submit
|
||||
fp_usb_transfer_submit_sync
|
||||
fp_usb_transfer_unref
|
||||
FpUsbTransferCallback
|
||||
FP_USB_ENDPOINT_IN
|
||||
FP_USB_ENDPOINT_OUT
|
||||
</SECTION>
|
||||
|
||||
|
||||
@@ -1,42 +1,14 @@
|
||||
subdir('xml')
|
||||
|
||||
private_headers = [
|
||||
'config.h',
|
||||
'config.h',
|
||||
'nbis-helpers.h',
|
||||
'fprint.h',
|
||||
'fp_internal.h',
|
||||
|
||||
'aeslib.h',
|
||||
'assembling.h',
|
||||
'fp_internal.h',
|
||||
'nbis-helpers.h',
|
||||
'fpi-async.h',
|
||||
'fpi-data.h',
|
||||
|
||||
# Drivers
|
||||
'aes1660.h',
|
||||
'aes2501.h',
|
||||
'aes2550.h',
|
||||
'aes2660.h',
|
||||
'aes3k.h',
|
||||
'aesx660.h',
|
||||
'driver_ids.h',
|
||||
'elan.h',
|
||||
'upek_proto.h',
|
||||
'upeksonly.h',
|
||||
'upektc.h',
|
||||
'upektc_img.h',
|
||||
'vfs0050.h',
|
||||
'vfs301_proto_fragments.h',
|
||||
'vfs301_proto.h',
|
||||
'vfs5011_proto.h',
|
||||
|
||||
# NBIS
|
||||
'morph.h',
|
||||
'sunrast.h',
|
||||
'bozorth.h',
|
||||
'defs.h',
|
||||
'log.h',
|
||||
'bz_array.h',
|
||||
'lfs.h',
|
||||
'mytime.h',
|
||||
# Subdirectories to ignore
|
||||
'drivers',
|
||||
'nbis',
|
||||
]
|
||||
|
||||
html_images = [
|
||||
@@ -53,19 +25,20 @@ glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||
|
||||
gnome.gtkdoc('libfprint',
|
||||
main_xml: 'libfprint-docs.xml',
|
||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||
dependencies: libfprint_dep,
|
||||
content_files: content_files,
|
||||
expand_content_files: expand_content_files,
|
||||
scan_args: [
|
||||
'--ignore-decorators=API_EXPORTED',
|
||||
'--ignore-headers=' + ' '.join(private_headers),
|
||||
],
|
||||
fixxref_args: [
|
||||
'--html-dir=@0@'.format(docpath),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
|
||||
],
|
||||
html_assets: html_images,
|
||||
install: true)
|
||||
main_xml: 'libfprint-docs.xml',
|
||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||
dependencies: libfprint_dep,
|
||||
content_files: content_files,
|
||||
expand_content_files: expand_content_files,
|
||||
scan_args: [
|
||||
#'--rebuild-sections',
|
||||
'--ignore-decorators=API_EXPORTED',
|
||||
'--ignore-headers=' + ' '.join(private_headers),
|
||||
],
|
||||
fixxref_args: [
|
||||
'--html-dir=@0@'.format(docpath),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
|
||||
],
|
||||
html_assets: html_images,
|
||||
install: true)
|
||||
|
||||
@@ -7,4 +7,6 @@ ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
|
||||
configure_file(input: 'gtkdocentities.ent.in',
|
||||
output: 'gtkdocentities.ent',
|
||||
configuration: ent_conf)
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
fp_init ();
|
||||
FpContext *ctx;
|
||||
|
||||
ctx = fp_context_new ();
|
||||
g_object_unref (ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Example fingerprint delete finger program, which delete the right index
|
||||
* finger which has been previously enrolled to disk.
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int r = 1;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
struct fp_print_data *data;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Opened device. Loading previously enrolled right index finger "
|
||||
"data...\n");
|
||||
|
||||
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
|
||||
fprintf(stderr, "Did you remember to enroll your right index finger "
|
||||
"first?\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
printf("Print loaded. delete data in sensor.\n");
|
||||
if(!fp_dev_supports_data_in_sensor(dev))
|
||||
{
|
||||
printf("This driver doesn't support to store data in sensor.\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
r = fp_delete_finger(dev, data);
|
||||
fp_print_data_free(data);
|
||||
if (r) {
|
||||
printf("delete finger failed with error %d :(\n", r);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("sensor data deleted. now delete host data");
|
||||
r = fp_print_data_delete(dev, RIGHT_INDEX);
|
||||
if (r < 0) {
|
||||
printf("Delete sensor data successfully but delete host data failed. %d :(\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
out_close:
|
||||
fp_dev_close(dev);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Example fingerprint enrollment program
|
||||
* Enrolls your right index finger and saves the print to disk
|
||||
* Enrolls your choosen finger and saves the print to disk
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,142 +20,177 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
#include "storage.h"
|
||||
#include "utilities.h"
|
||||
|
||||
typedef struct _EnrollData
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
}
|
||||
GMainLoop *loop;
|
||||
FpFinger finger;
|
||||
int ret_value;
|
||||
} EnrollData;
|
||||
|
||||
struct fp_print_data *enroll(struct fp_dev *dev) {
|
||||
struct fp_print_data *enrolled_print = NULL;
|
||||
int r;
|
||||
|
||||
printf("You will need to successfully scan your finger %d times to "
|
||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
||||
|
||||
do {
|
||||
struct fp_img *img = NULL;
|
||||
|
||||
printf("\nScan your finger now.\n");
|
||||
|
||||
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
||||
if (img) {
|
||||
fp_img_save_to_file(img, "enrolled.pgm");
|
||||
printf("Wrote scanned image to enrolled.pgm\n");
|
||||
fp_img_free(img);
|
||||
}
|
||||
if (r < 0) {
|
||||
printf("Enroll failed with error %d\n", r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case FP_ENROLL_COMPLETE:
|
||||
printf("Enroll complete!\n");
|
||||
break;
|
||||
case FP_ENROLL_FAIL:
|
||||
printf("Enroll failed, something wen't wrong :(\n");
|
||||
return NULL;
|
||||
case FP_ENROLL_PASS:
|
||||
printf("Enroll stage passed. Yay!\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY:
|
||||
printf("Didn't quite catch that. Please try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
||||
printf("Your swipe was too short, please try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
||||
printf("Didn't catch that, please center your finger on the "
|
||||
"sensor and try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
||||
printf("Scan failed, please remove your finger and then try "
|
||||
"again.\n");
|
||||
break;
|
||||
}
|
||||
} while (r != FP_ENROLL_COMPLETE);
|
||||
|
||||
if (!enrolled_print) {
|
||||
fprintf(stderr, "Enroll complete but no print?\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Enrollment completed!\n\n");
|
||||
return enrolled_print;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
static void
|
||||
enroll_data_free (EnrollData *enroll_data)
|
||||
{
|
||||
int r = 1;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
struct fp_print_data *data;
|
||||
g_main_loop_unref (enroll_data->loop);
|
||||
g_free (enroll_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free)
|
||||
|
||||
printf("This program will enroll your right index finger, "
|
||||
"unconditionally overwriting any right-index print that was enrolled "
|
||||
"previously. If you want to continue, press enter, otherwise hit "
|
||||
"Ctrl+C\n");
|
||||
getchar();
|
||||
static void
|
||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
EnrollData *enroll_data = user_data;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Opened device. It's now time to enroll your finger.\n\n");
|
||||
data = enroll(dev);
|
||||
if (!data)
|
||||
goto out_close;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
r = fp_print_data_save(data, RIGHT_INDEX);
|
||||
#pragma GCC diagnostic pop
|
||||
if (r < 0)
|
||||
fprintf(stderr, "Data save failed, code %d\n", r);
|
||||
|
||||
fp_print_data_free(data);
|
||||
out_close:
|
||||
fp_dev_close(dev);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
g_main_loop_quit (enroll_data->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
EnrollData *enroll_data = user_data;
|
||||
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
print = fp_device_enroll_finish (dev, res, &error);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
enroll_data->ret_value = EXIT_SUCCESS;
|
||||
|
||||
if (!fp_device_has_storage (dev))
|
||||
{
|
||||
g_debug ("Device has not storage, saving locally");
|
||||
int r = print_data_save (print, enroll_data->finger);
|
||||
if (r < 0)
|
||||
{
|
||||
g_warning ("Data save failed, code %d", r);
|
||||
enroll_data->ret_value = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Enroll failed with error %s\n", error->message);
|
||||
}
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
enroll_data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_enroll_progress (FpDevice *device,
|
||||
gint completed_stages,
|
||||
FpPrint *print,
|
||||
gpointer user_data,
|
||||
GError *error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Enroll stage %d of %d failed with error %s",
|
||||
completed_stages,
|
||||
fp_device_get_nr_enroll_stages (device),
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp_device_supports_capture (device) &&
|
||||
print_image_save (print, "enrolled.pgm"))
|
||||
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||
|
||||
printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages,
|
||||
fp_device_get_nr_enroll_stages (device));
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
EnrollData *enroll_data = user_data;
|
||||
FpPrint *print_template;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
g_main_loop_quit (enroll_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("Opened device. It's now time to enroll your finger.\n\n");
|
||||
printf ("You will need to successfully scan your %s finger %d times to "
|
||||
"complete the process.\n\n", finger_to_string (enroll_data->finger),
|
||||
fp_device_get_nr_enroll_stages (dev));
|
||||
printf ("Scan your finger now.\n");
|
||||
|
||||
print_template = print_create_template (dev, enroll_data->finger);
|
||||
fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL,
|
||||
NULL, (GAsyncReadyCallback) on_enroll_completed,
|
||||
enroll_data);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
g_autoptr(FpContext) ctx = NULL;
|
||||
g_autoptr(EnrollData) enroll_data = NULL;
|
||||
GPtrArray *devices;
|
||||
FpDevice *dev;
|
||||
FpFinger finger;
|
||||
|
||||
g_print ("This program will enroll the selected finger, unconditionally "
|
||||
"overwriting any print for the same finger that was enrolled "
|
||||
"previously. If you want to continue, press enter, otherwise hit "
|
||||
"Ctrl+C\n");
|
||||
getchar ();
|
||||
|
||||
g_print ("Choose the finger to enroll:\n");
|
||||
finger = finger_chooser ();
|
||||
|
||||
if (finger == FP_FINGER_UNKNOWN)
|
||||
{
|
||||
g_warning ("Unknown finger selected");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
|
||||
ctx = fp_context_new ();
|
||||
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
g_warning ("Impossible to get devices");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev = discover_device (devices);
|
||||
if (!dev)
|
||||
{
|
||||
g_warning ("No devices detected.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
enroll_data = g_new0 (EnrollData, 1);
|
||||
enroll_data->finger = finger;
|
||||
enroll_data->ret_value = EXIT_FAILURE;
|
||||
enroll_data->loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
||||
enroll_data);
|
||||
|
||||
g_main_loop_run (enroll_data->loop);
|
||||
|
||||
return enroll_data->ret_value;
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Example libfprint image capture program
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int r = 1;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
struct fp_img *img = NULL;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fp_dev_supports_imaging(dev)) {
|
||||
fprintf(stderr, "this device does not have imaging capabilities.\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
printf("Opened device. It's now time to scan your finger.\n\n");
|
||||
|
||||
r = fp_dev_img_capture(dev, 0, &img);
|
||||
if (r) {
|
||||
fprintf(stderr, "image capture failed, code %d\n", r);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
r = fp_img_save_to_file(img, "finger.pgm");
|
||||
if (r) {
|
||||
fprintf(stderr, "img save failed, code %d\n", r);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
fp_img_standardize(img);
|
||||
r = fp_img_save_to_file(img, "finger_standardized.pgm");
|
||||
fp_img_free(img);
|
||||
if (r) {
|
||||
fprintf(stderr, "standardized img save failed, code %d\n", r);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out_close:
|
||||
fp_dev_close(dev);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Example libfprint continuous image capture program
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
|
||||
#define FORMAT 0x32595559
|
||||
|
||||
static int adaptor = -1;
|
||||
static char *framebuffer = NULL;
|
||||
|
||||
static Display *display = NULL;
|
||||
static Window window=(Window)NULL;
|
||||
static XvImage *xv_image = NULL;
|
||||
static XvAdaptorInfo *info;
|
||||
static GC gc;
|
||||
static int connection = -1;
|
||||
|
||||
/* based on macro by Bart Nabbe */
|
||||
#define GREY2YUV(grey, y, u, v)\
|
||||
y = (9798*grey + 19235*grey + 3736*grey) / 32768;\
|
||||
u = (-4784*grey - 9437*grey + 14221*grey) / 32768 + 128;\
|
||||
v = (20218*grey - 16941*grey - 3277*grey) / 32768 + 128;\
|
||||
y = y < 0 ? 0 : y;\
|
||||
u = u < 0 ? 0 : u;\
|
||||
v = v < 0 ? 0 : v;\
|
||||
y = y > 255 ? 255 : y;\
|
||||
u = u > 255 ? 255 : u;\
|
||||
v = v > 255 ? 255 : v
|
||||
|
||||
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
|
||||
int i, j;
|
||||
int y0, y1, u0, u1, v0, v1;
|
||||
uint64_t gval;
|
||||
|
||||
for (i = 0, j = 0; i < num; i += 2, j += 4)
|
||||
{
|
||||
gval = grey[i];
|
||||
GREY2YUV (gval, y0, u0 , v0);
|
||||
gval = grey[i + 1];
|
||||
GREY2YUV (gval, y1, u1 , v1);
|
||||
YUV[j + 0] = y0;
|
||||
YUV[j + 1] = (u0+u1)/2;
|
||||
YUV[j + 2] = y1;
|
||||
YUV[j + 3] = (v0+v1)/2;
|
||||
}
|
||||
}
|
||||
|
||||
static void display_frame(struct fp_img *img)
|
||||
{
|
||||
int width = fp_img_get_width(img);
|
||||
int height = fp_img_get_height(img);
|
||||
unsigned char *data = fp_img_get_data(img);
|
||||
|
||||
if (adaptor < 0)
|
||||
return;
|
||||
|
||||
grey2yuy2(data, framebuffer, width * height);
|
||||
xv_image = XvCreateImage(display, info[adaptor].base_id, FORMAT,
|
||||
framebuffer, width, height);
|
||||
XvPutImage(display, info[adaptor].base_id, window, gc, xv_image,
|
||||
0, 0, width, height, 0, 0, width, height);
|
||||
}
|
||||
|
||||
static void QueryXv(void)
|
||||
{
|
||||
unsigned int num_adaptors;
|
||||
int num_formats;
|
||||
XvImageFormatValues *formats = NULL;
|
||||
int i,j;
|
||||
char xv_name[5];
|
||||
|
||||
XvQueryAdaptors(display, DefaultRootWindow(display), &num_adaptors,
|
||||
&info);
|
||||
|
||||
for(i = 0; i < num_adaptors; i++) {
|
||||
formats = XvListImageFormats(display, info[i].base_id,
|
||||
&num_formats);
|
||||
for(j = 0; j < num_formats; j++) {
|
||||
xv_name[4] = 0;
|
||||
memcpy(xv_name, &formats[j].id, 4);
|
||||
if(formats[j].id == FORMAT) {
|
||||
printf("using Xv format 0x%x %s %s\n",
|
||||
formats[j].id, xv_name,
|
||||
(formats[j].format==XvPacked)
|
||||
? "packed" : "planar");
|
||||
if (adaptor < 0)
|
||||
adaptor = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree(formats);
|
||||
if (adaptor < 0)
|
||||
printf("No suitable Xv adaptor found\n");
|
||||
}
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int r = 1;
|
||||
XEvent xev;
|
||||
XGCValues xgcv;
|
||||
long background=0x010203;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
int img_width;
|
||||
int img_height;
|
||||
int standardize = 0;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fp_dev_supports_imaging(dev)) {
|
||||
fprintf(stderr, "this device does not have imaging capabilities.\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
img_width = fp_dev_get_img_width(dev);
|
||||
img_height = fp_dev_get_img_height(dev);
|
||||
if (img_width <= 0 || img_height <= 0) {
|
||||
fprintf(stderr, "this device returns images with variable dimensions,"
|
||||
" this example does not support that.\n");
|
||||
goto out_close;
|
||||
}
|
||||
framebuffer = malloc(img_width * img_height * 2);
|
||||
if (!framebuffer)
|
||||
goto out_close;
|
||||
|
||||
/* make the window */
|
||||
display = XOpenDisplay(getenv("DISPLAY"));
|
||||
if(display == NULL) {
|
||||
fprintf(stderr,"Could not open display \"%s\"\n",
|
||||
getenv("DISPLAY"));
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
QueryXv();
|
||||
|
||||
if (adaptor < 0)
|
||||
goto out_close;
|
||||
|
||||
window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
|
||||
img_width, img_height, 0,
|
||||
WhitePixel(display, DefaultScreen(display)), background);
|
||||
|
||||
XSelectInput(display, window, StructureNotifyMask | KeyPressMask);
|
||||
XMapWindow(display, window);
|
||||
connection = ConnectionNumber(display);
|
||||
|
||||
gc = XCreateGC(display, window, 0, &xgcv);
|
||||
|
||||
printf("Press S to toggle standardized mode, Q to quit\n");
|
||||
|
||||
while (1) { /* event loop */
|
||||
struct fp_img *img;
|
||||
|
||||
r = fp_dev_img_capture(dev, 1, &img);
|
||||
if (r) {
|
||||
fprintf(stderr, "image capture failed, code %d\n", r);
|
||||
goto out_close;
|
||||
}
|
||||
if (standardize)
|
||||
fp_img_standardize(img);
|
||||
|
||||
display_frame(img);
|
||||
fp_img_free(img);
|
||||
XFlush(display);
|
||||
|
||||
while (XPending(display) > 0) {
|
||||
XNextEvent(display, &xev);
|
||||
if (xev.type != KeyPress)
|
||||
continue;
|
||||
|
||||
switch (XKeycodeToKeysym(display, xev.xkey.keycode, 0)) {
|
||||
case XK_q:
|
||||
case XK_Q:
|
||||
r = 0;
|
||||
goto out_close;
|
||||
break;
|
||||
case XK_s:
|
||||
case XK_S:
|
||||
standardize = !standardize;
|
||||
break;
|
||||
}
|
||||
} /* XPending */
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out_close:
|
||||
if (framebuffer)
|
||||
free(framebuffer);
|
||||
fp_dev_close(dev);
|
||||
if ((void *) window != NULL)
|
||||
XUnmapWindow(display, window);
|
||||
if (display != NULL)
|
||||
XFlush(display);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
284
examples/manage-prints.c
Normal file
284
examples/manage-prints.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Example fingerprint device prints listing and deletion
|
||||
* Enrolls your right index finger and saves the print to disk
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
#include "utilities.h"
|
||||
|
||||
typedef struct _ListData
|
||||
{
|
||||
GMainLoop *loop;
|
||||
int ret_value;
|
||||
GList *to_delete;
|
||||
gboolean any_failed;
|
||||
} ListData;
|
||||
|
||||
static void
|
||||
list_data_free (ListData *list_data)
|
||||
{
|
||||
g_list_free_full (list_data->to_delete, g_object_unref);
|
||||
g_main_loop_unref (list_data->loop);
|
||||
g_free (list_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free)
|
||||
|
||||
static void
|
||||
on_device_closed (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
ListData *list_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
|
||||
g_main_loop_quit (list_data->loop);
|
||||
}
|
||||
|
||||
typedef struct _DeleteData
|
||||
{
|
||||
ListData *list_data;
|
||||
FpPrint *print;
|
||||
} DeleteData;
|
||||
|
||||
static void
|
||||
delete_data_free (DeleteData *delete_data)
|
||||
{
|
||||
g_object_unref (delete_data->print);
|
||||
g_free (delete_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free);
|
||||
|
||||
static void on_print_deleted (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
delete_next_print (FpDevice *dev,
|
||||
ListData *list_data)
|
||||
{
|
||||
FpPrint *print;
|
||||
|
||||
g_assert_nonnull (list_data->to_delete);
|
||||
print = list_data->to_delete->data;
|
||||
|
||||
g_debug ("Deleting print %s\n", fp_print_get_description (print));
|
||||
fp_device_delete_print (dev, print, NULL,
|
||||
(GAsyncReadyCallback) on_print_deleted, list_data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_print_deleted (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
ListData *list_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
GList *deleted_link;
|
||||
|
||||
fp_device_delete_print_finish (dev, res, &error);
|
||||
|
||||
deleted_link = list_data->to_delete;
|
||||
print = g_steal_pointer (&deleted_link->data);
|
||||
list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Failed to remove print %s: %s",
|
||||
fp_print_get_description (print), error->message);
|
||||
list_data->any_failed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Deleted print %s from device", fp_print_get_description (print));
|
||||
}
|
||||
|
||||
if (list_data->to_delete != NULL)
|
||||
{
|
||||
delete_next_print (dev, list_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!list_data->any_failed)
|
||||
list_data->ret_value = EXIT_SUCCESS;
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
list_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_list_completed (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
ListData *list_data = user_data;
|
||||
|
||||
g_autoptr(GPtrArray) prints = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
prints = fp_device_list_prints_finish (dev, res, &error);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
guint i;
|
||||
char buf[128];
|
||||
|
||||
g_print ("Device contains %u prints\n", prints->len);
|
||||
|
||||
for (i = 0; i < prints->len; ++i)
|
||||
{
|
||||
FpPrint * print = prints->pdata[i];
|
||||
const GDate *date = fp_print_get_enroll_date (print);
|
||||
|
||||
g_print ("[%d] Print of %s finger for username %s", i + 1,
|
||||
finger_to_string (fp_print_get_finger (print)),
|
||||
fp_print_get_username (print));
|
||||
|
||||
if (date)
|
||||
{
|
||||
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
|
||||
g_print (", enrolled on %s", buf);
|
||||
}
|
||||
|
||||
g_print (". Description: %s\n", fp_print_get_description (print));
|
||||
}
|
||||
|
||||
if (prints->len)
|
||||
{
|
||||
gint64 idx = 0;
|
||||
|
||||
g_print ("Want to delete saved print? [<number>/A/n]\n> ");
|
||||
if (fgets (buf, 3, stdin))
|
||||
idx = g_ascii_strtoll (buf, NULL, 10);
|
||||
|
||||
if (idx > 0 && idx <= prints->len)
|
||||
{
|
||||
FpPrint *print = prints->pdata[idx - 1];
|
||||
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
||||
g_object_ref (print));
|
||||
}
|
||||
else if (buf[0] == 'A')
|
||||
{
|
||||
for (i = 0; i < prints->len; ++i)
|
||||
{
|
||||
FpPrint *print = prints->pdata[i];
|
||||
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
||||
g_object_ref (print));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buf[0] == 'n' || buf[0] == 'N')
|
||||
list_data->ret_value = EXIT_SUCCESS;
|
||||
else
|
||||
g_warning ("Invalid finger selected");
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
list_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_data->to_delete)
|
||||
delete_next_print (dev, list_data);
|
||||
else
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
list_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Getting prints failed with error %s", error->message);
|
||||
g_main_loop_quit (list_data->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_opened (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
ListData *list_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
g_main_loop_quit (list_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fp_device_has_storage (dev))
|
||||
{
|
||||
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
||||
g_main_loop_quit (list_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_device_list_prints (dev, NULL,
|
||||
(GAsyncReadyCallback) on_list_completed, list_data);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
g_autoptr(FpContext) ctx = NULL;
|
||||
g_autoptr(ListData) list_data = NULL;
|
||||
GPtrArray *devices;
|
||||
FpDevice *dev;
|
||||
|
||||
g_print ("This program will report the prints saved in device\n");
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
|
||||
ctx = fp_context_new ();
|
||||
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
g_warning ("Impossible to get devices");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev = discover_device (devices);
|
||||
if (!dev)
|
||||
{
|
||||
g_warning ("No devices detected.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
list_data = g_new0 (ListData, 1);
|
||||
list_data->ret_value = EXIT_FAILURE;
|
||||
list_data->loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data);
|
||||
|
||||
g_main_loop_run (list_data->loop);
|
||||
|
||||
return list_data->ret_value;
|
||||
}
|
||||
@@ -1,29 +1,19 @@
|
||||
|
||||
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ]
|
||||
examples = [ 'enroll', 'verify', 'manage-prints' ]
|
||||
foreach example: examples
|
||||
executable(example,
|
||||
example + '.c',
|
||||
dependencies: libfprint_dep,
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||
dependencies: [ libfprint_dep, glib_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
endforeach
|
||||
|
||||
executable('cpp-test',
|
||||
'cpp-test.cpp',
|
||||
dependencies: libfprint_dep,
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
|
||||
if get_option('x11-examples')
|
||||
executable('img_capture_continuous',
|
||||
'img_capture_continuous.c',
|
||||
dependencies: [ libfprint_dep, xv_dep, x11_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
endif
|
||||
'cpp-test.cpp',
|
||||
dependencies: libfprint_dep,
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
These are example images from NIST and are not copyrighted.
|
||||
These are example images from NIST and are in the public domain.
|
||||
|
||||
The PNG files have been generated by using the greyscale data as a mask.
|
||||
The PNG files have been generated by using the greyscale data as a mask.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# This script can be used together with the virtual_imgdev to simulate an
|
||||
# image based fingerprint reader.
|
||||
#
|
||||
# To use, set the FP_VIRTUAL_IMGDEV environment variable for both the
|
||||
# To use, set the FP_VIRTUAL_IMAGE environment variable for both the
|
||||
# libfprint using program (e.g. fprintd) and this script.
|
||||
#
|
||||
# Usually this would work by adding it into the systemd unit file. The
|
||||
@@ -12,7 +12,7 @@
|
||||
#
|
||||
# [Service]
|
||||
# RuntimeDirectory=fprint
|
||||
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
|
||||
# Environment=FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock
|
||||
# Environment=G_MESSAGES_DEBUG=all
|
||||
# ReadWritePaths=$RUNTIME_DIR
|
||||
#
|
||||
@@ -24,7 +24,7 @@
|
||||
# You may also need to disable selinux.
|
||||
#
|
||||
# Then run this script with e.g.
|
||||
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
|
||||
# FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,33 @@ import os
|
||||
import socket
|
||||
import struct
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
if len(sys.argv) != 2:
|
||||
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
|
||||
sys.exit(1)
|
||||
|
||||
# Just copied from the C file, we could also use the introspection data for
|
||||
# this. Also, most of them do *not* make any sense.
|
||||
commands = {
|
||||
'retry' : struct.pack('ii', -1, 0),
|
||||
'retry-too-short' : struct.pack('ii', -1, 1),
|
||||
'retry-center-finger' : struct.pack('ii', -1, 2),
|
||||
'retry-remove-finger' : struct.pack('ii', -1, 3),
|
||||
|
||||
'error' : struct.pack('ii', -2, 0),
|
||||
'error-not-supported' : struct.pack('ii', -2, 1),
|
||||
'error-not-open' : struct.pack('ii', -2, 2),
|
||||
'error-already-open' : struct.pack('ii', -2, 3),
|
||||
'error-busy' : struct.pack('ii', -2, 4),
|
||||
'error-proto' : struct.pack('ii', -2, 5),
|
||||
'error-data-invalid' : struct.pack('ii', -2, 6),
|
||||
'error-data-not-found' : struct.pack('ii', -2, 7),
|
||||
'error-data-full' : struct.pack('ii', -2, 8),
|
||||
}
|
||||
|
||||
|
||||
if sys.argv[1] in commands:
|
||||
command = commands[sys.argv[1]]
|
||||
else:
|
||||
png = cairo.ImageSurface.create_from_png(sys.argv[1])
|
||||
|
||||
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
|
||||
@@ -53,9 +79,15 @@ if len(sys.argv) == 2:
|
||||
|
||||
cr.set_source_surface(png)
|
||||
cr.paint()
|
||||
else:
|
||||
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
|
||||
sys.exit(1)
|
||||
|
||||
mem = img.get_data()
|
||||
mem = mem.tobytes()
|
||||
assert len(mem) == img.get_width() * img.get_height()
|
||||
|
||||
command = struct.pack('ii', img.get_width(), img.get_height())
|
||||
command += mem
|
||||
|
||||
|
||||
|
||||
def write_dbg_img():
|
||||
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
|
||||
@@ -70,17 +102,10 @@ def write_dbg_img():
|
||||
#write_dbg_img()
|
||||
|
||||
# Send image through socket
|
||||
sockaddr = os.environ['FP_VIRTUAL_IMGDEV']
|
||||
sockaddr = os.environ['FP_VIRTUAL_IMAGE']
|
||||
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.connect(sockaddr)
|
||||
|
||||
mem = img.get_data()
|
||||
mem = mem.tobytes()
|
||||
assert len(mem) == img.get_width() * img.get_height()
|
||||
|
||||
encoded_img = struct.pack('ii', img.get_width(), img.get_height())
|
||||
encoded_img += mem
|
||||
|
||||
sock.sendall(encoded_img)
|
||||
sock.sendall(command)
|
||||
|
||||
|
||||
226
examples/storage.c
Normal file
226
examples/storage.c
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Trivial storage driver for example programs
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define STORAGE_FILE "test-storage.variant"
|
||||
|
||||
static char *
|
||||
get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
|
||||
{
|
||||
const char *driver;
|
||||
const char *dev_id;
|
||||
|
||||
if (print)
|
||||
{
|
||||
driver = fp_print_get_driver (print);
|
||||
dev_id = fp_print_get_device_id (print);
|
||||
}
|
||||
else
|
||||
{
|
||||
driver = fp_device_get_driver (dev);
|
||||
dev_id = fp_device_get_device_id (dev);
|
||||
}
|
||||
|
||||
return g_strdup_printf ("%s/%s/%x",
|
||||
driver,
|
||||
dev_id,
|
||||
finger);
|
||||
}
|
||||
|
||||
static GVariantDict *
|
||||
load_data (void)
|
||||
{
|
||||
GVariantDict *res;
|
||||
GVariant *var;
|
||||
g_autofree gchar *contents = NULL;
|
||||
gssize length = 0;
|
||||
|
||||
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
|
||||
{
|
||||
g_warning ("Error loading storage, assuming it is empty");
|
||||
return g_variant_dict_new (NULL);
|
||||
}
|
||||
|
||||
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL);
|
||||
|
||||
res = g_variant_dict_new (var);
|
||||
g_variant_unref (var);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
save_data (GVariant *data)
|
||||
{
|
||||
const gchar *contents = NULL;
|
||||
gsize length;
|
||||
|
||||
length = g_variant_get_size (data);
|
||||
contents = (gchar *) g_variant_get_data (data);
|
||||
|
||||
if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL))
|
||||
{
|
||||
g_warning ("Error saving storage,!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_variant_ref_sink (data);
|
||||
g_variant_unref (data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
print_data_save (FpPrint *print, FpFinger finger)
|
||||
{
|
||||
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GVariantDict) dict = NULL;
|
||||
g_autofree guchar *data = NULL;
|
||||
GVariant *val;
|
||||
gsize size;
|
||||
int res;
|
||||
|
||||
dict = load_data ();
|
||||
|
||||
fp_print_serialize (print, &data, &size, &error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Error serializing data: %s", error->message);
|
||||
return -1;
|
||||
}
|
||||
val = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), data, size, 1);
|
||||
g_variant_dict_insert_value (dict, descr, val);
|
||||
|
||||
res = save_data (g_variant_dict_end (dict));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
FpPrint *
|
||||
print_data_load (FpDevice *dev, FpFinger finger)
|
||||
{
|
||||
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
|
||||
|
||||
g_autoptr(GVariant) val = NULL;
|
||||
g_autoptr(GVariantDict) dict = NULL;
|
||||
g_autofree guchar *stored_data = NULL;
|
||||
gsize stored_len;
|
||||
|
||||
dict = load_data ();
|
||||
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
|
||||
|
||||
if (val)
|
||||
{
|
||||
FpPrint *print;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
|
||||
print = fp_print_deserialize (stored_data, stored_len, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Error deserializing data: %s", error->message);
|
||||
|
||||
return print;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FpPrint *
|
||||
print_create_template (FpDevice *dev, FpFinger finger)
|
||||
{
|
||||
g_autoptr(GDateTime) datetime = NULL;
|
||||
FpPrint *template = NULL;
|
||||
GDate *date = NULL;
|
||||
gint year, month, day;
|
||||
|
||||
template = fp_print_new (dev);
|
||||
fp_print_set_finger (template, finger);
|
||||
fp_print_set_username (template, g_get_user_name ());
|
||||
datetime = g_date_time_new_now_local ();
|
||||
g_date_time_get_ymd (datetime, &year, &month, &day);
|
||||
date = g_date_new_dmy (day, month, year);
|
||||
fp_print_set_enroll_date (template, date);
|
||||
g_date_free (date);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
save_image_to_pgm (FpImage *img, const char *path)
|
||||
{
|
||||
FILE *fd = fopen (path, "w");
|
||||
size_t write_size;
|
||||
const guchar *data = fp_image_get_data (img, &write_size);
|
||||
int r;
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
g_warning ("could not open '%s' for writing: %d", path, errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r = fprintf (fd, "P5 %d %d 255\n",
|
||||
fp_image_get_width (img), fp_image_get_height (img));
|
||||
if (r < 0)
|
||||
{
|
||||
fclose (fd);
|
||||
g_critical ("pgm header write failed, error %d", r);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r = fwrite (data, 1, write_size, fd);
|
||||
if (r < write_size)
|
||||
{
|
||||
fclose (fd);
|
||||
g_critical ("short write (%d)", r);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fclose (fd);
|
||||
g_debug ("written to '%s'", path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
print_image_save (FpPrint *print, const char *path)
|
||||
{
|
||||
g_autoptr(FpImage) img = NULL;
|
||||
|
||||
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
|
||||
img = fp_print_get_image (print);
|
||||
|
||||
if (img)
|
||||
return save_image_to_pgm (img, path);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
* Trivial storage driver for example programs
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,18 +18,17 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_DATA_H__
|
||||
#define __FPI_DATA_H__
|
||||
#ifndef __STORAGE_H
|
||||
#define __STORAGE_H
|
||||
|
||||
struct fp_print_data;
|
||||
struct fp_print_data_item {
|
||||
size_t length;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
||||
struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data);
|
||||
void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item);
|
||||
int print_data_save (FpPrint *print,
|
||||
FpFinger finger);
|
||||
FpPrint * print_data_load (FpDevice *dev,
|
||||
FpFinger finger);
|
||||
FpPrint * print_create_template (FpDevice *dev,
|
||||
FpFinger finger);
|
||||
gboolean print_image_save (FpPrint *print,
|
||||
const char *path);
|
||||
|
||||
#endif
|
||||
#endif /* __STORAGE_H */
|
||||
135
examples/utilities.c
Normal file
135
examples/utilities.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Utilities for example programs
|
||||
*
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utilities.h"
|
||||
|
||||
FpDevice *
|
||||
discover_device (GPtrArray * devices)
|
||||
{
|
||||
FpDevice *dev;
|
||||
int i;
|
||||
|
||||
if (!devices->len)
|
||||
return NULL;
|
||||
|
||||
if (devices->len == 1)
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Multiple devices found, choose one\n");
|
||||
|
||||
for (i = 0; i < devices->len; ++i)
|
||||
{
|
||||
dev = g_ptr_array_index (devices, i);
|
||||
g_print ("[%d] %s (%s) - driver %s\n", i,
|
||||
fp_device_get_device_id (dev), fp_device_get_name (dev),
|
||||
fp_device_get_driver (dev));
|
||||
}
|
||||
|
||||
g_print ("> ");
|
||||
if (!scanf ("%d%*c", &i))
|
||||
return NULL;
|
||||
|
||||
if (i < 0 || i >= devices->len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = g_ptr_array_index (devices, i);
|
||||
g_print ("Selected device %s (%s) claimed by %s driver\n",
|
||||
fp_device_get_device_id (dev), fp_device_get_name (dev),
|
||||
fp_device_get_driver (dev));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
const char *
|
||||
finger_to_string (FpFinger finger)
|
||||
{
|
||||
switch (finger)
|
||||
{
|
||||
case FP_FINGER_LEFT_THUMB:
|
||||
return "left thumb";
|
||||
|
||||
case FP_FINGER_LEFT_INDEX:
|
||||
return "left index";
|
||||
|
||||
case FP_FINGER_LEFT_MIDDLE:
|
||||
return "left middle";
|
||||
|
||||
case FP_FINGER_LEFT_RING:
|
||||
return "left ring";
|
||||
|
||||
case FP_FINGER_LEFT_LITTLE:
|
||||
return "left little";
|
||||
|
||||
case FP_FINGER_RIGHT_THUMB:
|
||||
return "right thumb";
|
||||
|
||||
case FP_FINGER_RIGHT_INDEX:
|
||||
return "right index";
|
||||
|
||||
case FP_FINGER_RIGHT_MIDDLE:
|
||||
return "right middle";
|
||||
|
||||
case FP_FINGER_RIGHT_RING:
|
||||
return "right ring";
|
||||
|
||||
case FP_FINGER_RIGHT_LITTLE:
|
||||
return "right little";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
FpFinger
|
||||
finger_chooser (void)
|
||||
{
|
||||
int i;
|
||||
const FpFinger all_fingers[] = {
|
||||
FP_FINGER_LEFT_THUMB,
|
||||
FP_FINGER_LEFT_INDEX,
|
||||
FP_FINGER_LEFT_MIDDLE,
|
||||
FP_FINGER_LEFT_RING,
|
||||
FP_FINGER_LEFT_LITTLE,
|
||||
FP_FINGER_RIGHT_THUMB,
|
||||
FP_FINGER_RIGHT_INDEX,
|
||||
FP_FINGER_RIGHT_MIDDLE,
|
||||
FP_FINGER_RIGHT_RING,
|
||||
FP_FINGER_RIGHT_LITTLE,
|
||||
};
|
||||
|
||||
for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i)
|
||||
g_print (" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i));
|
||||
|
||||
g_print ("> ");
|
||||
if (!scanf ("%d%*c", &i))
|
||||
return FP_FINGER_UNKNOWN;
|
||||
|
||||
if (i < 0 || i >= G_N_ELEMENTS (all_fingers))
|
||||
return FP_FINGER_UNKNOWN;
|
||||
|
||||
return all_fingers[i];
|
||||
}
|
||||
28
examples/utilities.h
Normal file
28
examples/utilities.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Trivial storage driver for example programs
|
||||
*
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __UTILITIES_H
|
||||
#define __UTILITIES_H
|
||||
|
||||
FpDevice * discover_device (GPtrArray *devices);
|
||||
FpFinger finger_chooser (void);
|
||||
const char * finger_to_string (FpFinger finger);
|
||||
|
||||
#endif /* __UTILITIES_H */
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Example fingerprint verification program, which verifies the right index
|
||||
* Example fingerprint verification program, which verifies the
|
||||
* finger which has been previously enrolled to disk.
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,132 +20,247 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
#include "storage.h"
|
||||
#include "utilities.h"
|
||||
|
||||
typedef struct _VerifyData
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
GMainLoop *loop;
|
||||
FpFinger finger;
|
||||
int ret_value;
|
||||
} VerifyData;
|
||||
|
||||
static void
|
||||
verify_data_free (VerifyData *verify_data)
|
||||
{
|
||||
g_main_loop_unref (verify_data->loop);
|
||||
g_free (verify_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
|
||||
|
||||
static void
|
||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
VerifyData *verify_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
}
|
||||
|
||||
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
||||
static void start_verification (FpDevice *dev,
|
||||
VerifyData *verify_data);
|
||||
|
||||
static void
|
||||
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
int r;
|
||||
VerifyData *verify_data = user_data;
|
||||
|
||||
do {
|
||||
struct fp_img *img = NULL;
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
char buffer[20];
|
||||
gboolean match;
|
||||
|
||||
sleep(1);
|
||||
printf("\nScan your finger now.\n");
|
||||
r = fp_verify_finger_img(dev, data, &img);
|
||||
if (img) {
|
||||
fp_img_save_to_file(img, "verify.pgm");
|
||||
printf("Wrote scanned image to verify.pgm\n");
|
||||
fp_img_free(img);
|
||||
}
|
||||
if (r < 0) {
|
||||
printf("verification failed with error %d :(\n", r);
|
||||
return r;
|
||||
}
|
||||
switch (r) {
|
||||
case FP_VERIFY_NO_MATCH:
|
||||
printf("NO MATCH!\n");
|
||||
return 0;
|
||||
case FP_VERIFY_MATCH:
|
||||
printf("MATCH!\n");
|
||||
return 0;
|
||||
case FP_VERIFY_RETRY:
|
||||
printf("Scan didn't quite work. Please try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
||||
printf("Swipe was too short, please try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
||||
printf("Please center your finger on the sensor and try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
||||
printf("Please remove finger from the sensor and try again.\n");
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
||||
{
|
||||
g_warning ("Failed to verify print: %s", error->message);
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
g_print ("MATCH!\n");
|
||||
if (fp_device_supports_capture (dev) &&
|
||||
print_image_save (print, "verify.pgm"))
|
||||
g_print ("Print image saved as verify.pgm");
|
||||
|
||||
verify_data->ret_value = EXIT_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("NO MATCH!\n");
|
||||
verify_data->ret_value = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
g_print ("Verify again? [Y/n]? ");
|
||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||
(buffer[0] == 'Y' || buffer[0] == 'y'))
|
||||
{
|
||||
start_verification (dev, verify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
verify_data);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
static void
|
||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
int r = 1;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
struct fp_print_data *data;
|
||||
VerifyData *verify_data = user_data;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
g_autoptr(GPtrArray) prints = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
prints = fp_device_list_prints_finish (dev, res, &error);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
FpPrint *verify_print = NULL;
|
||||
guint i;
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
if (!prints->len)
|
||||
g_warning ("No prints saved on device");
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < prints->len; ++i)
|
||||
{
|
||||
FpPrint *print = prints->pdata[i];
|
||||
|
||||
printf("Opened device. Loading previously enrolled right index finger "
|
||||
"data...\n");
|
||||
if (fp_print_get_finger (print) == verify_data->finger &&
|
||||
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
||||
{
|
||||
const GDate *verify_print_date = NULL;
|
||||
const GDate *print_date = fp_print_get_enroll_date (print);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
|
||||
#pragma GCC diagnostic pop
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
|
||||
fprintf(stderr, "Did you remember to enroll your right index finger "
|
||||
"first?\n");
|
||||
goto out_close;
|
||||
}
|
||||
if (verify_print)
|
||||
verify_print_date = fp_print_get_enroll_date (verify_print);
|
||||
|
||||
printf("Print loaded. Time to verify!\n");
|
||||
do {
|
||||
char buffer[20];
|
||||
if (!verify_print || !print_date || !verify_print_date ||
|
||||
g_date_compare (print_date, verify_print_date) >= 0)
|
||||
verify_print = print;
|
||||
}
|
||||
}
|
||||
|
||||
verify(dev, data);
|
||||
printf("Verify again? [Y/n]? ");
|
||||
fgets(buffer, sizeof(buffer), stdin);
|
||||
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
|
||||
break;
|
||||
} while (1);
|
||||
if (!verify_print)
|
||||
{
|
||||
g_warning ("Did you remember to enroll your %s finger first?",
|
||||
finger_to_string (verify_data->finger));
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_print_data_free(data);
|
||||
out_close:
|
||||
fp_dev_close(dev);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
g_debug ("Comparing print with %s",
|
||||
fp_print_get_description (verify_print));
|
||||
|
||||
g_print ("Print loaded. Time to verify!\n");
|
||||
fp_device_verify (dev, verify_print, NULL,
|
||||
(GAsyncReadyCallback) on_verify_completed,
|
||||
verify_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Loading prints failed with error %s", error->message);
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||
{
|
||||
g_print ("Choose the finger to verify:\n");
|
||||
verify_data->finger = finger_chooser ();
|
||||
|
||||
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
||||
{
|
||||
g_warning ("Unknown finger selected");
|
||||
verify_data->ret_value = EXIT_FAILURE;
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp_device_has_storage (dev))
|
||||
{
|
||||
g_print ("Creating finger template, using device storage...\n");
|
||||
fp_device_list_prints (dev, NULL,
|
||||
(GAsyncReadyCallback) on_list_completed,
|
||||
verify_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Loading previously enrolled %s finger data...\n",
|
||||
finger_to_string (verify_data->finger));
|
||||
g_autoptr(FpPrint) verify_print = NULL;
|
||||
|
||||
verify_print = print_data_load (dev, verify_data->finger);
|
||||
|
||||
if (!verify_print)
|
||||
{
|
||||
g_warning ("Failed to load fingerprint data");
|
||||
g_warning ("Did you remember to enroll your %s finger first?",
|
||||
finger_to_string (verify_data->finger));
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Print loaded. Time to verify!\n");
|
||||
fp_device_verify (dev, verify_print, NULL,
|
||||
(GAsyncReadyCallback) on_verify_completed,
|
||||
verify_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
VerifyData *verify_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Opened device. ");
|
||||
|
||||
start_verification (dev, verify_data);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
g_autoptr(FpContext) ctx = NULL;
|
||||
g_autoptr(VerifyData) verify_data = NULL;
|
||||
GPtrArray *devices;
|
||||
FpDevice *dev;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
ctx = fp_context_new ();
|
||||
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
g_warning ("Impossible to get devices");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev = discover_device (devices);
|
||||
if (!dev)
|
||||
{
|
||||
g_warning ("No devices detected.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
verify_data = g_new0 (VerifyData, 1);
|
||||
verify_data->ret_value = EXIT_FAILURE;
|
||||
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
||||
verify_data);
|
||||
|
||||
g_main_loop_run (verify_data->loop);
|
||||
|
||||
return verify_data->ret_value;
|
||||
}
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Example fingerprint verification program
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||
{
|
||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||
struct fp_driver *drv;
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
drv = fp_dscv_dev_get_driver(ddev);
|
||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||
return ddev;
|
||||
}
|
||||
|
||||
struct fp_print_data *enroll(struct fp_dev *dev) {
|
||||
struct fp_print_data *enrolled_print = NULL;
|
||||
int r;
|
||||
|
||||
printf("You will need to successfully scan your finger %d times to "
|
||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
||||
|
||||
do {
|
||||
printf("\nScan your finger now.\n");
|
||||
r = fp_enroll_finger(dev, &enrolled_print);
|
||||
if (r < 0) {
|
||||
printf("Enroll failed with error %d\n", r);
|
||||
return NULL;
|
||||
}
|
||||
switch (r) {
|
||||
case FP_ENROLL_COMPLETE:
|
||||
printf("Enroll complete!\n");
|
||||
break;
|
||||
case FP_ENROLL_FAIL:
|
||||
printf("Enroll failed, something wen't wrong :(\n");
|
||||
return NULL;
|
||||
case FP_ENROLL_PASS:
|
||||
printf("Enroll stage passed. Yay!\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY:
|
||||
printf("Didn't quite catch that. Please try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
||||
printf("Your swipe was too short, please try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
||||
printf("Didn't catch that, please center your finger on the "
|
||||
"sensor and try again.\n");
|
||||
break;
|
||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
||||
printf("Scan failed, please remove your finger and then try "
|
||||
"again.\n");
|
||||
break;
|
||||
}
|
||||
} while (r != FP_ENROLL_COMPLETE);
|
||||
|
||||
if (!enrolled_print) {
|
||||
fprintf(stderr, "Enroll complete but no print?\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Enrollment completed!\n\n");
|
||||
return enrolled_print;
|
||||
}
|
||||
|
||||
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
sleep(1);
|
||||
printf("\nScan your finger now.\n");
|
||||
r = fp_verify_finger(dev, data);
|
||||
if (r < 0) {
|
||||
printf("verification failed with error %d :(\n", r);
|
||||
return r;
|
||||
}
|
||||
switch (r) {
|
||||
case FP_VERIFY_NO_MATCH:
|
||||
printf("NO MATCH!\n");
|
||||
return 0;
|
||||
case FP_VERIFY_MATCH:
|
||||
printf("MATCH!\n");
|
||||
return 0;
|
||||
case FP_VERIFY_RETRY:
|
||||
printf("Scan didn't quite work. Please try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
||||
printf("Swipe was too short, please try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
||||
printf("Please center your finger on the sensor and try again.\n");
|
||||
break;
|
||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
||||
printf("Please remove finger from the sensor and try again.\n");
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int r = 1;
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
struct fp_dev *dev;
|
||||
struct fp_print_data *data;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
r = fp_init();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
fprintf(stderr, "Could not discover devices\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = fp_dev_open(ddev);
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Could not open device.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Opened device. It's now time to enroll your finger.\n\n");
|
||||
data = enroll(dev);
|
||||
if (!data)
|
||||
goto out_close;
|
||||
|
||||
|
||||
printf("Normally we'd save that print to disk, and recall it at some "
|
||||
"point later when we want to authenticate the user who just "
|
||||
"enrolled. In the interests of demonstration, we'll authenticate "
|
||||
"that user immediately.\n");
|
||||
|
||||
do {
|
||||
char buffer[20];
|
||||
|
||||
verify(dev, data);
|
||||
printf("Verify again? [Y/n]? ");
|
||||
fgets(buffer, sizeof(buffer), stdin);
|
||||
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
fp_print_data_free(data);
|
||||
out_close:
|
||||
fp_dev_close(dev);
|
||||
out:
|
||||
fp_exit();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script can be used together with the virtual_misdev to simulate an
|
||||
# match-in-sensor device with internal storage.
|
||||
#
|
||||
# To use, set the FP_VIRTUAL_MISDEV environment variable for both the
|
||||
# libfprint using program (e.g. fprintd) and this script.
|
||||
#
|
||||
# Usually this would work by adding it into the systemd unit file. The
|
||||
# best way of doing so is to create
|
||||
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
|
||||
#
|
||||
# [Service]
|
||||
# RuntimeDirectory=fprint
|
||||
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
|
||||
# Environment=G_MESSAGES_DEBUG=all
|
||||
# ReadWritePaths=$RUNTIME_DIR
|
||||
#
|
||||
# After that run:
|
||||
#
|
||||
# systemctl daemon-reload
|
||||
# systemctl restart fprintd.service
|
||||
#
|
||||
# You may also need to disable selinux.
|
||||
#
|
||||
# Then run this script with e.g.
|
||||
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./virtmissensor.py /tmp/storage
|
||||
#
|
||||
# Please note that the storage file should be pre-created with a few lines
|
||||
# Each line represents a slot, if a print is stored, then it will contain a
|
||||
# UUID (defined by the driver) and a matching string to identify it again.
|
||||
# Note that the last slot line should not end with a \n
|
||||
|
||||
import sys
|
||||
import os
|
||||
import socket
|
||||
import struct
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Play virtual fingerprint device with internal storage.')
|
||||
parser.add_argument('storage', metavar='storage', type=argparse.FileType('r+'),
|
||||
help='The "storage" database (one line per slot)')
|
||||
parser.add_argument('-e', dest='enroll', type=str,
|
||||
help='Enroll a print using the string as identifier')
|
||||
parser.add_argument('-v', dest='verify', type=str,
|
||||
help='Verify print if the stored identifier matches the given identifier')
|
||||
parser.add_argument('-d', dest='delete', action='store_const', const=True,
|
||||
help='Delete print as requested by driver')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
cnt = 0
|
||||
if args.enroll:
|
||||
cnt += 1
|
||||
if args.verify:
|
||||
cnt += 1
|
||||
if args.delete:
|
||||
cnt += 1
|
||||
|
||||
assert cnt == 1, 'You need to give exactly one command argument, -e or -v'
|
||||
|
||||
prints = []
|
||||
for slot in args.storage.read().split('\n'):
|
||||
split = slot.split(' ', 1)
|
||||
if len(split) == 2:
|
||||
prints.append(split)
|
||||
else:
|
||||
prints.append(None)
|
||||
|
||||
|
||||
# Send image through socket
|
||||
sockaddr = os.environ['FP_VIRTUAL_MISDEV']
|
||||
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.connect(sockaddr)
|
||||
|
||||
# Assume we get a full message
|
||||
msg = sock.recv(1024)
|
||||
assert(msg[-1] == ord(b'\n'))
|
||||
|
||||
if args.enroll:
|
||||
if not msg.startswith(b'ENROLL '):
|
||||
sys.stderr.write('Expected to enroll, but driver is not ready for enrolling (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||
sys.exit(1)
|
||||
uuid = msg[7:-1].decode('utf-8')
|
||||
|
||||
for slot in prints:
|
||||
if slot is not None and slot[0] == uuid:
|
||||
sock.sendall(b'2\n') # ENROLL_FAIL
|
||||
sys.stderr.write('Failed to enroll; UUID has already been stored!\n')
|
||||
sys.exit(1)
|
||||
|
||||
# Find an empty slot
|
||||
for i, slot in enumerate(prints):
|
||||
if slot is not None:
|
||||
continue
|
||||
|
||||
prints[i] = (uuid, args.enroll)
|
||||
sock.sendall(b'1\n') # ENROLL_COMPLETE
|
||||
break
|
||||
else:
|
||||
# TODO: 2: ENROLL_FAIL, but we should send no empty slot!
|
||||
sock.sendall(b'2\n') # ENROLL_FAIL
|
||||
sys.stderr.write('Failed to enroll, no free slots!\n')
|
||||
sys.exit(1)
|
||||
|
||||
elif args.verify:
|
||||
if not msg.startswith(b'VERIFY '):
|
||||
sys.stderr.write('Expected to verify, but driver is not ready for verifying (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||
sys.exit(1)
|
||||
uuid = msg[7:-1].decode('utf-8')
|
||||
|
||||
for slot in prints:
|
||||
if slot is not None and slot[0] == uuid:
|
||||
if slot[1] == args.verify:
|
||||
sock.sendall(b'1\n') # VERIFY_MATCH
|
||||
else:
|
||||
sock.sendall(b'0\n') # VERIFY_NO_MATCH
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.stderr.write('Slot ID is unknown, returning error\n')
|
||||
sock.sendall(b'-1') # error, need way to report that print is unkown
|
||||
|
||||
elif args.delete:
|
||||
if not msg.startswith(b'DELETE '):
|
||||
sys.stderr.write('Expected to delete, but driver is not ready for deleting (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||
sys.exit(1)
|
||||
uuid = msg[7:-1].decode('utf-8')
|
||||
|
||||
for i, slot in enumerate(prints):
|
||||
if slot is not None and slot[0] == uuid:
|
||||
if slot[0] == uuid:
|
||||
prints[i] = None
|
||||
sock.sendall(b'0\n') # DELETE_COMPLETE
|
||||
break
|
||||
else:
|
||||
sys.stderr.write('Slot ID is unknown, just report back complete\n')
|
||||
sock.sendall(b'0') # DELETE_COMPLETE
|
||||
|
||||
prints_str = '\n'.join('' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
|
||||
prints_human_str = '\n'.join('empty slot' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
|
||||
|
||||
print('Prints stored now:')
|
||||
print(prints_human_str)
|
||||
args.storage.seek(0)
|
||||
args.storage.truncate()
|
||||
args.storage.write(prints_str)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,89 +25,71 @@
|
||||
#include "aes1660.h"
|
||||
|
||||
#define FRAME_WIDTH 128
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
|
||||
struct _FpiDeviceAes1660
|
||||
{
|
||||
FpiDeviceAesX660 parent;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI,
|
||||
DEVICE_AES1660, FpiDeviceAesX660);
|
||||
G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660);
|
||||
|
||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||
.frame_width = FRAME_WIDTH,
|
||||
.frame_height = AESX660_FRAME_HEIGHT,
|
||||
.image_width = IMAGE_WIDTH,
|
||||
.get_pixel = aes_get_pixel,
|
||||
.frame_width = FRAME_WIDTH,
|
||||
.frame_height = AESX660_FRAME_HEIGHT,
|
||||
.image_width = IMAGE_WIDTH,
|
||||
.get_pixel = aes_get_pixel,
|
||||
};
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x08ff, .pid = 0x1660, },
|
||||
{ .vid = 0x08ff, .pid = 0x1680, },
|
||||
{ .vid = 0x08ff, .pid = 0x1681, },
|
||||
{ .vid = 0x08ff, .pid = 0x1682, },
|
||||
{ .vid = 0x08ff, .pid = 0x1683, },
|
||||
{ .vid = 0x08ff, .pid = 0x1684, },
|
||||
{ .vid = 0x08ff, .pid = 0x1685, },
|
||||
{ .vid = 0x08ff, .pid = 0x1686, },
|
||||
{ .vid = 0x08ff, .pid = 0x1687, },
|
||||
{ .vid = 0x08ff, .pid = 0x1688, },
|
||||
{ .vid = 0x08ff, .pid = 0x1689, },
|
||||
{ .vid = 0x08ff, .pid = 0x168a, },
|
||||
{ .vid = 0x08ff, .pid = 0x168b, },
|
||||
{ .vid = 0x08ff, .pid = 0x168c, },
|
||||
{ .vid = 0x08ff, .pid = 0x168d, },
|
||||
{ .vid = 0x08ff, .pid = 0x168e, },
|
||||
{ .vid = 0x08ff, .pid = 0x168f, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_aes1660_init (FpiDeviceAes1660 *self)
|
||||
{
|
||||
/* TODO check that device has endpoints we're using */
|
||||
int r;
|
||||
struct aesX660_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
aesdev->init_seqs[0] = aes1660_init_1;
|
||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
|
||||
aesdev->init_seqs[1] = aes1660_init_2;
|
||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2);
|
||||
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
||||
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
||||
aesdev->assembling_ctx = &assembling_ctx;
|
||||
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
||||
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
static void
|
||||
fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass)
|
||||
{
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev->buffer);
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
||||
|
||||
dev_class->id = "aes1660";
|
||||
dev_class->full_name = "AuthenTec AES1660";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||
|
||||
img_class->bz3_threshold = 20;
|
||||
|
||||
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
|
||||
img_class->img_height = -1;
|
||||
|
||||
aes_class->init_seqs[0] = aes1660_init_1;
|
||||
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes1660_init_1);
|
||||
aes_class->init_seqs[1] = aes1660_init_2;
|
||||
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes1660_init_2);
|
||||
aes_class->start_imaging_cmd = (unsigned char *) aes1660_start_imaging_cmd;
|
||||
aes_class->start_imaging_cmd_len = sizeof (aes1660_start_imaging_cmd);
|
||||
aes_class->assembling_ctx = &assembling_ctx;
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x08ff, .product = 0x1660 },
|
||||
{ .vendor = 0x08ff, .product = 0x1680 },
|
||||
{ .vendor = 0x08ff, .product = 0x1681 },
|
||||
{ .vendor = 0x08ff, .product = 0x1682 },
|
||||
{ .vendor = 0x08ff, .product = 0x1683 },
|
||||
{ .vendor = 0x08ff, .product = 0x1684 },
|
||||
{ .vendor = 0x08ff, .product = 0x1685 },
|
||||
{ .vendor = 0x08ff, .product = 0x1686 },
|
||||
{ .vendor = 0x08ff, .product = 0x1687 },
|
||||
{ .vendor = 0x08ff, .product = 0x1688 },
|
||||
{ .vendor = 0x08ff, .product = 0x1689 },
|
||||
{ .vendor = 0x08ff, .product = 0x168a },
|
||||
{ .vendor = 0x08ff, .product = 0x168b },
|
||||
{ .vendor = 0x08ff, .product = 0x168c },
|
||||
{ .vendor = 0x08ff, .product = 0x168d },
|
||||
{ .vendor = 0x08ff, .product = 0x168e },
|
||||
{ .vendor = 0x08ff, .product = 0x168f },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
struct fp_img_driver aes1660_driver = {
|
||||
.driver = {
|
||||
.id = AES1660_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "AuthenTec AES1660",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
.bz3_threshold = 20,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = aesX660_dev_activate,
|
||||
.deactivate = aesX660_dev_deactivate,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -23,149 +23,149 @@
|
||||
#define __AES2501_H
|
||||
|
||||
enum aes2501_regs {
|
||||
AES2501_REG_CTRL1 = 0x80,
|
||||
AES2501_REG_CTRL2 = 0x81,
|
||||
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
|
||||
AES2501_REG_DETCTRL = 0x83, /* detect control */
|
||||
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
|
||||
AES2501_REG_MEASDRV = 0x89, /* measure drive */
|
||||
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
|
||||
AES2501_REG_DEMODPHASE1 = 0x8d,
|
||||
AES2501_REG_DEMODPHASE2 = 0x8c,
|
||||
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
|
||||
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
|
||||
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
|
||||
AES2501_REG_STRTROW = 0x93, /* start row */
|
||||
AES2501_REG_ENDROW = 0x94, /* end row */
|
||||
AES2501_REG_STRTCOL = 0x95, /* start column */
|
||||
AES2501_REG_ENDCOL = 0x96, /* end column */
|
||||
AES2501_REG_DATFMT = 0x97, /* data format */
|
||||
AES2501_REG_IMAGCTRL = 0x98, /* image data */
|
||||
AES2501_REG_STAT = 0x9a,
|
||||
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
|
||||
AES2501_REG_CHWORD2 = 0x9c,
|
||||
AES2501_REG_CHWORD3 = 0x9d,
|
||||
AES2501_REG_CHWORD4 = 0x9e,
|
||||
AES2501_REG_CHWORD5 = 0x9f,
|
||||
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
|
||||
AES2501_REG_AUTOCALOFFSET = 0xa8,
|
||||
AES2501_REG_TREGC = 0xac,
|
||||
AES2501_REG_TREGD = 0xad,
|
||||
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
|
||||
AES2501_REG_CTRL1 = 0x80,
|
||||
AES2501_REG_CTRL2 = 0x81,
|
||||
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
|
||||
AES2501_REG_DETCTRL = 0x83, /* detect control */
|
||||
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
|
||||
AES2501_REG_MEASDRV = 0x89, /* measure drive */
|
||||
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
|
||||
AES2501_REG_DEMODPHASE1 = 0x8d,
|
||||
AES2501_REG_DEMODPHASE2 = 0x8c,
|
||||
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
|
||||
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
|
||||
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
|
||||
AES2501_REG_STRTROW = 0x93, /* start row */
|
||||
AES2501_REG_ENDROW = 0x94, /* end row */
|
||||
AES2501_REG_STRTCOL = 0x95, /* start column */
|
||||
AES2501_REG_ENDCOL = 0x96, /* end column */
|
||||
AES2501_REG_DATFMT = 0x97, /* data format */
|
||||
AES2501_REG_IMAGCTRL = 0x98, /* image data */
|
||||
AES2501_REG_STAT = 0x9a,
|
||||
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
|
||||
AES2501_REG_CHWORD2 = 0x9c,
|
||||
AES2501_REG_CHWORD3 = 0x9d,
|
||||
AES2501_REG_CHWORD4 = 0x9e,
|
||||
AES2501_REG_CHWORD5 = 0x9f,
|
||||
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
|
||||
AES2501_REG_AUTOCALOFFSET = 0xa8,
|
||||
AES2501_REG_TREGC = 0xac,
|
||||
AES2501_REG_TREGD = 0xad,
|
||||
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
|
||||
};
|
||||
|
||||
#define FIRST_AES2501_REG AES2501_REG_CTRL1
|
||||
#define LAST_AES2501_REG AES2501_REG_CHWORD5
|
||||
#define FIRST_AES2501_REG AES2501_REG_CTRL1
|
||||
#define LAST_AES2501_REG AES2501_REG_CHWORD5
|
||||
|
||||
#define AES2501_CTRL1_MASTER_RESET (1<<0)
|
||||
#define AES2501_CTRL1_SCAN_RESET (1<<1) /* stop + restart scan sequencer */
|
||||
#define AES2501_CTRL1_MASTER_RESET (1 << 0)
|
||||
#define AES2501_CTRL1_SCAN_RESET (1 << 1) /* stop + restart scan sequencer */
|
||||
/* 1 = continuously updated, 0 = updated prior to starting a scan */
|
||||
#define AES2501_CTRL1_REG_UPDATE (1<<2)
|
||||
#define AES2501_CTRL1_REG_UPDATE (1 << 2)
|
||||
|
||||
/* 1 = continuous scans, 0 = single scans */
|
||||
#define AES2501_CTRL2_CONTINUOUS 0x01
|
||||
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
|
||||
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
|
||||
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
|
||||
#define AES2501_CTRL2_READ_ID 0x10
|
||||
#define AES2501_CTRL2_CONTINUOUS 0x01
|
||||
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
|
||||
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
|
||||
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
|
||||
#define AES2501_CTRL2_READ_ID 0x10
|
||||
|
||||
enum aes2501_detection_rate {
|
||||
/* rate of detection cycles: */
|
||||
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
|
||||
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
|
||||
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
|
||||
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
|
||||
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
|
||||
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
|
||||
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
|
||||
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
|
||||
/* rate of detection cycles: */
|
||||
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
|
||||
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
|
||||
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
|
||||
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
|
||||
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
|
||||
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
|
||||
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
|
||||
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
|
||||
};
|
||||
|
||||
enum aes2501_settling_delay {
|
||||
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
|
||||
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
|
||||
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
|
||||
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
|
||||
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
|
||||
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
|
||||
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
|
||||
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
|
||||
};
|
||||
|
||||
enum aes2501_col_scan_rate {
|
||||
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
|
||||
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
|
||||
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
|
||||
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
|
||||
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
|
||||
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
|
||||
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
|
||||
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
|
||||
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
|
||||
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
|
||||
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
|
||||
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
|
||||
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
|
||||
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
|
||||
|
||||
};
|
||||
|
||||
enum aes2501_mesure_drive {
|
||||
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
|
||||
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
|
||||
|
||||
};
|
||||
|
||||
/* Select (1=square | 0=sine) wave drive during measure */
|
||||
#define AES2501_MEASDRV_SQUARE 0x20
|
||||
/* 0 = use mesure drive setting, 1 = when sine wave is selected */
|
||||
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
|
||||
#define AES2501_MEASDRV_SQUARE 0x20
|
||||
/* 0 = use measure drive setting, 1 = when sine wave is selected */
|
||||
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
|
||||
|
||||
enum aes2501_measure_freq {
|
||||
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
|
||||
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
|
||||
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
|
||||
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
|
||||
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
|
||||
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
|
||||
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
|
||||
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
|
||||
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
|
||||
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
|
||||
};
|
||||
|
||||
#define DEMODPHASE_NONE 0x00
|
||||
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
|
||||
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
|
||||
#define DEMODPHASE_NONE 0x00
|
||||
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
|
||||
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
|
||||
|
||||
#define AES2501_REG_DEMODPHASE1 0x8d
|
||||
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
|
||||
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
|
||||
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
|
||||
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
|
||||
|
||||
enum aes2501_sensor_gain1 {
|
||||
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
|
||||
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
|
||||
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
|
||||
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
|
||||
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
|
||||
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
|
||||
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
|
||||
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
|
||||
};
|
||||
|
||||
enum aes2501_sensor_gain2 {
|
||||
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
|
||||
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
|
||||
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
|
||||
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
|
||||
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
|
||||
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
|
||||
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
|
||||
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
|
||||
};
|
||||
|
||||
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
|
||||
#define AES2501_DATFMT_LOW_RES 0x20
|
||||
#define AES2501_DATFMT_BIN_IMG 0x10
|
||||
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
|
||||
#define AES2501_DATFMT_LOW_RES 0x20
|
||||
#define AES2501_DATFMT_BIN_IMG 0x10
|
||||
|
||||
/* don't send image or authentication messages when imaging */
|
||||
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
|
||||
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
|
||||
/* send histogram when imaging */
|
||||
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
|
||||
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
|
||||
/* send histogram at end of each row rather than each scan */
|
||||
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
|
||||
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
|
||||
/* send full image array rather than 64x64 center */
|
||||
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
|
||||
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
|
||||
/* return registers before data (rather than after) */
|
||||
#define AES2501_IMAGCTRL_REG_FIRST 0x10
|
||||
#define AES2501_IMAGCTRL_REG_FIRST 0x10
|
||||
/* return test registers with register dump */
|
||||
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
|
||||
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
|
||||
|
||||
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
|
||||
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
|
||||
|
||||
/* Enable the reading of the register in TREGD */
|
||||
#define AES2501_TREGC_ENABLE 0x01
|
||||
#define AES2501_TREGC_ENABLE 0x01
|
||||
|
||||
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
|
||||
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
|
||||
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
|
||||
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
|
||||
|
||||
#define AES2501_ADREFHI_MIN_VALUE 0x28
|
||||
#define AES2501_ADREFHI_MAX_VALUE 0x58
|
||||
@@ -173,4 +173,4 @@ enum aes2501_sensor_gain2 {
|
||||
#define AES2501_SUM_HIGH_THRESH 1000
|
||||
#define AES2501_SUM_LOW_THRESH 700
|
||||
|
||||
#endif /* __AES2501_H */
|
||||
#endif /* __AES2501_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,93 +22,93 @@
|
||||
|
||||
/* Registers bits */
|
||||
|
||||
#define AES2550_REG80_MASTER_RESET (1 << 0)
|
||||
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
|
||||
#define AES2550_REG80_LPO_START (1 << 2)
|
||||
#define AES2550_REG80_HGC_ENABLE (1 << 3)
|
||||
#define AES2550_REG80_SENSOR_MODE_OFS (4)
|
||||
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
|
||||
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
|
||||
#define AES2550_REG80_MASTER_RESET (1 << 0)
|
||||
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
|
||||
#define AES2550_REG80_LPO_START (1 << 2)
|
||||
#define AES2550_REG80_HGC_ENABLE (1 << 3)
|
||||
#define AES2550_REG80_SENSOR_MODE_OFS (4)
|
||||
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
|
||||
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
|
||||
|
||||
#define AES2550_REG81_CONT_SCAN (1 << 0)
|
||||
#define AES2550_REG81_READ_REG (1 << 1)
|
||||
#define AES2550_REG81_NSHOT (1 << 2)
|
||||
#define AES2550_REG81_RUN_FD (1 << 3)
|
||||
#define AES2550_REG81_READ_ID (1 << 4)
|
||||
#define AES2550_REG81_RUN_CAL (1 << 5)
|
||||
#define AES2550_REG81_RUN_TIMER (1 << 6)
|
||||
#define AES2550_REG81_RUN_BIST (1 << 7)
|
||||
#define AES2550_REG81_CONT_SCAN (1 << 0)
|
||||
#define AES2550_REG81_READ_REG (1 << 1)
|
||||
#define AES2550_REG81_NSHOT (1 << 2)
|
||||
#define AES2550_REG81_RUN_FD (1 << 3)
|
||||
#define AES2550_REG81_READ_ID (1 << 4)
|
||||
#define AES2550_REG81_RUN_CAL (1 << 5)
|
||||
#define AES2550_REG81_RUN_TIMER (1 << 6)
|
||||
#define AES2550_REG81_RUN_BIST (1 << 7)
|
||||
|
||||
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
|
||||
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
|
||||
|
||||
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
|
||||
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
|
||||
|
||||
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
|
||||
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
|
||||
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
|
||||
#define AES2550_REG8F_HISTO64 (1 << 4)
|
||||
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
|
||||
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
|
||||
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
|
||||
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
|
||||
#define AES2550_REG8F_HISTO64 (1 << 4)
|
||||
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
|
||||
|
||||
#define AES2550_REG95_COL_SCANNED_OFS (0)
|
||||
#define AES2550_REG95_EPIX_AVG_OFS (4)
|
||||
#define AES2550_REG95_COL_SCANNED_OFS (0)
|
||||
#define AES2550_REG95_EPIX_AVG_OFS (4)
|
||||
|
||||
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
|
||||
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
|
||||
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
|
||||
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
|
||||
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
|
||||
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
|
||||
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
|
||||
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
|
||||
|
||||
#define AES2550_REGAD_LPFD_AVG_OFS (0)
|
||||
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
|
||||
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
|
||||
#define AES2550_REGAD_LPFD_AVG_OFS (0)
|
||||
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
|
||||
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
|
||||
|
||||
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
|
||||
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
|
||||
#define AES2550_REGB1_ANALOG_PD (1 << 3)
|
||||
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
|
||||
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
|
||||
#define AES2550_REGB1_RESET_UHSM (1 << 6)
|
||||
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
|
||||
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
|
||||
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
|
||||
#define AES2550_REGB1_ANALOG_PD (1 << 3)
|
||||
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
|
||||
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
|
||||
#define AES2550_REGB1_RESET_UHSM (1 << 6)
|
||||
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
|
||||
|
||||
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
|
||||
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
|
||||
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
|
||||
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
|
||||
|
||||
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
|
||||
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
|
||||
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
|
||||
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
|
||||
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
|
||||
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
|
||||
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
|
||||
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
|
||||
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
|
||||
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
|
||||
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
|
||||
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
|
||||
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
|
||||
|
||||
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
|
||||
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
|
||||
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
|
||||
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
|
||||
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
|
||||
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
|
||||
|
||||
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
|
||||
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
|
||||
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
|
||||
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
|
||||
|
||||
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
|
||||
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
|
||||
|
||||
/* Commands */
|
||||
|
||||
enum aes2550_cmds {
|
||||
AES2550_CMD_SET_IDLE_MODE = 0x00,
|
||||
AES2550_CMD_RUN_FD = 0x01,
|
||||
AES2550_CMD_GET_ENROLL_IMG = 0x02,
|
||||
AES2550_CMD_CALIBRATE = 0x06,
|
||||
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
|
||||
AES2550_CMD_HEARTBEAT = 0x70,
|
||||
AES2550_CMD_SET_IDLE_MODE = 0x00,
|
||||
AES2550_CMD_RUN_FD = 0x01,
|
||||
AES2550_CMD_GET_ENROLL_IMG = 0x02,
|
||||
AES2550_CMD_CALIBRATE = 0x06,
|
||||
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
|
||||
AES2550_CMD_HEARTBEAT = 0x70,
|
||||
};
|
||||
|
||||
/* Messages */
|
||||
|
||||
#define AES2550_STRIP_SIZE (0x31e + 3)
|
||||
#define AES2550_HEARTBEAT_SIZE (4 + 3)
|
||||
#define AES2550_EDATA_MAGIC 0xe0
|
||||
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
||||
#define AES2550_STRIP_SIZE (0x31e + 3)
|
||||
#define AES2550_HEARTBEAT_SIZE (4 + 3)
|
||||
#define AES2550_EDATA_MAGIC 0xe0
|
||||
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
||||
|
||||
#define AES2550_EP_IN_BUF_SIZE 8192
|
||||
#define AES2550_EP_IN_BUF_SIZE 8192
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,91 +25,73 @@
|
||||
#include "aes2660.h"
|
||||
|
||||
#define FRAME_WIDTH 192
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
|
||||
struct _FpiDeviceAes2660
|
||||
{
|
||||
FpiDeviceAesX660 parent;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI,
|
||||
DEVICE_AES2660, FpiDeviceAesX660);
|
||||
G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660);
|
||||
|
||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||
.frame_width = FRAME_WIDTH,
|
||||
.frame_height = AESX660_FRAME_HEIGHT,
|
||||
.image_width = IMAGE_WIDTH,
|
||||
.get_pixel = aes_get_pixel,
|
||||
.frame_width = FRAME_WIDTH,
|
||||
.frame_height = AESX660_FRAME_HEIGHT,
|
||||
.image_width = IMAGE_WIDTH,
|
||||
.get_pixel = aes_get_pixel,
|
||||
};
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x08ff, .pid = 0x2660, },
|
||||
{ .vid = 0x08ff, .pid = 0x2680, },
|
||||
{ .vid = 0x08ff, .pid = 0x2681, },
|
||||
{ .vid = 0x08ff, .pid = 0x2682, },
|
||||
{ .vid = 0x08ff, .pid = 0x2683, },
|
||||
{ .vid = 0x08ff, .pid = 0x2684, },
|
||||
{ .vid = 0x08ff, .pid = 0x2685, },
|
||||
{ .vid = 0x08ff, .pid = 0x2686, },
|
||||
{ .vid = 0x08ff, .pid = 0x2687, },
|
||||
{ .vid = 0x08ff, .pid = 0x2688, },
|
||||
{ .vid = 0x08ff, .pid = 0x2689, },
|
||||
{ .vid = 0x08ff, .pid = 0x268a, },
|
||||
{ .vid = 0x08ff, .pid = 0x268b, },
|
||||
{ .vid = 0x08ff, .pid = 0x268c, },
|
||||
{ .vid = 0x08ff, .pid = 0x268d, },
|
||||
{ .vid = 0x08ff, .pid = 0x268e, },
|
||||
{ .vid = 0x08ff, .pid = 0x268f, },
|
||||
{ .vid = 0x08ff, .pid = 0x2691, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_aes2660_init (FpiDeviceAes2660 *self)
|
||||
{
|
||||
/* TODO check that device has endpoints we're using */
|
||||
int r;
|
||||
struct aesX660_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
/* No scaling for AES2660 */
|
||||
aesdev->init_seqs[0] = aes2660_init_1;
|
||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
|
||||
aesdev->init_seqs[1] = aes2660_init_2;
|
||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2);
|
||||
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
||||
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
||||
aesdev->assembling_ctx = &assembling_ctx;
|
||||
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
||||
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
static void
|
||||
fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass)
|
||||
{
|
||||
struct aesX660_dev *aesdev;
|
||||
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev->buffer);
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
||||
|
||||
dev_class->id = "aes2660";
|
||||
dev_class->full_name = "AuthenTec AES2660";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||
|
||||
img_class->bz3_threshold = 20;
|
||||
|
||||
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
|
||||
img_class->img_height = -1;
|
||||
|
||||
aes_class->init_seqs[0] = aes2660_init_1;
|
||||
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes2660_init_1);
|
||||
aes_class->init_seqs[1] = aes2660_init_2;
|
||||
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes2660_init_2);
|
||||
aes_class->start_imaging_cmd = (unsigned char *) aes2660_start_imaging_cmd;
|
||||
aes_class->start_imaging_cmd_len = sizeof (aes2660_start_imaging_cmd);
|
||||
aes_class->assembling_ctx = &assembling_ctx;
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x08ff, .product = 0x2660 },
|
||||
{ .vendor = 0x08ff, .product = 0x2680 },
|
||||
{ .vendor = 0x08ff, .product = 0x2681 },
|
||||
{ .vendor = 0x08ff, .product = 0x2682 },
|
||||
{ .vendor = 0x08ff, .product = 0x2683 },
|
||||
{ .vendor = 0x08ff, .product = 0x2684 },
|
||||
{ .vendor = 0x08ff, .product = 0x2685 },
|
||||
{ .vendor = 0x08ff, .product = 0x2686 },
|
||||
{ .vendor = 0x08ff, .product = 0x2687 },
|
||||
{ .vendor = 0x08ff, .product = 0x2688 },
|
||||
{ .vendor = 0x08ff, .product = 0x2689 },
|
||||
{ .vendor = 0x08ff, .product = 0x268a },
|
||||
{ .vendor = 0x08ff, .product = 0x268b },
|
||||
{ .vendor = 0x08ff, .product = 0x268c },
|
||||
{ .vendor = 0x08ff, .product = 0x268d },
|
||||
{ .vendor = 0x08ff, .product = 0x268e },
|
||||
{ .vendor = 0x08ff, .product = 0x268f },
|
||||
{ .vendor = 0x08ff, .product = 0x2691 },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
struct fp_img_driver aes2660_driver = {
|
||||
.driver = {
|
||||
.id = AES2660_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "AuthenTec AES2660",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = aesX660_dev_activate,
|
||||
.deactivate = aesX660_dev_deactivate,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,156 +29,130 @@
|
||||
|
||||
#define FP_COMPONENT "aes3500"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
|
||||
#define DATA_BUFLEN 0x2089
|
||||
#define DATA_BUFLEN 0x2089
|
||||
|
||||
/* image size = FRAME_WIDTH x FRAME_WIDTH */
|
||||
#define FRAME_WIDTH 128
|
||||
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||
#define ENLARGE_FACTOR 2
|
||||
#define FRAME_WIDTH 128
|
||||
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||
#define ENLARGE_FACTOR 2
|
||||
|
||||
|
||||
static struct aes_regwrite init_reqs[] = {
|
||||
/* master reset */
|
||||
{ 0x80, 0x01 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* master reset */
|
||||
{ 0x80, 0x01 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
/* scan reset */
|
||||
{ 0x80, 0x02 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* scan reset */
|
||||
{ 0x80, 0x02 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
/* disable register buffering */
|
||||
{ 0x80, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* disable register buffering */
|
||||
{ 0x80, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* windows driver reads registers now (81 02) */
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* windows driver reads registers now (81 02) */
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
|
||||
/* set excitation bias current: 2mhz drive ring frequency,
|
||||
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||
{ 0x82, 0x04 },
|
||||
/* set excitation bias current: 2mhz drive ring frequency,
|
||||
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||
{ 0x82, 0x04 },
|
||||
|
||||
/* continuously sample drive ring for finger detection,
|
||||
* 62.50ms debounce delay */
|
||||
{ 0x83, 0x13 },
|
||||
/* continuously sample drive ring for finger detection,
|
||||
* 62.50ms debounce delay */
|
||||
{ 0x83, 0x13 },
|
||||
|
||||
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||
{ 0x88, 0x02 }, /* set column scan period */
|
||||
{ 0x89, 0x02 }, /* set measure drive */
|
||||
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||
{ 0x8f, 0x07 }, /* set image parameters */
|
||||
{ 0x90, 0x00 }, /* carrier offset null */
|
||||
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||
{ 0x94, 0x07 }, /* set end row */
|
||||
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||
{ 0x96, 0x1f }, /* set end column */
|
||||
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||
{ 0x98, 0x28 }, /* image data control */
|
||||
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||
{ 0x88, 0x02 }, /* set column scan period */
|
||||
{ 0x89, 0x02 }, /* set measure drive */
|
||||
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||
{ 0x8f, 0x07 }, /* set image parameters */
|
||||
{ 0x90, 0x00 }, /* carrier offset null */
|
||||
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||
{ 0x94, 0x07 }, /* set end row */
|
||||
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||
{ 0x96, 0x1f }, /* set end column */
|
||||
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||
{ 0x98, 0x28 }, /* image data control */
|
||||
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
};
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
struct _FpiDeviceAes3500
|
||||
{
|
||||
int r;
|
||||
struct aes3k_dev *aesdev;
|
||||
FpiDeviceAes3k parent;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
|
||||
DEVICE_AES3500, FpiDeviceAes3k);
|
||||
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x08ff, .pid = 0x5731 },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
if (!aesdev)
|
||||
return -ENOMEM;
|
||||
|
||||
aesdev->data_buflen = DATA_BUFLEN;
|
||||
aesdev->frame_width = FRAME_WIDTH;
|
||||
aesdev->frame_size = FRAME_SIZE;
|
||||
aesdev->frame_number = FRAME_NUMBER;
|
||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
||||
aesdev->init_reqs = init_reqs;
|
||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
|
||||
return r;
|
||||
static void
|
||||
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
static void
|
||||
fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
||||
{
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
|
||||
|
||||
dev_class->id = "aes3500";
|
||||
dev_class->full_name = "AuthenTec AES3500";
|
||||
dev_class->id_table = id_table;
|
||||
|
||||
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||
|
||||
aes_class->data_buflen = DATA_BUFLEN;
|
||||
aes_class->frame_width = FRAME_WIDTH;
|
||||
aes_class->frame_size = FRAME_SIZE;
|
||||
aes_class->frame_number = FRAME_NUMBER;
|
||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||
aes_class->init_reqs = init_reqs;
|
||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||
}
|
||||
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x08ff, .product = 0x5731 },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
struct fp_img_driver aes3500_driver = {
|
||||
.driver = {
|
||||
.id = AES3500_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "AuthenTec AES3500",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
|
||||
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
|
||||
|
||||
/* temporarily lowered until image quality improves */
|
||||
.bz3_threshold = 9,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = aes3k_dev_activate,
|
||||
.deactivate = aes3k_dev_deactivate,
|
||||
};
|
||||
|
||||
|
||||
@@ -40,119 +40,187 @@
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
|
||||
#define CTRL_TIMEOUT 1000
|
||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||
|
||||
static void do_capture(struct fp_img_dev *dev);
|
||||
|
||||
static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height,
|
||||
unsigned char *output)
|
||||
typedef struct
|
||||
{
|
||||
size_t row, column;
|
||||
FpiUsbTransfer *img_trf;
|
||||
gboolean deactivating;
|
||||
} FpiDeviceAes3kPrivate;
|
||||
|
||||
for (column = 0; column < width; column++) {
|
||||
for (row = 0; row < height; row += 2) {
|
||||
output[width * row + column] = (*input & 0x0f) * 17;
|
||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||
input++;
|
||||
}
|
||||
}
|
||||
#define CTRL_TIMEOUT 1000
|
||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||
|
||||
static void do_capture (FpImageDevice *dev);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE);
|
||||
|
||||
static void
|
||||
aes3k_assemble_image (unsigned char *input, size_t width, size_t height,
|
||||
unsigned char *output)
|
||||
{
|
||||
size_t row, column;
|
||||
|
||||
for (column = 0; column < width; column++)
|
||||
{
|
||||
for (row = 0; row < height; row += 2)
|
||||
{
|
||||
output[width * row + column] = (*input & 0x0f) * 17;
|
||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||
input++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void img_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *ptr = transfer->buffer;
|
||||
struct fp_img *tmp;
|
||||
struct fp_img *img;
|
||||
int i;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
unsigned char *ptr = transfer->buffer;
|
||||
FpImage *tmp;
|
||||
FpImage *img;
|
||||
int i;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||
goto err;
|
||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_imgdev_session_error(dev, -EIO);
|
||||
goto err;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fpi_imgdev_session_error(dev, -EPROTO);
|
||||
goto err;
|
||||
}
|
||||
priv->img_trf = NULL;
|
||||
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
if (error)
|
||||
{
|
||||
if (g_error_matches (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
/* Deactivation was completed. */
|
||||
g_error_free (error);
|
||||
if (priv->deactivating)
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width);
|
||||
tmp->width = aesdev->frame_width;
|
||||
tmp->height = aesdev->frame_width;
|
||||
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
||||
for (i = 0; i < aesdev->frame_number; i++) {
|
||||
fp_dbg("frame header byte %02x", *ptr);
|
||||
ptr++;
|
||||
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
|
||||
ptr += aesdev->frame_size;
|
||||
}
|
||||
fpi_image_device_session_error (dev, error);
|
||||
}
|
||||
|
||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||
* to process reliably */
|
||||
img = fpi_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
||||
fp_img_free(tmp);
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_image_device_report_finger_status (dev, TRUE);
|
||||
|
||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||
* it really has, then restart the capture */
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
tmp = fp_image_new (cls->frame_width, cls->frame_width);
|
||||
tmp->width = cls->frame_width;
|
||||
tmp->height = cls->frame_width;
|
||||
tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||
for (i = 0; i < cls->frame_number; i++)
|
||||
{
|
||||
fp_dbg ("frame header byte %02x", *ptr);
|
||||
ptr++;
|
||||
aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT));
|
||||
ptr += cls->frame_size;
|
||||
}
|
||||
|
||||
do_capture(dev);
|
||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||
* to process reliably */
|
||||
img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor);
|
||||
g_object_unref (tmp);
|
||||
fpi_image_device_image_captured (dev, img);
|
||||
|
||||
err:
|
||||
g_free(transfer->buffer);
|
||||
aesdev->img_trf = NULL;
|
||||
libusb_free_transfer(transfer);
|
||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||
* it really has, then restart the capture */
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
|
||||
do_capture (dev);
|
||||
}
|
||||
|
||||
static void do_capture(struct fp_img_dev *dev)
|
||||
static void
|
||||
do_capture (FpImageDevice *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data;
|
||||
int r;
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
|
||||
aesdev->img_trf = fpi_usb_alloc();
|
||||
data = g_malloc(aesdev->data_buflen);
|
||||
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data,
|
||||
aesdev->data_buflen, img_cb, dev, 0);
|
||||
|
||||
r = libusb_submit_transfer(aesdev->img_trf);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(aesdev->img_trf);
|
||||
aesdev->img_trf = NULL;
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
}
|
||||
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
|
||||
priv->img_trf->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (priv->img_trf, 0,
|
||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||
img_cb, NULL);
|
||||
}
|
||||
|
||||
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||
static void
|
||||
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||
{
|
||||
fpi_imgdev_activate_complete(dev, result);
|
||||
if (result == 0)
|
||||
do_capture(dev);
|
||||
fpi_image_device_activate_complete (dev, result);
|
||||
if (!result)
|
||||
do_capture (dev);
|
||||
}
|
||||
|
||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
static void
|
||||
aes3k_dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
||||
return 0;
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
|
||||
priv->deactivating = FALSE;
|
||||
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||
}
|
||||
|
||||
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
||||
static void
|
||||
aes3k_dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
|
||||
/* FIXME: should wait for cancellation to complete before returning
|
||||
* from deactivation, otherwise app may legally exit before we've
|
||||
* cleaned up */
|
||||
if (aesdev->img_trf)
|
||||
libusb_cancel_transfer(aesdev->img_trf);
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
priv->deactivating = TRUE;
|
||||
if (priv->img_trf)
|
||||
return;
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
aes3k_dev_init (FpImageDevice *dev)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
||||
{
|
||||
fpi_image_device_open_complete (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_image_device_open_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
aes3k_dev_deinit (FpImageDevice *dev)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||
0, 0, &error);
|
||||
fpi_image_device_close_complete (dev, error);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
img_class->img_open = aes3k_dev_init;
|
||||
img_class->img_close = aes3k_dev_deinit;
|
||||
img_class->activate = aes3k_dev_activate;
|
||||
img_class->deactivate = aes3k_dev_deactivate;
|
||||
|
||||
/* Extremely low due to low image quality. */
|
||||
img_class->bz3_threshold = 9;
|
||||
|
||||
/* Everything else is set by the subclasses. */
|
||||
}
|
||||
|
||||
@@ -34,25 +34,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AES3K_H
|
||||
#define __AES3K_H
|
||||
#pragma once
|
||||
#include "fpi-image-device.h"
|
||||
#include "aeslib.h"
|
||||
|
||||
#define AES3K_FRAME_HEIGHT 16
|
||||
#define AES3K_FRAME_HEIGHT 16
|
||||
|
||||
struct aes3k_dev {
|
||||
struct libusb_transfer *img_trf;
|
||||
size_t frame_width; /* image size = frame_width x frame_width */
|
||||
size_t frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
|
||||
size_t frame_number; /* number of frames */
|
||||
size_t enlarge_factor;
|
||||
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI,
|
||||
DEVICE_AES3K, FpImageDevice)
|
||||
|
||||
size_t data_buflen; /* buffer length of usb bulk transfer */
|
||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||
size_t init_reqs_len;
|
||||
#define FPI_TYPE_DEVICE_AES3K (fpi_device_aes3k_get_type ())
|
||||
|
||||
struct _FpiDeviceAes3kClass
|
||||
{
|
||||
FpImageDeviceClass parent;
|
||||
|
||||
gsize frame_width; /* image size = frame_width x frame_width */
|
||||
gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
|
||||
gsize frame_number; /* number of frames */
|
||||
gsize enlarge_factor;
|
||||
|
||||
gsize data_buflen; /* buffer length of usb bulk transfer */
|
||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||
gsize init_reqs_len;
|
||||
};
|
||||
|
||||
|
||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
void aes3k_dev_deactivate(struct fp_img_dev *dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,156 +26,130 @@
|
||||
|
||||
#define FP_COMPONENT "aes4000"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
|
||||
#define DATA_BUFLEN 0x1259
|
||||
#define DATA_BUFLEN 0x1259
|
||||
|
||||
/* image size = FRAME_WIDTH x FRAME_WIDTH */
|
||||
#define FRAME_WIDTH 96
|
||||
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||
#define ENLARGE_FACTOR 3
|
||||
#define FRAME_WIDTH 96
|
||||
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||
#define ENLARGE_FACTOR 3
|
||||
|
||||
|
||||
static struct aes_regwrite init_reqs[] = {
|
||||
/* master reset */
|
||||
{ 0x80, 0x01 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* master reset */
|
||||
{ 0x80, 0x01 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
/* scan reset */
|
||||
{ 0x80, 0x02 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* scan reset */
|
||||
{ 0x80, 0x02 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
/* disable register buffering */
|
||||
{ 0x80, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* disable register buffering */
|
||||
{ 0x80, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* windows driver reads registers now (81 02) */
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
/* windows driver reads registers now (81 02) */
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
|
||||
/* set excitation bias current: 2mhz drive ring frequency,
|
||||
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||
{ 0x82, 0x04 },
|
||||
/* set excitation bias current: 2mhz drive ring frequency,
|
||||
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||
{ 0x82, 0x04 },
|
||||
|
||||
/* continuously sample drive ring for finger detection,
|
||||
* 62.50ms debounce delay */
|
||||
{ 0x83, 0x13 },
|
||||
/* continuously sample drive ring for finger detection,
|
||||
* 62.50ms debounce delay */
|
||||
{ 0x83, 0x13 },
|
||||
|
||||
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||
{ 0x88, 0x02 }, /* set column scan period */
|
||||
{ 0x89, 0x02 }, /* set measure drive */
|
||||
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||
{ 0x8f, 0x07 }, /* set image parameters */
|
||||
{ 0x90, 0x00 }, /* carrier offset null */
|
||||
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||
{ 0x94, 0x05 }, /* set end row to 5 */
|
||||
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
|
||||
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||
{ 0x98, 0x28 }, /* image data control */
|
||||
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||
{ 0x88, 0x02 }, /* set column scan period */
|
||||
{ 0x89, 0x02 }, /* set measure drive */
|
||||
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||
{ 0x8f, 0x07 }, /* set image parameters */
|
||||
{ 0x90, 0x00 }, /* carrier offset null */
|
||||
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||
{ 0x94, 0x05 }, /* set end row to 5 */
|
||||
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
|
||||
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||
{ 0x98, 0x28 }, /* image data control */
|
||||
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x04 },
|
||||
{ 0, 0 },
|
||||
{ 0x81, 0x00 },
|
||||
};
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
struct _FpiDeviceAes4000
|
||||
{
|
||||
int r;
|
||||
struct aes3k_dev *aesdev;
|
||||
FpiDeviceAes3k parent;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
|
||||
DEVICE_AES4000, FpiDeviceAes3k);
|
||||
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .pid = 0x08ff, .vid = 0x5501 },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
if (!aesdev)
|
||||
return -ENOMEM;
|
||||
|
||||
aesdev->data_buflen = DATA_BUFLEN;
|
||||
aesdev->frame_width = FRAME_WIDTH;
|
||||
aesdev->frame_size = FRAME_SIZE;
|
||||
aesdev->frame_number = FRAME_NUMBER;
|
||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
||||
aesdev->init_reqs = init_reqs;
|
||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
|
||||
return r;
|
||||
static void
|
||||
fpi_device_aes4000_init (FpiDeviceAes4000 *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
static void
|
||||
fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
||||
{
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
|
||||
|
||||
dev_class->id = "aes4000";
|
||||
dev_class->full_name = "AuthenTec AES4000";
|
||||
dev_class->id_table = id_table;
|
||||
|
||||
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||
|
||||
aes_class->data_buflen = DATA_BUFLEN;
|
||||
aes_class->frame_width = FRAME_WIDTH;
|
||||
aes_class->frame_size = FRAME_SIZE;
|
||||
aes_class->frame_number = FRAME_NUMBER;
|
||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||
aes_class->init_reqs = init_reqs;
|
||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||
}
|
||||
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x08ff, .product = 0x5501 },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
struct fp_img_driver aes4000_driver = {
|
||||
.driver = {
|
||||
.id = AES4000_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "AuthenTec AES4000",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
|
||||
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
|
||||
|
||||
/* temporarily lowered until image quality improves */
|
||||
.bz3_threshold = 9,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = aes3k_dev_activate,
|
||||
.deactivate = aes3k_dev_deactivate,
|
||||
};
|
||||
|
||||
|
||||
@@ -24,151 +24,148 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "fpi-usb.h"
|
||||
#include "fpi-usb-transfer.h"
|
||||
#include "fpi-assembling.h"
|
||||
#include "aeslib.h"
|
||||
|
||||
#define MAX_REGWRITES_PER_REQUEST 16
|
||||
#define MAX_REGWRITES_PER_REQUEST 16
|
||||
|
||||
#define BULK_TIMEOUT 4000
|
||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||
#define BULK_TIMEOUT 4000
|
||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||
|
||||
struct write_regv_data {
|
||||
struct fp_img_dev *imgdev;
|
||||
unsigned int num_regs;
|
||||
const struct aes_regwrite *regs;
|
||||
unsigned int offset;
|
||||
aes_write_regv_cb callback;
|
||||
void *user_data;
|
||||
struct write_regv_data
|
||||
{
|
||||
unsigned int num_regs;
|
||||
const struct aes_regwrite *regs;
|
||||
unsigned int offset;
|
||||
aes_write_regv_cb callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void continue_write_regv(struct write_regv_data *wdata);
|
||||
static void continue_write_regv (FpImageDevice *dev,
|
||||
struct write_regv_data *wdata);
|
||||
|
||||
/* libusb bulk callback for regv write completion transfer. continues the
|
||||
* transaction */
|
||||
static void write_regv_trf_complete(struct libusb_transfer *transfer)
|
||||
static void
|
||||
write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct write_regv_data *wdata = transfer->user_data;
|
||||
struct write_regv_data *wdata = user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
|
||||
else
|
||||
continue_write_regv(wdata);
|
||||
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
if (error)
|
||||
{
|
||||
wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data);
|
||||
g_free (wdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue_write_regv (FP_IMAGE_DEVICE (device), wdata);
|
||||
}
|
||||
}
|
||||
|
||||
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
||||
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
|
||||
static void
|
||||
do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound)
|
||||
{
|
||||
unsigned int offset = wdata->offset;
|
||||
unsigned int num = upper_bound - offset + 1;
|
||||
size_t alloc_size = num * 2;
|
||||
unsigned char *data = g_malloc(alloc_size);
|
||||
unsigned int i;
|
||||
size_t data_offset = 0;
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
unsigned int offset = wdata->offset;
|
||||
unsigned int num = upper_bound - offset + 1;
|
||||
size_t alloc_size = num * 2;
|
||||
unsigned int i;
|
||||
size_t data_offset = 0;
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
|
||||
for (i = offset; i < offset + num; i++) {
|
||||
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
||||
data[data_offset++] = regwrite->reg;
|
||||
data[data_offset++] = regwrite->value;
|
||||
}
|
||||
fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size);
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev (FP_DEV(wdata->imgdev)), EP_OUT, data,
|
||||
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
for (i = offset; i < offset + num; i++)
|
||||
{
|
||||
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
||||
transfer->buffer[data_offset++] = regwrite->reg;
|
||||
transfer->buffer[data_offset++] = regwrite->value;
|
||||
}
|
||||
|
||||
return r;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
write_regv_trf_complete, wdata);
|
||||
}
|
||||
|
||||
/* write the next batch of registers to be written, or if there are no more,
|
||||
* indicate completion to the caller */
|
||||
static void continue_write_regv(struct write_regv_data *wdata)
|
||||
static void
|
||||
continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
|
||||
{
|
||||
unsigned int offset = wdata->offset;
|
||||
unsigned int regs_remaining;
|
||||
unsigned int limit;
|
||||
unsigned int upper_bound;
|
||||
int i;
|
||||
int r;
|
||||
unsigned int offset = wdata->offset;
|
||||
unsigned int regs_remaining;
|
||||
unsigned int limit;
|
||||
unsigned int upper_bound;
|
||||
int i;
|
||||
|
||||
/* skip all zeros and ensure there is still work to do */
|
||||
while (TRUE) {
|
||||
if (offset >= wdata->num_regs) {
|
||||
fp_dbg("all registers written");
|
||||
wdata->callback(wdata->imgdev, 0, wdata->user_data);
|
||||
return;
|
||||
}
|
||||
if (wdata->regs[offset].reg)
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
/* skip all zeros and ensure there is still work to do */
|
||||
while (TRUE)
|
||||
{
|
||||
if (offset >= wdata->num_regs)
|
||||
{
|
||||
fp_dbg ("all registers written");
|
||||
wdata->callback (dev, 0, wdata->user_data);
|
||||
g_free (wdata);
|
||||
return;
|
||||
}
|
||||
if (wdata->regs[offset].reg)
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
|
||||
wdata->offset = offset;
|
||||
regs_remaining = wdata->num_regs - offset;
|
||||
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
||||
upper_bound = offset + limit - 1;
|
||||
wdata->offset = offset;
|
||||
regs_remaining = wdata->num_regs - offset;
|
||||
limit = MIN (regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
||||
upper_bound = offset + limit - 1;
|
||||
|
||||
/* determine if we can write the entire of the regs at once, or if there
|
||||
* is a zero dividing things up */
|
||||
for (i = offset; i <= upper_bound; i++)
|
||||
if (!wdata->regs[i].reg) {
|
||||
upper_bound = i - 1;
|
||||
break;
|
||||
}
|
||||
/* determine if we can write the entire of the regs at once, or if there
|
||||
* is a zero dividing things up */
|
||||
for (i = offset; i <= upper_bound; i++)
|
||||
if (!wdata->regs[i].reg)
|
||||
{
|
||||
upper_bound = i - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
r = do_write_regv(wdata, upper_bound);
|
||||
if (r < 0) {
|
||||
wdata->callback(wdata->imgdev, r, wdata->user_data);
|
||||
return;
|
||||
}
|
||||
do_write_regv (dev, wdata, upper_bound);
|
||||
|
||||
wdata->offset = upper_bound + 1;
|
||||
wdata->offset = upper_bound + 1;
|
||||
}
|
||||
|
||||
/* write a load of registers to the device, combining multiple writes in a
|
||||
* single URB up to a limit. insert writes to non-existent register 0 to force
|
||||
* specific groups of writes to be separated by different URBs. */
|
||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
|
||||
void
|
||||
aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs,
|
||||
unsigned int num_regs, aes_write_regv_cb callback,
|
||||
void *user_data)
|
||||
{
|
||||
struct write_regv_data *wdata;
|
||||
struct write_regv_data *wdata;
|
||||
|
||||
fp_dbg("write %d regs", num_regs);
|
||||
wdata = g_malloc(sizeof(*wdata));
|
||||
wdata->imgdev = dev;
|
||||
wdata->num_regs = num_regs;
|
||||
wdata->regs = regs;
|
||||
wdata->offset = 0;
|
||||
wdata->callback = callback;
|
||||
wdata->user_data = user_data;
|
||||
continue_write_regv(wdata);
|
||||
|
||||
g_free(wdata);
|
||||
fp_dbg ("write %d regs", num_regs);
|
||||
wdata = g_malloc (sizeof (*wdata));
|
||||
wdata->num_regs = num_regs;
|
||||
wdata->regs = regs;
|
||||
wdata->offset = 0;
|
||||
wdata->callback = callback;
|
||||
wdata->user_data = user_data;
|
||||
continue_write_regv (dev, wdata);
|
||||
}
|
||||
|
||||
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned int x,
|
||||
unsigned int y)
|
||||
unsigned char
|
||||
aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned int x,
|
||||
unsigned int y)
|
||||
{
|
||||
unsigned char ret;
|
||||
unsigned char ret;
|
||||
|
||||
ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)];
|
||||
ret = y % 2 ? ret >> 4 : ret & 0xf;
|
||||
ret *= 17;
|
||||
ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)];
|
||||
ret = y % 2 ? ret >> 4 : ret & 0xf;
|
||||
ret *= 17;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -22,24 +22,28 @@
|
||||
|
||||
#include <fprint.h>
|
||||
|
||||
struct aes_regwrite {
|
||||
unsigned char reg;
|
||||
unsigned char value;
|
||||
struct aes_regwrite
|
||||
{
|
||||
unsigned char reg;
|
||||
unsigned char value;
|
||||
};
|
||||
|
||||
struct fpi_frame;
|
||||
struct fpi_frame_asmbl_ctx;
|
||||
|
||||
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
||||
void *user_data);
|
||||
typedef void (*aes_write_regv_cb)(FpImageDevice *dev,
|
||||
GError *error,
|
||||
void *user_data);
|
||||
|
||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
|
||||
void aes_write_regv (FpImageDevice *dev,
|
||||
const struct aes_regwrite *regs,
|
||||
unsigned int num_regs,
|
||||
aes_write_regv_cb callback,
|
||||
void *user_data);
|
||||
|
||||
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned int x,
|
||||
unsigned int y);
|
||||
unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned int x,
|
||||
unsigned int y);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __AESX660_H
|
||||
#define __AESX660_H
|
||||
#pragma once
|
||||
|
||||
#define AESX660_HEADER_SIZE 3
|
||||
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
|
||||
@@ -43,80 +42,70 @@
|
||||
|
||||
#define AESX660_FRAME_HEIGHT 8
|
||||
|
||||
struct aesX660_dev {
|
||||
GSList *strips;
|
||||
size_t strips_len;
|
||||
gboolean deactivating;
|
||||
struct aesX660_cmd *init_seq;
|
||||
size_t init_seq_len;
|
||||
unsigned int init_cmd_idx;
|
||||
unsigned int init_seq_idx;
|
||||
struct libusb_transfer *fd_data_transfer;
|
||||
unsigned char *buffer;
|
||||
size_t buffer_size;
|
||||
size_t buffer_max;
|
||||
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI,
|
||||
DEVICE_AES_X660, FpImageDevice)
|
||||
|
||||
/* Device-specific stuff */
|
||||
struct aesX660_cmd *init_seqs[2];
|
||||
size_t init_seqs_len[2];
|
||||
unsigned char *start_imaging_cmd;
|
||||
size_t start_imaging_cmd_len;
|
||||
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||
uint16_t extra_img_flags;
|
||||
#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ())
|
||||
|
||||
struct _FpiDeviceAesX660Class
|
||||
{
|
||||
FpImageDeviceClass parent;
|
||||
|
||||
struct aesX660_cmd *init_seqs[2];
|
||||
gsize init_seqs_len[2];
|
||||
guint8 *start_imaging_cmd;
|
||||
gsize start_imaging_cmd_len;
|
||||
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||
};
|
||||
|
||||
struct aesX660_cmd {
|
||||
const unsigned char *cmd;
|
||||
size_t len;
|
||||
struct aesX660_cmd
|
||||
{
|
||||
const guint8 *cmd;
|
||||
gsize len;
|
||||
};
|
||||
|
||||
/* 0x77 cmd seems to control LED, this sequence
|
||||
* makes LED blink
|
||||
*/
|
||||
static const unsigned char led_blink_cmd[] = {
|
||||
0x77, 0x18, 0x00,
|
||||
0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
|
||||
0x01, 0x00, 0x7f
|
||||
static const guint8 led_blink_cmd[] = {
|
||||
0x77, 0x18, 0x00,
|
||||
0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
|
||||
0x01, 0x00, 0x7f
|
||||
};
|
||||
|
||||
/* This sequence makes LED light solid
|
||||
*/
|
||||
static const unsigned char led_solid_cmd[] = {
|
||||
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f
|
||||
static const guint8 led_solid_cmd[] = {
|
||||
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f
|
||||
};
|
||||
|
||||
static const unsigned char wait_for_finger_cmd[] = {
|
||||
0x20,
|
||||
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
||||
static const guint8 wait_for_finger_cmd[] = {
|
||||
0x20,
|
||||
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
||||
};
|
||||
|
||||
/* 0x40 cmd response
|
||||
*
|
||||
static const unsigned char pkt1371[] = {
|
||||
0x40, 0x01, 0x00, 0x01
|
||||
};
|
||||
*/
|
||||
static const guint8 pkt1371[] = {
|
||||
0x40, 0x01, 0x00, 0x01
|
||||
};
|
||||
*/
|
||||
|
||||
static const unsigned char set_idle_cmd[] = {
|
||||
0x0d, /* Reset or "set idle"? */
|
||||
static const guint8 set_idle_cmd[] = {
|
||||
0x0d, /* Reset or "set idle"? */
|
||||
};
|
||||
|
||||
static const unsigned char read_id_cmd[] = {
|
||||
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
|
||||
0x07, /* Read ID? */
|
||||
static const guint8 read_id_cmd[] = {
|
||||
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
|
||||
0x07, /* Read ID? */
|
||||
};
|
||||
|
||||
static const unsigned char calibrate_cmd[] = {
|
||||
0x44, 0x02, 0x00, 0x04, 0x00,
|
||||
0x06,
|
||||
static const guint8 calibrate_cmd[] = {
|
||||
0x44, 0x02, 0x00, 0x04, 0x00,
|
||||
0x06,
|
||||
};
|
||||
|
||||
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
void aesX660_dev_deactivate(struct fp_img_dev *dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,29 +21,27 @@
|
||||
#define __DRIVER_IDS
|
||||
|
||||
enum {
|
||||
UPEKTS_ID = 1,
|
||||
URU4000_ID = 2,
|
||||
AES4000_ID = 3,
|
||||
AES2501_ID = 4,
|
||||
UPEKTC_ID = 5,
|
||||
AES1610_ID = 6,
|
||||
FDU2000_ID = 7,
|
||||
VCOM5S_ID = 8,
|
||||
UPEKSONLY_ID = 9,
|
||||
VFS101_ID = 10,
|
||||
VFS301_ID = 11,
|
||||
AES2550_ID = 12,
|
||||
/* UPEKE2_ID = 13 */
|
||||
AES1660_ID = 14,
|
||||
AES2660_ID = 15,
|
||||
AES3500_ID = 16,
|
||||
UPEKTC_IMG_ID = 17,
|
||||
ETES603_ID = 18,
|
||||
VFS5011_ID = 19,
|
||||
VFS0050_ID = 20,
|
||||
ELAN_ID = 21,
|
||||
VIRTUAL_IMG_ID = 22,
|
||||
VIRTUAL_MIS_ID = 23,
|
||||
UPEKTS_ID = 1,
|
||||
URU4000_ID = 2,
|
||||
AES4000_ID = 3,
|
||||
AES2501_ID = 4,
|
||||
UPEKTC_ID = 5,
|
||||
AES1610_ID = 6,
|
||||
/* FDU2000_ID = 7, */
|
||||
VCOM5S_ID = 8,
|
||||
UPEKSONLY_ID = 9,
|
||||
VFS101_ID = 10,
|
||||
VFS301_ID = 11,
|
||||
AES2550_ID = 12,
|
||||
/* UPEKE2_ID = 13 */
|
||||
AES1660_ID = 14,
|
||||
AES2660_ID = 15,
|
||||
AES3500_ID = 16,
|
||||
UPEKTC_IMG_ID = 17,
|
||||
ETES603_ID = 18,
|
||||
VFS5011_ID = 19,
|
||||
VFS0050_ID = 20,
|
||||
ELAN_ID = 21,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
||||
#ifndef __ELAN_H
|
||||
#define __ELAN_H
|
||||
|
||||
#include <libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#define ELAN_VEND_ID 0x04f3
|
||||
|
||||
@@ -59,9 +59,9 @@
|
||||
#define ELAN_SKIP_LAST_FRAMES 2
|
||||
|
||||
#define ELAN_CMD_LEN 0x2
|
||||
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
||||
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
||||
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
||||
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
|
||||
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
|
||||
#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN)
|
||||
|
||||
/* used as response length to tell the driver to skip reading response */
|
||||
#define ELAN_CMD_SKIP_READ 0
|
||||
@@ -71,154 +71,158 @@
|
||||
#define ELAN_CMD_TIMEOUT 10000
|
||||
#define ELAN_FINGER_TIMEOUT 200
|
||||
|
||||
struct elan_cmd {
|
||||
unsigned char cmd[ELAN_CMD_LEN];
|
||||
int response_len;
|
||||
int response_in;
|
||||
unsigned short devices;
|
||||
struct elan_cmd
|
||||
{
|
||||
unsigned char cmd[ELAN_CMD_LEN];
|
||||
int response_len;
|
||||
int response_in;
|
||||
unsigned short devices;
|
||||
gboolean never_cancel;
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_sensor_dim_cmd = {
|
||||
.cmd = {0x00, 0x0c},
|
||||
.response_len = 0x4,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x00, 0x0c},
|
||||
.response_len = 0x4,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_fw_ver_cmd = {
|
||||
.cmd = {0x40, 0x19},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x19},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* unknown, returns 0x0 0x1 on 0907 */
|
||||
static const struct elan_cmd activate_cmd_1 = {
|
||||
.cmd = {0x40, 0x2a},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_0907,
|
||||
.cmd = {0x40, 0x2a},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_0907,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_image_cmd = {
|
||||
.cmd = {0x00, 0x09},
|
||||
/* raw frame sizes are calculated from image dimensions reported by the
|
||||
* device */
|
||||
.response_len = -1,
|
||||
.response_in = ELAN_EP_IMG_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x00, 0x09},
|
||||
/* raw frame sizes are calculated from image dimensions reported by the
|
||||
* device */
|
||||
.response_len = -1,
|
||||
.response_in = ELAN_EP_IMG_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd read_sensor_status_cmd = {
|
||||
.cmd = {0x40, 0x13},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x13},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_calib_status_cmd = {
|
||||
.cmd = {0x40, 0x23},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x23},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_calib_mean_cmd = {
|
||||
.cmd = {0x40, 0x24},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x24},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd led_on_cmd = {
|
||||
.cmd = {0x40, 0x31},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x31},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* wait for finger
|
||||
* subsequent read will not complete until finger is placed on the reader */
|
||||
static const struct elan_cmd pre_scan_cmd = {
|
||||
.cmd = {0x40, 0x3f},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x40, 0x3f},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* led off, stop waiting for finger */
|
||||
static const struct elan_cmd stop_cmd = {
|
||||
.cmd = {0x00, 0x0b},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.cmd = {0x00, 0x0b},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
.never_cancel = TRUE,
|
||||
};
|
||||
|
||||
static const struct usb_id elan_id_table[] = {
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42},
|
||||
{0, 0, 0,},
|
||||
static const FpIdEntry elan_id_table[] = {
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||
};
|
||||
|
||||
static void elan_cmd_done(fpi_ssm *ssm);
|
||||
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||
static void elan_cmd_done (FpiSsm *ssm);
|
||||
static void elan_cmd_read (FpiSsm *ssm,
|
||||
FpDevice *dev);
|
||||
|
||||
static void elan_calibrate(struct fp_img_dev *dev);
|
||||
static void elan_capture(struct fp_img_dev *dev);
|
||||
static void elan_deactivate(struct fp_img_dev *dev);
|
||||
static void elan_calibrate (FpDevice *dev);
|
||||
static void elan_capture (FpDevice *dev);
|
||||
|
||||
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
static void dev_change_state (FpImageDevice *dev,
|
||||
FpImageDeviceState state);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* Secugen FDU2000 driver for libfprint
|
||||
* Copyright (C) 2007 Gustavo Chain <g@0xff.cl>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "fdu2000"
|
||||
|
||||
#include "drivers_api.h"
|
||||
|
||||
#ifndef HAVE_MEMMEM
|
||||
gpointer
|
||||
memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
|
||||
const gchar *begin;
|
||||
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
|
||||
|
||||
/* The first occurrence of the empty string is deemed to occur at
|
||||
* the beginning of the string. */
|
||||
if (needle_len == 0)
|
||||
return (void *) haystack;
|
||||
|
||||
/* Sanity check, otherwise the loop might search through the whole
|
||||
* memory. */
|
||||
if (haystack_len < needle_len)
|
||||
return NULL;
|
||||
|
||||
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
|
||||
if (begin[0] == ((const char *) needle)[0] &&
|
||||
!memcmp((const void *) &begin[1],
|
||||
(const void *) ((const char *) needle + 1),
|
||||
needle_len - 1))
|
||||
return (void *) begin;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_MEMMEM */
|
||||
|
||||
#define EP_IMAGE ( 0x02 | LIBUSB_ENDPOINT_IN )
|
||||
#define EP_REPLY ( 0x01 | LIBUSB_ENDPOINT_IN )
|
||||
#define EP_CMD ( 0x01 | LIBUSB_ENDPOINT_OUT )
|
||||
#define BULK_TIMEOUT 200
|
||||
|
||||
/* fdu_req[] index */
|
||||
typedef enum {
|
||||
CAPTURE_READY,
|
||||
CAPTURE_READ,
|
||||
CAPTURE_END,
|
||||
LED_OFF,
|
||||
LED_ON
|
||||
} req_index;
|
||||
|
||||
|
||||
#define CMD_LEN 2
|
||||
#define ACK_LEN 8
|
||||
static const struct fdu2000_req {
|
||||
const gchar cmd[CMD_LEN]; // Command to send
|
||||
const gchar ack[ACK_LEN]; // Expected ACK
|
||||
const guint ack_len; // ACK has variable length
|
||||
} fdu_req[] = {
|
||||
/* Capture */
|
||||
{
|
||||
.cmd = { 0x00, 0x04 },
|
||||
.ack = { 0x00, 0x04, 0x01, 0x01 },
|
||||
.ack_len = 4
|
||||
},
|
||||
|
||||
{
|
||||
.cmd = { 0x00, 0x01 },
|
||||
.ack = { 0x00, 0x01, 0x01, 0x01 },
|
||||
.ack_len = 4
|
||||
},
|
||||
|
||||
{
|
||||
.cmd = { 0x00, 0x05 },
|
||||
.ack = { 0x00, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
|
||||
.ack_len = 8
|
||||
},
|
||||
|
||||
/* Led */
|
||||
{
|
||||
.cmd = { 0x05, 0x00 },
|
||||
.ack = {},
|
||||
.ack_len = 0
|
||||
},
|
||||
|
||||
{
|
||||
.cmd = { 0x05, 0x01 },
|
||||
.ack = {},
|
||||
.ack_len = 0
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Write a command and verify reponse
|
||||
*/
|
||||
static gint
|
||||
bulk_write_safe(libusb_dev_handle *dev, req_index rIndex) {
|
||||
|
||||
gchar reponse[ACK_LEN];
|
||||
gint r;
|
||||
gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
|
||||
gchar *ack = (gchar *)fdu_req[rIndex].ack;
|
||||
gint ack_len = fdu_req[rIndex].ack_len;
|
||||
struct libusb_bulk_transfer wrmsg = {
|
||||
.endpoint = EP_CMD,
|
||||
.data = cmd,
|
||||
.length = sizeof(cmd),
|
||||
};
|
||||
struct libusb_bulk_transfer readmsg = {
|
||||
.endpoint = EP_REPLY,
|
||||
.data = reponse,
|
||||
.length = sizeof(reponse),
|
||||
};
|
||||
int trf;
|
||||
|
||||
r = libusb_bulk_transfer(dev, &wrmsg, &trf, BULK_TIMEOUT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ack_len == 0)
|
||||
return 0;
|
||||
|
||||
/* Check reply from FP */
|
||||
r = libusb_bulk_transfer(dev, &readmsg, &trf, BULK_TIMEOUT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strncmp(ack, reponse, ack_len))
|
||||
return 0;
|
||||
|
||||
fp_err("Expected different ACK from dev");
|
||||
return 1; /* Error */
|
||||
}
|
||||
|
||||
static gint
|
||||
capture(struct fp_img_dev *dev, gboolean unconditional,
|
||||
struct fp_img **ret)
|
||||
{
|
||||
#define RAW_IMAGE_WIDTH 398
|
||||
#define RAW_IMAGE_HEIGTH 301
|
||||
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
|
||||
|
||||
struct fp_img *img = NULL;
|
||||
int bytes, r;
|
||||
const gchar SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
|
||||
const gchar SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 }; // Start of line + { L L } (L: Line num) (8 nibbles)
|
||||
gchar *buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
|
||||
gchar *image;
|
||||
gchar *p;
|
||||
guint offset;
|
||||
struct libusb_bulk_transfer msg = {
|
||||
.endpoint = EP_IMAGE,
|
||||
.data = buffer,
|
||||
.length = RAW_IMAGE_SIZE * 6,
|
||||
};
|
||||
|
||||
image = g_malloc0(RAW_IMAGE_SIZE);
|
||||
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_ON))) {
|
||||
fp_err("Command: LED_ON");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READY))) {
|
||||
fp_err("Command: CAPTURE_READY");
|
||||
goto out;
|
||||
}
|
||||
|
||||
read:
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READ))) {
|
||||
fp_err("Command: CAPTURE_READ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now we are ready to read from dev */
|
||||
|
||||
r = libusb_bulk_transfer(fpi_dev_get_usb_dev(FP_DEV(dev)), &msg, &bytes, BULK_TIMEOUT * 10);
|
||||
if (r < 0 || bytes < 1)
|
||||
goto read;
|
||||
|
||||
/*
|
||||
* Find SOF (start of line)
|
||||
*/
|
||||
p = memmem(buffer, RAW_IMAGE_SIZE * 6,
|
||||
(const gpointer)SOF, sizeof SOF);
|
||||
fp_dbg("Read %d byte/s from dev", bytes);
|
||||
if (!p)
|
||||
goto out;
|
||||
|
||||
p += sizeof SOF;
|
||||
|
||||
int i = 0;
|
||||
bytes = 0;
|
||||
while(p) {
|
||||
if ( i >= RAW_IMAGE_HEIGTH )
|
||||
break;
|
||||
|
||||
offset = p - buffer;
|
||||
p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
|
||||
(const gpointer)SOL, sizeof SOL);
|
||||
if (p) {
|
||||
p += sizeof SOL + 4;
|
||||
int j;
|
||||
for (j = 0; j < RAW_IMAGE_WIDTH; j++) {
|
||||
/*
|
||||
* Convert from 4 to 8 bits
|
||||
* The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1
|
||||
*/
|
||||
*(image + bytes + j) = *(p + (j * 2) + 0) << 4 & 0xf0;
|
||||
*(image + bytes + j) |= *(p + (j * 2) + 1) & 0x0f;
|
||||
}
|
||||
p += RAW_IMAGE_WIDTH * 2;
|
||||
bytes += RAW_IMAGE_WIDTH;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) {
|
||||
fp_err("Command: CAPTURE_END");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
|
||||
fp_err("Command: LED_OFF");
|
||||
goto out;
|
||||
}
|
||||
|
||||
img = fpi_img_new_for_imgdev(dev);
|
||||
memcpy(img->data, image, RAW_IMAGE_SIZE);
|
||||
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
||||
*ret = img;
|
||||
|
||||
out:
|
||||
g_free(buffer);
|
||||
g_free(image);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static
|
||||
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
gint r;
|
||||
//if ( (r = usb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
|
||||
// goto out;
|
||||
|
||||
if ( (r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0)) < 0 ) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
//if ( (r = usb_set_altinterface(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
|
||||
// goto out;
|
||||
|
||||
//if ( (r = usb_clear_halt(fpi_dev_get_usb_dev(FP_DEV(dev)), EP_CMD)) < 0 )
|
||||
// goto out;
|
||||
|
||||
/* Make sure sensor mode is not capture_{ready|read} */
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) {
|
||||
fp_err("Command: CAPTURE_END");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
|
||||
fp_err("Command: LED_OFF");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
fp_err("could not init dev");
|
||||
return r;
|
||||
}
|
||||
|
||||
static
|
||||
void dev_exit(struct fp_img_dev *dev)
|
||||
{
|
||||
if (bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))
|
||||
fp_err("Command: CAPTURE_END");
|
||||
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x1162, .product = 0x0300 },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
struct fp_img_driver fdu2000_driver = {
|
||||
.driver = {
|
||||
.id = FDU2000_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "Secugen FDU 2000",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.img_height = RAW_IMAGE_HEIGTH,
|
||||
.img_width = RAW_IMAGE_WIDTH,
|
||||
.bz3_threshold = 23,
|
||||
|
||||
.init = dev_init,
|
||||
.exit = dev_exit,
|
||||
.capture = capture,
|
||||
};
|
||||
232
libfprint/drivers/synaptics/bmkt.h
Normal file
232
libfprint/drivers/synaptics/bmkt.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Synaptics MiS Fingerprint Sensor Interface
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _BMKT_H_
|
||||
#define _BMKT_H_
|
||||
|
||||
/**< User ID maximum length allowed */
|
||||
#define BMKT_MAX_USER_ID_LEN 100
|
||||
/**< Software Part Number length */
|
||||
#define BMKT_PART_NUM_LEN 10
|
||||
/**< Software supplier identification length */
|
||||
#define BMKT_SUPPLIER_ID_LEN 2
|
||||
|
||||
/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */
|
||||
#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bmkt_response.h"
|
||||
|
||||
/*!
|
||||
*******************************************************************************
|
||||
** Type definition for result
|
||||
*/
|
||||
/** No error; Operation successfully completed. */
|
||||
#define BMKT_SUCCESS 0
|
||||
/** Fingerprint system not initialized */
|
||||
#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101
|
||||
/** Fingerprint system busy performing another operation */
|
||||
#define BMKT_FP_SYSTEM_BUSY 102
|
||||
/** Operation not allowed */
|
||||
#define BMKT_OPERATION_DENIED 103
|
||||
/** System ran out of memory while performing operation */
|
||||
#define BMKT_OUT_OF_MEMORY 104
|
||||
/** Corrupt message, CRC check fail or truncated message */
|
||||
#define BMKT_CORRUPT_MESSAGE 110
|
||||
/** One of the command parameters is outside the range of valid values */
|
||||
#define BMKT_INVALID_PARAM 111
|
||||
/** Unrecognized message or message with invalid message ID */
|
||||
#define BMKT_UNRECOGNIZED_MESSAGE 112
|
||||
/** Operation time out */
|
||||
#define BMKT_OP_TIME_OUT 113
|
||||
/** General error – cause of error cannot be determined */
|
||||
#define BMKT_GENERAL_ERROR 114
|
||||
|
||||
#define BMKT_SET_SECURITY_LEVEL_FAIL 120
|
||||
#define BMKT_GET_SECURITY_LEVEL_FAIL 121
|
||||
|
||||
/** Fingerprint sensor reset while operation was being performed */
|
||||
#define BMKT_SENSOR_RESET 201
|
||||
/** Fingerprint sensor malfunctioned */
|
||||
#define BMKT_SENSOR_MALFUNCTION 202
|
||||
/** Fingerprint sensor cannot be accessed despite repeated attempts */
|
||||
#define BMKT_SENSOR_TAMPERED 203
|
||||
/**
|
||||
* BMKT_SENSOR_NOT_INIT:
|
||||
* Fingerprint sensor module not initialized yet – not ready for use
|
||||
* (different from error code 101 which indicates that the entire system
|
||||
* has not been initialized)
|
||||
*/
|
||||
#define BMKT_SENSOR_NOT_INIT 204
|
||||
/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */
|
||||
#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205
|
||||
/**
|
||||
* BMKT_SENSOR_STIMULUS_ERROR:
|
||||
* There is a finger or debris on the sensor that needs to be removed
|
||||
* before issuing this command
|
||||
*/
|
||||
#define BMKT_SENSOR_STIMULUS_ERROR 213
|
||||
/**
|
||||
* BMKT_CORRUPT_TEMPLATE_DATA:
|
||||
* One of the fingerprint templates stored on flash is corrupt.
|
||||
* This error code is returned in case of failure in finding a fingerprint match
|
||||
* during identify or verify operations while also detecting that one or more
|
||||
* fingerprint templates stored on the flash has become corrupted
|
||||
*/
|
||||
#define BMKT_CORRUPT_TEMPLATE_DATA 300
|
||||
/** Failed to extract features from fingerprint image acquired by sensor */
|
||||
#define BMKT_FEATURE_EXTRACT_FAIL 301
|
||||
/** Failed to generate fingerprint template */
|
||||
#define BMKT_ENROLL_FAIL 302
|
||||
/** Specified finger already enrolled for this user */
|
||||
#define BMKT_ENROLLMENT_EXISTS 303
|
||||
/** Invalid fingerprint image */
|
||||
#define BMKT_INVALID_FP_IMAGE 304
|
||||
/** No matching user fingerprint template found in database */
|
||||
#define BMKT_FP_NO_MATCH 404
|
||||
/** Fingerprint database is full */
|
||||
#define BMKT_FP_DATABASE_FULL 501
|
||||
/** Fingerprint database is empty */
|
||||
#define BMKT_FP_DATABASE_EMPTY 502
|
||||
/** Cannot access fingerprint database */
|
||||
#define BMKT_FP_DATABASE_ACCESS_FAIL 503
|
||||
/** Fingerprint template record does not exist */
|
||||
#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504
|
||||
/** Failed to read/write system parameters stored on flash */
|
||||
#define BMKT_FP_PARAM_ACCESS_FAIL 505
|
||||
/** Fingerprint is a spoof */
|
||||
#define BMKT_FP_SPOOF_ALERT 801
|
||||
/** Anti-spoof module failure */
|
||||
#define BMKT_ANTI_SPOOF_MODULE_FAIL 802
|
||||
|
||||
#define BMKT_CORRUPT_UPDATE_IMAGE 901
|
||||
#define BMKT_SYSTEM_UPDATE_FAIL 902
|
||||
|
||||
#define BMKT_EVENT_NOT_SET 1000
|
||||
#define BMKT_SENSOR_NOT_READY 1001
|
||||
#define BMKT_TIMEOUT 1002
|
||||
#define BMKT_SENSOR_RESPONSE_PENDING 1003
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* bmkt_mode:
|
||||
* Fingerprint system operational mode values level 1
|
||||
*/
|
||||
typedef enum bmkt_mode {
|
||||
BMKT_STATE_UNINIT = 0xFF,
|
||||
BMKT_STATE_IDLE = 0x00,
|
||||
BMKT_STATE_ENROLL = 0x10,
|
||||
BMKT_STATE_IDENTIFY = 0x20,
|
||||
BMKT_STATE_VERIFY = 0x30,
|
||||
BMKT_STATE_DB_OPS = 0x40,
|
||||
BMKT_STATE_SYS_TEST = 0x50,
|
||||
BMKT_STATE_SYS_OPS = 0x60,
|
||||
} bmkt_mode_t;
|
||||
|
||||
/**
|
||||
* bmkt_mode_level2:
|
||||
* Fingerprint system operational mode values level 2
|
||||
*/
|
||||
typedef enum bmkt_mode_level2 {
|
||||
BMKT_STATE_L2_IDLE = 0x00,
|
||||
BMKT_STATE_L2_STARTING = 0x11,
|
||||
BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12,
|
||||
BMKT_STATE_L2_CAPTURE_IMAGE = 0x13,
|
||||
BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14,
|
||||
BMKT_STATE_L2_EXTRACT_FEATURE = 0x15,
|
||||
BMKT_STATE_L2_CREATE_TEMPLATE = 0x16,
|
||||
BMKT_STATE_L2_READING_FROM_FLASH = 0x17,
|
||||
BMKT_STATE_L2_WRITING_TO_FLASH = 0x18,
|
||||
BMKT_STATE_L2_FINISHING = 0x19,
|
||||
BMKT_STATE_L2_CANCELING_OP = 0x20,
|
||||
BMKT_STATE_L2_MATCHING = 0x21,
|
||||
BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22,
|
||||
BMKT_STATE_L2_READY_POWER_DOWN = 0xF0,
|
||||
} bmkt_mode_level2_t;
|
||||
|
||||
/**
|
||||
* bmkt_transport_type:
|
||||
* Fingerprint system transport types
|
||||
*/
|
||||
typedef enum bmkt_transport_type {
|
||||
BMKT_TRANSPORT_TYPE_USB = 0,
|
||||
} bmkt_transport_type_t;
|
||||
|
||||
/**
|
||||
* bmkt_usb_config:
|
||||
* Structure represcontainingenting USB configuration details
|
||||
*/
|
||||
typedef struct bmkt_usb_config
|
||||
{
|
||||
int product_id; /**< USB device product ID */
|
||||
} bmkt_usb_config_t;
|
||||
|
||||
/**
|
||||
* bmkt_transport_config_t:
|
||||
* Union containing transport configuration details
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
bmkt_usb_config_t usb_config;
|
||||
} bmkt_transport_config_t;
|
||||
|
||||
/**
|
||||
* bmkt_sensor_desc_t:
|
||||
* Structure containing fingerprint system description
|
||||
*/
|
||||
typedef struct bmkt_sensor_desc
|
||||
{
|
||||
int product_id;
|
||||
int flags;
|
||||
} bmkt_sensor_desc_t;
|
||||
|
||||
/**
|
||||
* bmkt_finger_state_t:
|
||||
* Finger state representation values.
|
||||
*/
|
||||
typedef enum {
|
||||
BMKT_FINGER_STATE_UNKNOWN = 0,
|
||||
BMKT_FINGER_STATE_ON_SENSOR,
|
||||
BMKT_FINGER_STATE_NOT_ON_SENSOR,
|
||||
} bmkt_finger_state_t;
|
||||
|
||||
/**
|
||||
* bmkt_finger_event_t:
|
||||
* Structure containing finger state
|
||||
*/
|
||||
typedef struct bmkt_finger_event
|
||||
{
|
||||
bmkt_finger_state_t finger_state;
|
||||
} bmkt_finger_event_t;
|
||||
|
||||
typedef struct bmkt_user_id
|
||||
{
|
||||
uint8_t user_id_len;
|
||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN];
|
||||
} bmkt_user_id_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BMKT_H_ */
|
||||
400
libfprint/drivers/synaptics/bmkt_message.c
Normal file
400
libfprint/drivers/synaptics/bmkt_message.c
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include "bmkt_response.h"
|
||||
#include "bmkt_message.h"
|
||||
|
||||
static uint8_t
|
||||
extract8 (const uint8_t *buf, int *offset)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
int off = 0;
|
||||
|
||||
if (offset)
|
||||
off = *offset;
|
||||
|
||||
ret = *(buf + off);
|
||||
|
||||
if (offset)
|
||||
*offset += 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
if (msg_resp->payload_len != 2)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
|
||||
|
||||
if (msg_resp->payload_len != 1)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
init_resp->finger_presence = extract8 (msg_resp->payload, NULL);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
int offset = 0;
|
||||
bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp;
|
||||
|
||||
if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t))
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
fps_mode_resp->mode = extract8 (msg_resp->payload, &offset);
|
||||
fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset);
|
||||
fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset);
|
||||
fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
||||
|
||||
if (msg_resp->payload_len != 1)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
enroll_resp->progress = extract8 (msg_resp->payload, NULL);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
||||
|
||||
if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1))
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
enroll_resp->finger_id = msg_resp->payload[0];
|
||||
memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_identify_resp_t *id_resp = &resp->response.id_resp;
|
||||
|
||||
if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3))
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1];
|
||||
id_resp->finger_id = msg_resp->payload[2];
|
||||
memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp;
|
||||
|
||||
if (msg_resp->payload_len != 1)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp;
|
||||
|
||||
if (msg_resp->payload_len != 1)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
del_all_users_resp->progress = extract8 (msg_resp->payload, NULL);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp;
|
||||
int offset = 0;
|
||||
|
||||
if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
db_cap_resp->total = extract8 (msg_resp->payload, &offset);
|
||||
db_cap_resp->empty = extract8 (msg_resp->payload, &offset);
|
||||
|
||||
if (msg_resp->payload_len == 4)
|
||||
{
|
||||
db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset);
|
||||
db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset);
|
||||
}
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
int offset = 0;
|
||||
int i = 0;
|
||||
|
||||
if (msg_resp->payload_len < 2)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
/* 2 bytes per finger so calculate the total number of fingers to process*/
|
||||
int num_fingers = (msg_resp->payload_len) / 2;
|
||||
|
||||
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
|
||||
|
||||
for (i = 0; i < num_fingers; i++)
|
||||
{
|
||||
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
|
||||
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
|
||||
|
||||
}
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
static int
|
||||
parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
int offset = 0;
|
||||
int i = 0;
|
||||
|
||||
/* the payload is 2 bytes + template data */
|
||||
if (msg_resp->payload_len < 2)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
|
||||
|
||||
get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset);
|
||||
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
||||
|
||||
int n = 0;
|
||||
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
||||
{
|
||||
if (offset >= msg_resp->payload_len)
|
||||
break;
|
||||
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
|
||||
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
|
||||
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
|
||||
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
|
||||
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
|
||||
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
|
||||
}
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp;
|
||||
int offset = 0;
|
||||
|
||||
if (msg_resp->payload_len != 15)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
|
||||
offset += BMKT_PART_NUM_LEN;
|
||||
get_version_resp->year = extract8 (msg_resp->payload, &offset);
|
||||
get_version_resp->week = extract8 (msg_resp->payload, &offset);
|
||||
get_version_resp->patch = extract8 (msg_resp->payload, &offset);
|
||||
memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
|
||||
uint8_t payload_size, const uint8_t *payload)
|
||||
{
|
||||
int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size;
|
||||
|
||||
if (*cmd_len < message_len)
|
||||
return BMKT_OUT_OF_MEMORY;
|
||||
|
||||
cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID;
|
||||
cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num;
|
||||
cmd[BMKT_MESSAGE_ID_FIELD] = msg_id;
|
||||
cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size;
|
||||
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
|
||||
|
||||
*cmd_len = message_len;
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
|
||||
{
|
||||
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
|
||||
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
|
||||
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
|
||||
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
|
||||
if (msg_resp->payload_len > 0)
|
||||
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
|
||||
else
|
||||
msg_resp->payload = NULL;
|
||||
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||
{
|
||||
int ret = BMKT_SUCCESS;
|
||||
|
||||
memset (resp, 0, sizeof (bmkt_response_t));
|
||||
|
||||
resp->response_id = msg_resp->msg_id;
|
||||
|
||||
switch(msg_resp->msg_id)
|
||||
{
|
||||
case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL:
|
||||
case BMKT_RSP_SENSOR_MODULE_TEST_FAIL:
|
||||
case BMKT_RSP_FPS_INIT_FAIL:
|
||||
case BMKT_RSP_FPS_MODE_FAIL:
|
||||
case BMKT_RSP_SET_SECURITY_LEVEL_FAIL:
|
||||
case BMKT_RSP_GET_SECURITY_LEVEL_FAIL:
|
||||
case BMKT_RSP_CANCEL_OP_FAIL:
|
||||
case BMKT_RSP_ENROLL_FAIL:
|
||||
case BMKT_RSP_ID_FAIL:
|
||||
case BMKT_RSP_VERIFY_FAIL:
|
||||
case BMKT_RSP_QUERY_FAIL:
|
||||
case BMKT_RSP_DEL_USER_FP_FAIL:
|
||||
case BMKT_RSP_DEL_FULL_DB_FAIL:
|
||||
case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
||||
case BMKT_RSP_POWER_DOWN_FAIL:
|
||||
case BMKT_RSP_GET_VERSION_FAIL:
|
||||
case BMKT_RSP_DISABLE_PAIRING_FAIL:
|
||||
case BMKT_RSP_QUERY_PAIRING_FAIL:
|
||||
case BMKT_RSP_SENSOR_STATUS_FAIL:
|
||||
case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
||||
ret = parse_error_response (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_FPS_INIT_OK:
|
||||
ret = parse_init_ok (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_CANCEL_OP_OK:
|
||||
case BMKT_RSP_DEL_FULL_DB_OK:
|
||||
case BMKT_RSP_DEL_USER_FP_OK:
|
||||
/* responses with a payload of 0
|
||||
so the response indicates success */
|
||||
resp->result = BMKT_SUCCESS;
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_FPS_MODE_REPORT:
|
||||
// parse_fps_mode
|
||||
ret = parse_fps_mode_report (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
||||
case BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
||||
/* parse security level result */
|
||||
ret = parse_security_level_report (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_DELETE_PROGRESS:
|
||||
ret = parse_del_all_users_progress_report (msg_resp, resp);
|
||||
break;
|
||||
|
||||
case BMKT_RSP_CAPTURE_COMPLETE:
|
||||
resp->result = BMKT_SUCCESS;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_ENROLL_READY:
|
||||
resp->result = BMKT_SUCCESS;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_ENROLL_REPORT:
|
||||
ret = parse_enroll_report (msg_resp, resp);
|
||||
break;
|
||||
|
||||
case BMKT_RSP_ENROLL_OK:
|
||||
resp->complete = 1;
|
||||
ret = parse_enroll_ok (msg_resp, resp);
|
||||
break;
|
||||
|
||||
case BMKT_RSP_ID_OK:
|
||||
case BMKT_RSP_VERIFY_OK:
|
||||
ret = parse_auth_ok (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
||||
ret = parse_get_enrolled_fingers_report (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
||||
resp->complete = 1;
|
||||
ret = parse_db_cap_report (msg_resp, resp);
|
||||
break;
|
||||
|
||||
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
||||
ret = parse_get_enrolled_users_report (msg_resp, resp);
|
||||
break;
|
||||
|
||||
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_VERSION_INFO:
|
||||
ret = parse_get_version_report (msg_resp, resp);
|
||||
resp->complete = 1;
|
||||
break;
|
||||
|
||||
case BMKT_RSP_POWER_DOWN_READY:
|
||||
resp->complete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
93
libfprint/drivers/synaptics/bmkt_message.h
Normal file
93
libfprint/drivers/synaptics/bmkt_message.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BMKT_MESSAGE_H_
|
||||
#define BMKT_MESSAGE_H_
|
||||
|
||||
|
||||
#define BMKT_MESSAGE_HEADER_ID 0xFE
|
||||
#define BMKT_MESSAGE_HEADER_LEN (4)
|
||||
#define BMKT_MESSAGE_CRC32_LEN (4)
|
||||
#define BMKT_MESSAGE_HEADER_ID_FIELD 0
|
||||
#define BMKT_MESSAGE_SEQ_NUM_FIELD 1
|
||||
#define BMKT_MESSAGE_ID_FIELD 2
|
||||
#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3
|
||||
#define BMKT_MESSAGE_PAYLOAD_FIELD 4
|
||||
|
||||
// Command messages
|
||||
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01
|
||||
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04
|
||||
#define BMKT_CMD_SENSOR_MODULE_TEST 0x06
|
||||
#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08
|
||||
#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B
|
||||
#define BMKT_CMD_FPS_INIT 0x11
|
||||
#define BMKT_CMD_GET_FPS_MODE 0x21
|
||||
#define BMKT_CMD_SET_SECURITY_LEVEL 0x31
|
||||
#define BMKT_CMD_GET_SECURITY_LEVEL 0x34
|
||||
#define BMKT_CMD_CANCEL_OP 0x41
|
||||
#define BMKT_CMD_ENROLL_USER 0x51
|
||||
#define BMKT_CMD_ENROLL_PAUSE 0x52
|
||||
#define BMKT_CMD_ENROLL_RESUME 0x53
|
||||
#define BMKT_CMD_ID_USER 0x61
|
||||
#define BMKT_CMD_VERIFY_USER 0x65
|
||||
#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71
|
||||
#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72
|
||||
#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73
|
||||
#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74
|
||||
#define BMKT_CMD_DEL_USER_FP 0x81
|
||||
#define BMKT_CMD_DEL_FULL_DB 0x84
|
||||
#define BMKT_CMD_REPEAT_LAST_RSP 0x92
|
||||
#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1
|
||||
#define BMKT_CMD_GET_VERSION 0xB1
|
||||
#define BMKT_CMD_DISABLE_PAIRING 0xC2
|
||||
#define BMKT_CMD_QUERY_PAIRING 0xC5
|
||||
#define BMKT_CMD_SENSOR_STATUS 0xD1
|
||||
#define BMKT_CMD_ID_USER_IN_ORDER 0xE1
|
||||
#define BMKT_CMD_ID_NEXT_USER 0xE3
|
||||
#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1
|
||||
#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2
|
||||
#define BMKT_CMD_GET_FINAL_RESULT 0xE4
|
||||
|
||||
#define BMKT_EVT_FINGER_REPORT 0x91
|
||||
|
||||
#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00
|
||||
#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01
|
||||
|
||||
typedef struct bmkt_msg_resp
|
||||
{
|
||||
uint8_t msg_id;
|
||||
uint8_t seq_num;
|
||||
uint8_t payload_len;
|
||||
uint8_t *payload;
|
||||
int result;
|
||||
} bmkt_msg_resp_t;
|
||||
|
||||
int bmkt_compose_message (uint8_t *cmd,
|
||||
int *cmd_len,
|
||||
uint8_t msg_id,
|
||||
uint8_t seq_num,
|
||||
uint8_t payload_size,
|
||||
const uint8_t *payload);
|
||||
|
||||
int bmkt_parse_message_header (uint8_t *resp_buf,
|
||||
int resp_len,
|
||||
bmkt_msg_resp_t *msg_resp);
|
||||
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
|
||||
bmkt_response_t *resp);
|
||||
#endif /* BMKT_MESSAGE_H_ */
|
||||
489
libfprint/drivers/synaptics/bmkt_response.h
Normal file
489
libfprint/drivers/synaptics/bmkt_response.h
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Synaptics MiS Fingerprint Sensor Response Data Interface
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _BMKT_RESPONSE_H_
|
||||
#define _BMKT_RESPONSE_H_
|
||||
|
||||
#include "bmkt.h"
|
||||
|
||||
/** List of response message IDs */
|
||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02
|
||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03
|
||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05
|
||||
#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07
|
||||
#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09
|
||||
#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A
|
||||
#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C
|
||||
|
||||
/*! \addtogroup init
|
||||
* Response IDs returned by fingerprint initialization operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to initialize fingerprint sensor module */
|
||||
#define BMKT_RSP_FPS_INIT_FAIL 0x12
|
||||
/** Successfully initialized fingerprint sensor module */
|
||||
#define BMKT_RSP_FPS_INIT_OK 0x13
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup mode
|
||||
* Response IDs returned by get fingerprint mode operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to get fingerprint sensor module’s current operational mode */
|
||||
#define BMKT_RSP_FPS_MODE_FAIL 0x22
|
||||
/**
|
||||
* BMKT_RSP_FPS_MODE_REPORT:
|
||||
* Response containing the current operational mode of the fingerprint sensor module
|
||||
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_FPS_MODE_REPORT 0x23
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup setseclevel
|
||||
* Response IDs returned by set security level operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to set fingerprint sensor module security level */
|
||||
#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32
|
||||
/**
|
||||
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
||||
* Security level of the fingerprint sensor module was set successfully
|
||||
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup getseclevel
|
||||
* Response IDs returned by get security level operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to get fingerprint sensor module security level */
|
||||
#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35
|
||||
/**
|
||||
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
||||
* Returns the current security level of the fingerprint sensor module
|
||||
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup cancelop
|
||||
* Response IDs returned by cancel_operation operation
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* BMKT_RSP_CANCEL_OP_OK:
|
||||
* Successfully canceled the current operation and returned
|
||||
* fingerprint sensor module to idle mode
|
||||
*/
|
||||
#define BMKT_RSP_CANCEL_OP_OK 0x42
|
||||
/** Failed to cancel the current operation */
|
||||
#define BMKT_RSP_CANCEL_OP_FAIL 0x43
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup enrollment
|
||||
* Response IDs returned by enrollment operation
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* BMKT_RSP_ENROLL_READY:
|
||||
* Fingerprint enrollment session has begun and the user can place
|
||||
* their finger on the sensor
|
||||
*/
|
||||
#define BMKT_RSP_ENROLL_READY 0x54
|
||||
/** Progress of the currently on-going fingerprint enrollment session */
|
||||
#define BMKT_RSP_ENROLL_REPORT 0x55
|
||||
/** Enrollment has been paused */
|
||||
#define BMKT_RSP_ENROLL_PAUSED 0x56
|
||||
/** Enrollment has been resume */
|
||||
#define BMKT_RSP_ENROLL_RESUMED 0x57
|
||||
/** The current enrollment session has encountered an error */
|
||||
#define BMKT_RSP_ENROLL_FAIL 0x58
|
||||
/**
|
||||
* BMKT_RSP_ENROLL_OK:
|
||||
* User has been successfully enrolled into the fingerprint sensor module
|
||||
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_ENROLL_OK 0x59
|
||||
|
||||
/**
|
||||
* BMKT_RSP_CAPTURE_COMPLETE:
|
||||
* Fingerprint image capture is complete and it is safe for the user
|
||||
* to lift their finger off the sensor
|
||||
*/
|
||||
#define BMKT_RSP_CAPTURE_COMPLETE 0x60
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup identify
|
||||
* Response IDs returned by identify operation.
|
||||
* @{
|
||||
*/
|
||||
/* Fingerprint identification session has begun */
|
||||
#define BMKT_RSP_ID_READY 0x62
|
||||
/* Identification has failed */
|
||||
#define BMKT_RSP_ID_FAIL 0x63
|
||||
/**
|
||||
* BMKT_RSP_ID_OK:
|
||||
* User has been successfully identified
|
||||
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
||||
*/
|
||||
#define BMKT_RSP_ID_OK 0x64
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup verify
|
||||
* Response IDs returned by identify operation.
|
||||
* @{
|
||||
*/
|
||||
/** Fingerprint verification session has begun */
|
||||
#define BMKT_RSP_VERIFY_READY 0x66
|
||||
/** Verification has failed */
|
||||
#define BMKT_RSP_VERIFY_FAIL 0x67
|
||||
/**
|
||||
* BMKT_RSP_VERIFY_OK:
|
||||
* User’s identity has been successfully verified
|
||||
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
||||
*/
|
||||
#define BMKT_RSP_VERIFY_OK 0x68
|
||||
/*! @} */
|
||||
|
||||
/**
|
||||
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
||||
* Response ID returned by get enrolled users templates record operation
|
||||
* <br>Returns list of template records containing user IDs and corresponding finger IDs
|
||||
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75
|
||||
|
||||
/**
|
||||
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
||||
* Response ID returned by get next query response operation
|
||||
* <br>Complete sequence of messages containing the template records query response has been sent
|
||||
*/
|
||||
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76
|
||||
|
||||
/**
|
||||
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
||||
* Response ID returned by get enrolled fingers operation
|
||||
* <br> Returns list of IDs of enrolled fingers for a specific user,
|
||||
* along with template record status corresponding to each enrolled finger
|
||||
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77
|
||||
|
||||
/*! \addtogroup dbcapacity
|
||||
* Response IDs returned by get database capacity operation
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
||||
* Response specifying total capacity of fingerprint template database and
|
||||
* how much free capacity is remaining along with how many templates are corrupted and
|
||||
* how many bad (permanently unusable) storage slots are there.
|
||||
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78
|
||||
/** Failed to execute database query */
|
||||
#define BMKT_RSP_QUERY_FAIL 0x79
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup deluser
|
||||
* Response IDs returned by delete fingerprint of specific user operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to delete a user’s fingerprint template from the database */
|
||||
#define BMKT_RSP_DEL_USER_FP_FAIL 0x82
|
||||
/**
|
||||
* BMKT_RSP_DEL_USER_FP_OK:
|
||||
* Fingerprint template successfully deleted from the database.
|
||||
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
|
||||
* then all fingerprint templates for that user have been deleted from the database
|
||||
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_DEL_USER_FP_OK 0x83
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup delfulldb
|
||||
* Response IDs returned by delete entire fingerprint template DB operation
|
||||
* @{
|
||||
*/
|
||||
/** Failed to erase entire fingerprint template database */
|
||||
#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85
|
||||
/** Successfully erased entire fingerprint template database */
|
||||
#define BMKT_RSP_DEL_FULL_DB_OK 0x86
|
||||
/**
|
||||
* BMKT_RSP_DELETE_PROGRESS:
|
||||
* Notify progress made during the on-going deletion of the full template database
|
||||
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_DELETE_PROGRESS 0x87
|
||||
/*! @} */
|
||||
|
||||
/**
|
||||
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
||||
* Response ID returned by repeate last response operation
|
||||
* <br>Failed to retrieve and re-send last response
|
||||
*/
|
||||
#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93
|
||||
|
||||
/*! \addtogroup pwrdwn
|
||||
* Response IDs returned by power down notify operation
|
||||
* @{
|
||||
*/
|
||||
/** Fingerprint sensor module is ready to be powered down */
|
||||
#define BMKT_RSP_POWER_DOWN_READY 0xA2
|
||||
/** Failed to go into power down mode */
|
||||
#define BMKT_RSP_POWER_DOWN_FAIL 0xA3
|
||||
/*! @} */
|
||||
|
||||
/*! \addtogroup versioninfo
|
||||
* Response IDs returned by get version operation
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* BMKT_RSP_VERSION_INFO:
|
||||
* System version information of the fingerprint sensor module
|
||||
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
|
||||
*/
|
||||
#define BMKT_RSP_VERSION_INFO 0xB2
|
||||
/* Failed to retrieve and send last response */
|
||||
#define BMKT_RSP_GET_VERSION_FAIL 0xB3
|
||||
/*! @} */
|
||||
|
||||
/**
|
||||
* BMKT_RSP_GENERAL_ERROR:
|
||||
* Not tied to a specific command-response session.
|
||||
* <br>Could be caused by corrupt or truncated command message
|
||||
*/
|
||||
#define BMKT_RSP_GENERAL_ERROR 0xC1
|
||||
#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3
|
||||
#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4
|
||||
#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6
|
||||
#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7
|
||||
|
||||
/*! \addtogroup versioninfo
|
||||
* Response IDs returned by get sensor module status operation
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* BMKT_RSP_SENSOR_STATUS_REPORT:
|
||||
* Response returning the current status of the sensor module
|
||||
* <br>Payload data represented in bmkt_XXX struct
|
||||
*/
|
||||
#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2
|
||||
/** Failed to retrieve sensor status */
|
||||
#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3
|
||||
/*! @} */
|
||||
|
||||
/**
|
||||
* BMKT_RSP_SEND_NEXT_USER_ID:
|
||||
* Response ID returned by identify user in order operation
|
||||
* <br>Notify to send the next batch of user IDs in the priority list
|
||||
*/
|
||||
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2
|
||||
/**
|
||||
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
||||
* Response IDs returned by retrieve final result operation
|
||||
* <br>Failed to retrieve and re-send cached final result
|
||||
*/
|
||||
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
|
||||
|
||||
/**
|
||||
* Response payload data structure returned by sensor initialization operation.
|
||||
*/
|
||||
typedef struct bmkt_init_resp
|
||||
{
|
||||
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
|
||||
} bmkt_init_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_enroll_resp:
|
||||
* Response payload data structure returned by enrollment operation.
|
||||
*/
|
||||
typedef struct bmkt_enroll_resp
|
||||
{
|
||||
int progress; /**< Shows current progress stutus [0-100] */
|
||||
uint8_t finger_id; /**< User's finger id [1-10] */
|
||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
|
||||
} bmkt_enroll_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_auth_resp:
|
||||
* Response payload data structure returned by identify and verify operations.
|
||||
*/
|
||||
struct bmkt_auth_resp
|
||||
{
|
||||
double match_result; /**< match result returned by matcher */
|
||||
uint8_t finger_id; /**< Matched templates's finger id */
|
||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */
|
||||
};
|
||||
|
||||
typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */
|
||||
typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */
|
||||
|
||||
/**
|
||||
* bmkt_fps_mode_resp:
|
||||
* Response payload data structure returned by get fingerprint mode operation.
|
||||
*/
|
||||
typedef struct bmkt_fps_mode_resp
|
||||
{
|
||||
uint8_t mode; /**< One of the Level I bmkt_mode_t values */
|
||||
uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */
|
||||
uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */
|
||||
uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */
|
||||
} bmkt_fps_mode_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_get_version_resp:
|
||||
* Response payload data structure returned by get version operation.
|
||||
*/
|
||||
typedef struct bmkt_get_version_resp
|
||||
{
|
||||
uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */
|
||||
uint8_t year; /**< Software Version Year */
|
||||
uint8_t week; /**< Software Version Week */
|
||||
uint8_t patch; /**< Software Version Patch Level */
|
||||
uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */
|
||||
} bmkt_get_version_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_get_db_capacity_resp:
|
||||
* Response payload data structure returned by get DB capacity operation.
|
||||
*/
|
||||
typedef struct bmkt_get_db_capacity_resp
|
||||
{
|
||||
uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */
|
||||
uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */
|
||||
uint8_t bad_slots; /**< Number of bad template storage slots */
|
||||
uint8_t corrupt_templates; /**< Number of corrupt templates */
|
||||
} bmkt_get_db_capacity_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_sec_level:
|
||||
* Security level values.
|
||||
*/
|
||||
typedef enum bmkt_sec_level {
|
||||
BMKT_SECURITY_LEVEL_LOW = 0x10,
|
||||
BMKT_SECURITY_LEVEL_MEDIUM = 0x40,
|
||||
BMKT_SECURITY_LEVEL_HIGH = 0x60,
|
||||
} bmkt_sec_level_t;
|
||||
|
||||
/**
|
||||
* bmkt_set_sec_level_resp:
|
||||
* Response payload data structure returned by get/set security level operations.
|
||||
*/
|
||||
typedef struct bmkt_set_sec_level_resp
|
||||
{
|
||||
bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */
|
||||
} bmkt_set_sec_level_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_del_all_users_resp:
|
||||
* Response payload data structure returned by delete all enrolled users operation.
|
||||
*/
|
||||
typedef struct bmkt_del_all_users_resp
|
||||
{
|
||||
int progress; /**< Progress indicator as a percentage */
|
||||
} bmkt_del_all_users_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_del_user_resp:
|
||||
* Response payload data structure returned by delete enrolled user operation.
|
||||
*/
|
||||
typedef struct bmkt_del_user_resp
|
||||
{
|
||||
int progress; /**< Progress indicator as a percentage */
|
||||
} bmkt_del_user_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_enroll_template:
|
||||
* Structure of enrolled users template record data.
|
||||
*/
|
||||
typedef struct bmkt_enroll_template
|
||||
{
|
||||
uint8_t user_id_len; /**< Length of user_id string */
|
||||
uint8_t template_status; /**< Template record status */
|
||||
uint8_t finger_id; /**< ID of enrolled finger */
|
||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */
|
||||
} bmkt_enroll_template_t;
|
||||
|
||||
/**
|
||||
* bmkt_enroll_templates_resp:
|
||||
* Response payload data structure returned by get enrolled user list operation.
|
||||
*/
|
||||
typedef struct bmkt_enroll_templates_resp
|
||||
{
|
||||
uint8_t total_query_messages; /**< Total query response messages */
|
||||
uint8_t query_sequence; /**< Query response sequence number */
|
||||
bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */
|
||||
} bmkt_enroll_templates_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_enrolled_fingers:
|
||||
* Structure of template record status corresponding to each enrolled finger.
|
||||
*/
|
||||
typedef struct bmkt_enrolled_fingers
|
||||
{
|
||||
uint8_t finger_id; /**< ID of enrolled finger */
|
||||
uint8_t template_status; /**< Template record status of finger_id */
|
||||
} bmkt_enrolled_fingers_t;
|
||||
|
||||
/**
|
||||
* bmkt_enrolled_fingers_resp:
|
||||
* Response payload data structure returned by get enrolled fingers operation.
|
||||
*/
|
||||
typedef struct bmkt_enrolled_fingers_resp
|
||||
{
|
||||
bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */
|
||||
} bmkt_enrolled_fingers_resp_t;
|
||||
|
||||
/**
|
||||
* bmkt_response_data_t:
|
||||
* Union combining all response payload data types.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
bmkt_init_resp_t init_resp;
|
||||
bmkt_enroll_resp_t enroll_resp;
|
||||
bmkt_verify_resp_t verify_resp;
|
||||
bmkt_identify_resp_t id_resp;
|
||||
bmkt_fps_mode_resp_t fps_mode_resp;
|
||||
bmkt_get_version_resp_t get_version_resp;
|
||||
bmkt_get_db_capacity_resp_t db_cap_resp;
|
||||
bmkt_set_sec_level_resp_t sec_level_resp;
|
||||
bmkt_del_all_users_resp_t del_all_users_resp;
|
||||
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
||||
bmkt_del_user_resp_t del_user_resp;
|
||||
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
|
||||
} bmkt_response_data_t;
|
||||
|
||||
/**
|
||||
* bmkt_response:
|
||||
* Structure to abstract different response structure types in one API
|
||||
* to be used in bmkt_resp_cb_t callback function.
|
||||
*/
|
||||
typedef struct bmkt_response
|
||||
{
|
||||
int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */
|
||||
int result; /**< Operation execution result code */
|
||||
int complete; /**< Operation completion status 1: complete / 0: not completed */
|
||||
bmkt_response_data_t response; /**< Operation specific response union */
|
||||
} bmkt_response_t;
|
||||
|
||||
#endif /* _BMKT_RESPONSE_H_ */
|
||||
87
libfprint/drivers/synaptics/sensor.h
Normal file
87
libfprint/drivers/synaptics/sensor.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _SENSOR_H_
|
||||
#define _SENSOR_H_
|
||||
|
||||
#include "usb_transport.h"
|
||||
#define BMKT_MAX_PENDING_SESSIONS 2
|
||||
|
||||
typedef enum bmkt_sensor_state {
|
||||
BMKT_SENSOR_STATE_UNINIT = 0,
|
||||
BMKT_SENSOR_STATE_IDLE,
|
||||
BMKT_SENSOR_STATE_INIT,
|
||||
BMKT_SENSOR_STATE_EXIT,
|
||||
} bmkt_sensor_state_t;
|
||||
|
||||
typedef struct bmkt_sensor_drv bmkt_sensor_drv_t;
|
||||
|
||||
typedef struct bmkt_sensor_version
|
||||
{
|
||||
uint32_t build_time;
|
||||
uint32_t build_num;
|
||||
uint8_t version_major;
|
||||
uint8_t version_minor;
|
||||
uint8_t target;
|
||||
uint8_t product;
|
||||
uint8_t silicon_rev;
|
||||
uint8_t formal_release;
|
||||
uint8_t platform;
|
||||
uint8_t patch;
|
||||
uint8_t serial_number[6];
|
||||
uint16_t security;
|
||||
uint8_t iface;
|
||||
uint8_t device_type;
|
||||
} bmkt_sensor_version_t;
|
||||
|
||||
typedef struct bmkt_sensor
|
||||
{
|
||||
bmkt_usb_transport_t usb_xport;
|
||||
bmkt_sensor_version_t version;
|
||||
bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS];
|
||||
int empty_session_idx;
|
||||
int flags;
|
||||
int seq_num;
|
||||
bmkt_sensor_state_t sensor_state;
|
||||
bmkt_event_cb_t finger_event_cb;
|
||||
void *finger_cb_ctx;
|
||||
bmkt_general_error_cb_t gen_err_cb;
|
||||
void *gen_err_cb_ctx;
|
||||
bmkt_op_state_t op_state;
|
||||
} bmkt_sensor_t;
|
||||
|
||||
int bmkt_sensor_open (bmkt_sensor_t *sensor,
|
||||
bmkt_general_error_cb_t err_cb,
|
||||
void *err_cb_ctx);
|
||||
int bmkt_sensor_close (bmkt_sensor_t *sensor);
|
||||
|
||||
int bmkt_sensor_init_fps (bmkt_sensor_t *sensor);
|
||||
|
||||
int bmkt_sensor_send_message (bmkt_sensor_t *sensor,
|
||||
uint8_t msg_id,
|
||||
uint8_t payload_size,
|
||||
uint8_t *payload,
|
||||
bmkt_resp_cb_t resp_cb,
|
||||
void *resp_data);
|
||||
int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
|
||||
uint8_t *resp_buf,
|
||||
int resp_len,
|
||||
bmkt_msg_resp_t *msg_resp);
|
||||
|
||||
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
|
||||
#endif /* _SENSOR_H_ */
|
||||
1210
libfprint/drivers/synaptics/synaptics.c
Normal file
1210
libfprint/drivers/synaptics/synaptics.c
Normal file
File diff suppressed because it is too large
Load Diff
130
libfprint/drivers/synaptics/synaptics.h
Normal file
130
libfprint/drivers/synaptics/synaptics.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Synaptics Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __synaptics_h__
|
||||
#define __synaptics_h__
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
#define SYNAPTICS_VENDOR_ID 0x06cb
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice)
|
||||
|
||||
|
||||
#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
|
||||
|
||||
#define USB_EP_REQUEST 0x01
|
||||
#define USB_EP_REPLY 0x81
|
||||
#define USB_EP_FINGERPRINT 0x82
|
||||
#define USB_EP_INTERRUPT 0x83
|
||||
|
||||
#define USB_ASYNC_MESSAGE_PENDING 0x4
|
||||
#define USB_INTERRUPT_DATA_SIZE 7
|
||||
|
||||
#define SENSOR_CMD_GET_VERSION 1
|
||||
#define SENSOR_CMD_ACE_COMMAND 167
|
||||
#define SENSOR_CMD_ASYNCMSG_READ 168
|
||||
|
||||
#define SENSOR_FW_CMD_HEADER_LEN 1
|
||||
#define SENSOR_FW_REPLY_HEADER_LEN 2
|
||||
|
||||
|
||||
/* Number of enroll stages */
|
||||
#define ENROLL_SAMPLES 8
|
||||
|
||||
|
||||
#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors"
|
||||
#include "bmkt.h"
|
||||
#include "bmkt_response.h"
|
||||
|
||||
|
||||
typedef struct bmkt_sensor_version
|
||||
{
|
||||
uint32_t build_time;
|
||||
uint32_t build_num;
|
||||
uint8_t version_major;
|
||||
uint8_t version_minor;
|
||||
uint8_t target;
|
||||
uint8_t product;
|
||||
uint8_t silicon_rev;
|
||||
uint8_t formal_release;
|
||||
uint8_t platform;
|
||||
uint8_t patch;
|
||||
uint8_t serial_number[6];
|
||||
uint16_t security;
|
||||
uint8_t iface;
|
||||
uint8_t device_type;
|
||||
} bmkt_sensor_version_t;
|
||||
|
||||
|
||||
struct syna_enroll_resp_data
|
||||
{
|
||||
int progress;
|
||||
};
|
||||
typedef enum syna_state {
|
||||
SYNA_STATE_UNINIT = 0,
|
||||
SYNA_STATE_IDLE,
|
||||
SYNA_STATE_ENROLL,
|
||||
SYNA_STATE_IDENTIFY,
|
||||
SYNA_STATE_IDENTIFY_DELAY_RESULT,
|
||||
SYNA_STATE_VERIFY,
|
||||
SYNA_STATE_VERIFY_DELAY_RESULT,
|
||||
SYNA_STATE_DELETE,
|
||||
} syna_state_t;
|
||||
|
||||
typedef enum {
|
||||
SYNAPTICS_CMD_SEND_PENDING = 0,
|
||||
SYNAPTICS_CMD_GET_RESP,
|
||||
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
||||
SYNAPTICS_CMD_SEND_ASYNC,
|
||||
SYNAPTICS_CMD_RESTART,
|
||||
SYNAPTICS_CMD_NUM_STATES,
|
||||
} SynapticsCmdState;
|
||||
|
||||
|
||||
typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self,
|
||||
bmkt_response_t *resp,
|
||||
GError *error);
|
||||
|
||||
struct _FpiDeviceSynaptics
|
||||
{
|
||||
FpDevice parent;
|
||||
|
||||
guint8 cmd_seq_num;
|
||||
guint8 last_seq_num;
|
||||
FpiSsm *cmd_ssm;
|
||||
FpiUsbTransfer *cmd_pending_transfer;
|
||||
gboolean cmd_complete_on_removal;
|
||||
GError *cmd_complete_error;
|
||||
void *cmd_complete_data;
|
||||
|
||||
bmkt_sensor_version_t mis_version;
|
||||
|
||||
GCancellable *interrupt_cancellable;
|
||||
|
||||
gint enroll_stage;
|
||||
gboolean finger_on_sensor;
|
||||
GPtrArray *list_result;
|
||||
|
||||
|
||||
struct syna_enroll_resp_data enroll_resp_data;
|
||||
syna_state_t state;
|
||||
};
|
||||
|
||||
#endif //__synaptics_h__
|
||||
@@ -21,46 +21,47 @@
|
||||
#include "upek_proto.h"
|
||||
|
||||
static const uint16_t crc_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
uint16_t
|
||||
udf_crc(unsigned char *buffer, size_t size)
|
||||
udf_crc (unsigned char *buffer, size_t size)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
while (size--)
|
||||
crc = (uint16_t) ((crc << 8) ^
|
||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||
return crc;
|
||||
uint16_t crc = 0;
|
||||
|
||||
while (size--)
|
||||
crc = (uint16_t) ((crc << 8) ^
|
||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
@@ -21,4 +21,5 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
uint16_t udf_crc(unsigned char *buffer, size_t size);
|
||||
uint16_t udf_crc (unsigned char *buffer,
|
||||
size_t size);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,297 +23,298 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define IMG_WIDTH_2016 288
|
||||
#define IMG_WIDTH_1000 288
|
||||
#define IMG_WIDTH_1001 216
|
||||
#define IMG_WIDTH_2016 288
|
||||
#define IMG_WIDTH_1000 288
|
||||
#define IMG_WIDTH_1001 216
|
||||
|
||||
struct sonly_regwrite {
|
||||
uint8_t reg;
|
||||
uint8_t value;
|
||||
struct sonly_regwrite
|
||||
{
|
||||
guint8 reg;
|
||||
guint8 value;
|
||||
};
|
||||
|
||||
/***** AWAIT FINGER *****/
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_1[] = {
|
||||
{ 0x0a, 0x00 }, { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x3b },
|
||||
{ 0x00, 0x67 }, { 0x00, 0x67 },
|
||||
{ 0x0a, 0x00 }, { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x3b },
|
||||
{ 0x00, 0x67 }, { 0x00, 0x67 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_1000_writev_1[] = {
|
||||
/* Initialize sensor settings */
|
||||
{ 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x37 }, { 0x00, 0x5f },
|
||||
{ 0x01, 0x6e }, { 0x01, 0xee }, { 0x0c, 0x13 }, { 0x0d, 0x0d },
|
||||
{ 0x0e, 0x0e }, { 0x0f, 0x0d },
|
||||
/* Initialize sensor settings */
|
||||
{ 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x37 }, { 0x00, 0x5f },
|
||||
{ 0x01, 0x6e }, { 0x01, 0xee }, { 0x0c, 0x13 }, { 0x0d, 0x0d },
|
||||
{ 0x0e, 0x0e }, { 0x0f, 0x0d },
|
||||
|
||||
{ 0x13, 0x05 }, { 0x13, 0x45 },
|
||||
{ 0x13, 0x05 }, { 0x13, 0x45 },
|
||||
|
||||
/* Initialize finger detection registers (not enabling yet) */
|
||||
{ 0x30, 0xe0 }, { 0x15, 0x26 },
|
||||
/* Initialize finger detection registers (not enabling yet) */
|
||||
{ 0x30, 0xe0 }, { 0x15, 0x26 },
|
||||
|
||||
{ 0x12, 0x01 }, { 0x20, 0x01 }, { 0x07, 0x10 },
|
||||
{ 0x10, 0x00 }, { 0x11, 0xbf },
|
||||
{ 0x12, 0x01 }, { 0x20, 0x01 }, { 0x07, 0x10 },
|
||||
{ 0x10, 0x00 }, { 0x11, 0xbf },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_2[] = {
|
||||
{ 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||
{ 0x0f, 0x0d }, { 0x0b, 0x00 },
|
||||
{ 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||
{ 0x0f, 0x0d }, { 0x0b, 0x00 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_1000_writev_2[] = {
|
||||
/* Enable finger detection */
|
||||
{ 0x30, 0xe1 }, { 0x15, 0x06 }, { 0x15, 0x86 },
|
||||
/* Enable finger detection */
|
||||
{ 0x30, 0xe1 }, { 0x15, 0x06 }, { 0x15, 0x86 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_3[] = {
|
||||
{ 0x13, 0x45 }, { 0x30, 0xe0 }, { 0x12, 0x01 }, { 0x20, 0x01 },
|
||||
{ 0x09, 0x20 }, { 0x0a, 0x00 }, { 0x30, 0xe0 }, { 0x20, 0x01 },
|
||||
{ 0x13, 0x45 }, { 0x30, 0xe0 }, { 0x12, 0x01 }, { 0x20, 0x01 },
|
||||
{ 0x09, 0x20 }, { 0x0a, 0x00 }, { 0x30, 0xe0 }, { 0x20, 0x01 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_4[] = {
|
||||
{ 0x08, 0x00 }, { 0x10, 0x00 }, { 0x12, 0x01 }, { 0x11, 0xbf },
|
||||
{ 0x12, 0x01 }, { 0x07, 0x10 }, { 0x07, 0x10 }, { 0x04, 0x00 },\
|
||||
{ 0x05, 0x00 }, { 0x0b, 0x00 },
|
||||
|
||||
/* enter finger detection mode */
|
||||
{ 0x15, 0x20 }, { 0x30, 0xe1 }, { 0x15, 0x24 }, { 0x15, 0x04 },
|
||||
{ 0x15, 0x84 },
|
||||
{ 0x08, 0x00 }, { 0x10, 0x00 }, { 0x12, 0x01 }, { 0x11, 0xbf },
|
||||
{ 0x12, 0x01 }, { 0x07, 0x10 }, { 0x07, 0x10 }, { 0x04, 0x00 }, \
|
||||
{ 0x05, 0x00 }, { 0x0b, 0x00 },
|
||||
|
||||
/* enter finger detection mode */
|
||||
{ 0x15, 0x20 }, { 0x30, 0xe1 }, { 0x15, 0x24 }, { 0x15, 0x04 },
|
||||
{ 0x15, 0x84 },
|
||||
};
|
||||
|
||||
/***** CAPTURE MODE *****/
|
||||
|
||||
static const struct sonly_regwrite capsm_2016_writev[] = {
|
||||
/* enter capture mode */
|
||||
{ 0x09, 0x28 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, { 0x04, 0x00 },
|
||||
{ 0x05, 0x00 },
|
||||
/* enter capture mode */
|
||||
{ 0x09, 0x28 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, { 0x04, 0x00 },
|
||||
{ 0x05, 0x00 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1000_writev[] = {
|
||||
{ 0x08, 0x80 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, /* Enter capture mode */
|
||||
{ 0x08, 0x80 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, /* Enter capture mode */
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_1[] = {
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4e, 0x05 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4e, 0x05 },
|
||||
};
|
||||
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_2[] = {
|
||||
{ 0x4d, 0xc0 }, { 0x4e, 0x09 },
|
||||
{ 0x4d, 0xc0 }, { 0x4e, 0x09 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_3[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x0b, 0x00 },
|
||||
{ 0x04, 0x00 },
|
||||
{ 0x05, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4d, 0x40 }, { 0x4e, 0x09 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x0b, 0x00 },
|
||||
{ 0x04, 0x00 },
|
||||
{ 0x05, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4d, 0x40 }, { 0x4e, 0x09 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_4[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4e, 0x08 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4e, 0x08 },
|
||||
};
|
||||
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_5[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x00, 0x5f }, { 0x01, 0xee },
|
||||
{ 0x03, 0x2c },
|
||||
{ 0x07, 0x00 }, { 0x08, 0x00 }, { 0x09, 0x29 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||
{ 0x0f, 0x0d }, { 0x10, 0x00 }, { 0x11, 0x8f }, { 0x12, 0x01 }, { 0x13, 0x45 },
|
||||
{ 0x15, 0x26 },
|
||||
{ 0x1e, 0x02 },
|
||||
{ 0x20, 0x01 },
|
||||
{ 0x25, 0x8f },
|
||||
{ 0x27, 0x23 },
|
||||
{ 0x30, 0xe0 },
|
||||
{ 0x07, 0x10 },
|
||||
{ 0x09, 0x21 },
|
||||
{ 0x13, 0x75 },
|
||||
{ 0x0b, 0x80 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x00, 0x5f }, { 0x01, 0xee },
|
||||
{ 0x03, 0x2c },
|
||||
{ 0x07, 0x00 }, { 0x08, 0x00 }, { 0x09, 0x29 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||
{ 0x0f, 0x0d }, { 0x10, 0x00 }, { 0x11, 0x8f }, { 0x12, 0x01 }, { 0x13, 0x45 },
|
||||
{ 0x15, 0x26 },
|
||||
{ 0x1e, 0x02 },
|
||||
{ 0x20, 0x01 },
|
||||
{ 0x25, 0x8f },
|
||||
{ 0x27, 0x23 },
|
||||
{ 0x30, 0xe0 },
|
||||
{ 0x07, 0x10 },
|
||||
{ 0x09, 0x21 },
|
||||
{ 0x13, 0x75 },
|
||||
{ 0x0b, 0x80 },
|
||||
};
|
||||
|
||||
/***** DEINITIALIZATION *****/
|
||||
|
||||
static const struct sonly_regwrite deinitsm_2016_writev[] = {
|
||||
/* reset + enter low power mode */
|
||||
{ 0x0b, 0x00 }, { 0x09, 0x20 }, { 0x13, 0x45 }, { 0x13, 0x45 },
|
||||
/* reset + enter low power mode */
|
||||
{ 0x0b, 0x00 }, { 0x09, 0x20 }, { 0x13, 0x45 }, { 0x13, 0x45 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite deinitsm_1000_writev[] = {
|
||||
{ 0x15, 0x26 }, { 0x30, 0xe0 }, /* Disable finger detection */
|
||||
{ 0x15, 0x26 }, { 0x30, 0xe0 }, /* Disable finger detection */
|
||||
|
||||
{ 0x0b, 0x00 }, { 0x13, 0x45 }, { 0x08, 0x00 }, /* Disable capture mode */
|
||||
{ 0x0b, 0x00 }, { 0x13, 0x45 }, { 0x08, 0x00 }, /* Disable capture mode */
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite deinitsm_1001_writev[] = {
|
||||
{ 0x0b, 0x00 },
|
||||
{ 0x13, 0x45 },
|
||||
{ 0x09, 0x29 },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x0b, 0x00 },
|
||||
{ 0x13, 0x45 },
|
||||
{ 0x09, 0x29 },
|
||||
{ 0x1a, 0x00 },
|
||||
};
|
||||
|
||||
/***** INITIALIZATION *****/
|
||||
|
||||
static const struct sonly_regwrite initsm_2016_writev_1[] = {
|
||||
{ 0x49, 0x00 },
|
||||
|
||||
/* BSAPI writes different values to register 0x3e each time. I initially
|
||||
* thought this was some kind of clever authentication, but just blasting
|
||||
* these sniffed values each time seems to work. */
|
||||
{ 0x3e, 0x83 }, { 0x3e, 0x4f }, { 0x3e, 0x0f }, { 0x3e, 0xbf },
|
||||
{ 0x3e, 0x45 }, { 0x3e, 0x35 }, { 0x3e, 0x1c }, { 0x3e, 0xae },
|
||||
{ 0x49, 0x00 },
|
||||
|
||||
{ 0x44, 0x01 }, { 0x43, 0x06 }, { 0x43, 0x05 }, { 0x43, 0x04 },
|
||||
{ 0x44, 0x00 }, { 0x0b, 0x00 },
|
||||
/* BSAPI writes different values to register 0x3e each time. I initially
|
||||
* thought this was some kind of clever authentication, but just blasting
|
||||
* these sniffed values each time seems to work. */
|
||||
{ 0x3e, 0x83 }, { 0x3e, 0x4f }, { 0x3e, 0x0f }, { 0x3e, 0xbf },
|
||||
{ 0x3e, 0x45 }, { 0x3e, 0x35 }, { 0x3e, 0x1c }, { 0x3e, 0xae },
|
||||
|
||||
{ 0x44, 0x01 }, { 0x43, 0x06 }, { 0x43, 0x05 }, { 0x43, 0x04 },
|
||||
{ 0x44, 0x00 }, { 0x0b, 0x00 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite initsm_1000_writev_1[] = {
|
||||
{ 0x49, 0x00 }, /* Encryption disabled */
|
||||
{ 0x49, 0x00 }, /* Encryption disabled */
|
||||
|
||||
/* Setting encryption key. Doesn't need to be random since we don't use any
|
||||
* encryption. */
|
||||
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||
/* Setting encryption key. Doesn't need to be random since we don't use any
|
||||
* encryption. */
|
||||
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||
|
||||
{ 0x04, 0x00 }, { 0x05, 0x00 },
|
||||
{ 0x04, 0x00 }, { 0x05, 0x00 },
|
||||
|
||||
{ 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */
|
||||
{ 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_1[] = {
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4f, 0x06 },
|
||||
{ 0x4f, 0x05 },
|
||||
{ 0x4f, 0x04 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x3e, 0xa6 },
|
||||
{ 0x3e, 0x01 },
|
||||
{ 0x3e, 0x68 },
|
||||
{ 0x3e, 0xfd },
|
||||
{ 0x3e, 0x72 },
|
||||
{ 0x3e, 0xef },
|
||||
{ 0x3e, 0x5d },
|
||||
{ 0x3e, 0xc5 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4c, 0x1f }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4f, 0x06 },
|
||||
{ 0x4f, 0x05 },
|
||||
{ 0x4f, 0x04 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x3e, 0xa6 },
|
||||
{ 0x3e, 0x01 },
|
||||
{ 0x3e, 0x68 },
|
||||
{ 0x3e, 0xfd },
|
||||
{ 0x3e, 0x72 },
|
||||
{ 0x3e, 0xef },
|
||||
{ 0x3e, 0x5d },
|
||||
{ 0x3e, 0xc5 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4c, 0x1f }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||
};
|
||||
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_2[] = {
|
||||
{ 0x4c, 0x03 }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||
{ 0x4c, 0x03 }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_3[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4c, 0xff }, { 0x4d, 0xc0 }, { 0x4e, 0x00 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4c, 0xff }, { 0x4d, 0xc0 }, { 0x4e, 0x00 },
|
||||
};
|
||||
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_4[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x09, 0x27 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x49, 0x01 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x49, 0x00 },
|
||||
{ 0x3e, 0x90 },
|
||||
{ 0x3e, 0xbd },
|
||||
{ 0x3e, 0xbf },
|
||||
{ 0x3e, 0x48 },
|
||||
{ 0x3e, 0x2a },
|
||||
{ 0x3e, 0xe3 },
|
||||
{ 0x3e, 0xd2 },
|
||||
{ 0x3e, 0x58 },
|
||||
{ 0x09, 0x2f },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4d, 0x40 }, { 0x4e, 0x03 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x09, 0x27 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x49, 0x01 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x02 },
|
||||
{ 0x47, 0x0a },
|
||||
{ 0x47, 0x00 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x47, 0x04 },
|
||||
{ 0x49, 0x00 },
|
||||
{ 0x3e, 0x90 },
|
||||
{ 0x3e, 0xbd },
|
||||
{ 0x3e, 0xbf },
|
||||
{ 0x3e, 0x48 },
|
||||
{ 0x3e, 0x2a },
|
||||
{ 0x3e, 0xe3 },
|
||||
{ 0x3e, 0xd2 },
|
||||
{ 0x3e, 0x58 },
|
||||
{ 0x09, 0x2f },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x1a, 0x02 },
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4d, 0x40 }, { 0x4e, 0x03 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_5[] = {
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
{ 0x4a, 0x9c },
|
||||
{ 0x1a, 0x00 },
|
||||
};
|
||||
|
||||
@@ -23,457 +23,441 @@
|
||||
#include "drivers_api.h"
|
||||
#include "upektc.h"
|
||||
|
||||
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
||||
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
||||
#define UPEKET_EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define UPEKET_EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||
#define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN)
|
||||
#define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT)
|
||||
#define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||
#define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||
#define BULK_TIMEOUT 4000
|
||||
|
||||
struct upektc_dev {
|
||||
gboolean deactivating;
|
||||
const struct setup_cmd *setup_commands;
|
||||
size_t setup_commands_len;
|
||||
int ep_in;
|
||||
int ep_out;
|
||||
int init_idx;
|
||||
int sum_threshold;
|
||||
struct _FpiDeviceUpektc
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
||||
gboolean deactivating;
|
||||
const struct setup_cmd *setup_commands;
|
||||
size_t setup_commands_len;
|
||||
int ep_in;
|
||||
int ep_out;
|
||||
int init_idx;
|
||||
int sum_threshold;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC,
|
||||
FpImageDevice);
|
||||
G_DEFINE_TYPE (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE);
|
||||
|
||||
enum upektc_driver_data {
|
||||
UPEKTC_2015,
|
||||
UPEKTC_3001,
|
||||
UPEKTC_2015,
|
||||
UPEKTC_3001,
|
||||
};
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
static void complete_deactivation(struct fp_img_dev *dev);
|
||||
static void start_finger_detection(struct fp_img_dev *dev);
|
||||
static void start_capture (FpImageDevice *dev);
|
||||
static void complete_deactivation (FpImageDevice *dev,
|
||||
GError *error);
|
||||
static void start_finger_detection (FpImageDevice *dev);
|
||||
|
||||
/****** INITIALIZATION/DEINITIALIZATION ******/
|
||||
|
||||
enum activate_states {
|
||||
WRITE_INIT,
|
||||
READ_DATA,
|
||||
ACTIVATE_NUM_STATES,
|
||||
WRITE_INIT,
|
||||
READ_DATA,
|
||||
ACTIVATE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void
|
||||
upektc_next_init_cmd(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
upektc_next_init_cmd (FpiSsm *ssm,
|
||||
FpImageDevice *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
upekdev->init_idx += 1;
|
||||
if (upekdev->init_idx == upekdev->setup_commands_len)
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
else
|
||||
fpi_ssm_jump_to_state(ssm, WRITE_INIT);
|
||||
self->init_idx += 1;
|
||||
if (self->init_idx == self->setup_commands_len)
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
else
|
||||
fpi_ssm_jump_to_state (ssm, WRITE_INIT);
|
||||
}
|
||||
|
||||
static void write_init_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
write_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
upektc_next_init_cmd(ssm, dev);
|
||||
} else {
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
if (!error)
|
||||
{
|
||||
if (self->setup_commands[self->init_idx].response_len)
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
else
|
||||
upektc_next_init_cmd (transfer->ssm, dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_init_data_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||
upektc_next_init_cmd(ssm, dev);
|
||||
else
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
if (!error)
|
||||
upektc_next_init_cmd (transfer->ssm, dev);
|
||||
else
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
}
|
||||
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_INIT:
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case WRITE_INIT:
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
||||
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
fpi_usb_transfer_fill_bulk_full (transfer,
|
||||
self->ep_out,
|
||||
(unsigned char *) self->setup_commands[self->init_idx].cmd,
|
||||
UPEKTC_CMD_LEN,
|
||||
NULL);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
write_init_cb, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data,
|
||||
upekdev->setup_commands[upekdev->init_idx].response_len,
|
||||
read_init_data_cb, ssm, BULK_TIMEOUT);
|
||||
case READ_DATA:
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
fpi_usb_transfer_fill_bulk (transfer,
|
||||
self->ep_in,
|
||||
self->setup_commands[self->init_idx].response_len);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
read_init_data_cb, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
fpi_image_device_activate_complete (dev, error);
|
||||
|
||||
if (!error)
|
||||
start_finger_detection (dev);
|
||||
}
|
||||
|
||||
|
||||
/****** FINGER PRESENCE DETECTION ******/
|
||||
|
||||
static int finger_present(unsigned char *img, size_t len, int sum_threshold)
|
||||
static int
|
||||
finger_present (unsigned char *img, size_t len, int sum_threshold)
|
||||
{
|
||||
int i, sum;
|
||||
int i, sum;
|
||||
|
||||
sum = 0;
|
||||
sum = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (img[i] < 160) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
if (img[i] < 160)
|
||||
sum++;
|
||||
|
||||
fp_dbg("finger_present: sum is %d\n", sum);
|
||||
return sum < sum_threshold ? 0 : 1;
|
||||
fp_dbg ("finger_present: sum is %d\n", sum);
|
||||
return sum < sum_threshold ? 0 : 1;
|
||||
}
|
||||
|
||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("data transfer status %d\n", transfer->status);
|
||||
fpi_imgdev_session_error(dev, -EIO);
|
||||
goto out;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fp_dbg("expected %d, got %d bytes", transfer->length,
|
||||
transfer->actual_length);
|
||||
fpi_imgdev_session_error(dev, -EPROTO);
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("data transfer status %s\n", error->message);
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) {
|
||||
/* finger present, start capturing */
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
start_capture(dev);
|
||||
} else {
|
||||
/* no finger, poll for a new histogram */
|
||||
start_finger_detection(dev);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold))
|
||||
{
|
||||
/* finger present, start capturing */
|
||||
fpi_image_device_report_finger_status (dev, TRUE);
|
||||
start_capture (dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no finger, poll for a new histogram */
|
||||
start_finger_detection (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void finger_det_cmd_cb(struct libusb_transfer *t)
|
||||
static void
|
||||
finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
int r;
|
||||
struct fp_img_dev *dev = t->user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpiUsbTransfer *transfer;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("req transfer status %d\n", t->status);
|
||||
fpi_imgdev_session_error(dev, -EIO);
|
||||
goto exit_free_transfer;
|
||||
} else if (t->length != t->actual_length) {
|
||||
fp_dbg("expected %d, sent %d bytes", t->length, t->actual_length);
|
||||
fpi_imgdev_session_error(dev, -EPROTO);
|
||||
goto exit_free_transfer;
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("req transfer status %s\n", error->message);
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
data = g_malloc(IMAGE_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
}
|
||||
exit_free_transfer:
|
||||
libusb_free_transfer(t);
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
|
||||
IMAGE_SIZE);
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
finger_det_data_cb, NULL);
|
||||
}
|
||||
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
static void
|
||||
start_finger_detection (FpImageDevice *dev)
|
||||
{
|
||||
int r;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct libusb_transfer *transfer;
|
||||
G_DEBUG_HERE();
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
if (upekdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
}
|
||||
if (self->deactivating)
|
||||
{
|
||||
complete_deactivation (dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
||||
(unsigned char *) scan_cmd,
|
||||
UPEKTC_CMD_LEN, NULL);
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
finger_det_cmd_cb, NULL);
|
||||
}
|
||||
|
||||
/****** CAPTURE ******/
|
||||
|
||||
enum capture_states {
|
||||
CAPTURE_WRITE_CMD,
|
||||
CAPTURE_READ_DATA,
|
||||
CAPTURE_NUM_STATES,
|
||||
CAPTURE_WRITE_CMD,
|
||||
CAPTURE_READ_DATA,
|
||||
CAPTURE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpImage *img;
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("request is not completed, %s", error->message);
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
||||
memcpy (img->data, transfer->buffer, IMAGE_SIZE);
|
||||
fpi_image_device_image_captured (dev, img);
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
}
|
||||
|
||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
unsigned char *data = transfer->buffer;
|
||||
struct fp_img *img;
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("request is not completed, %d", transfer->status);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CAPTURE_WRITE_CMD:
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||
|
||||
img = fpi_img_new(IMAGE_SIZE);
|
||||
memcpy(img->data, data, IMAGE_SIZE);
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
out:
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
||||
(unsigned char *) scan_cmd,
|
||||
UPEKTC_CMD_LEN, NULL);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPTURE_READ_DATA:
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||
|
||||
fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
|
||||
IMAGE_SIZE);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
capture_read_data_cb, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_WRITE_CMD:
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
fp_dbg ("Capture completed");
|
||||
if (self->deactivating)
|
||||
complete_deactivation (dev, error);
|
||||
else if (error)
|
||||
fpi_image_device_session_error (dev, error);
|
||||
else
|
||||
start_finger_detection (dev);
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
data = g_malloc(IMAGE_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
start_capture (FpImageDevice *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
fp_dbg("Capture completed");
|
||||
if (upekdev->deactivating)
|
||||
complete_deactivation(dev);
|
||||
else if (fpi_ssm_get_error(ssm))
|
||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||
else
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
if (self->deactivating)
|
||||
{
|
||||
complete_deactivation (dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
|
||||
G_DEBUG_HERE ();
|
||||
fpi_ssm_start (ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
|
||||
if (upekdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
self->init_idx = 0;
|
||||
fpi_ssm_start (ssm, activate_sm_complete);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
static void
|
||||
dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
upekdev->init_idx = 0;
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
self->deactivating = TRUE;
|
||||
}
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
static void
|
||||
complete_deactivation (FpImageDevice *dev, GError *error)
|
||||
{
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
|
||||
upekdev->deactivating = TRUE;
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->deactivating = FALSE;
|
||||
fpi_image_device_deactivate_complete (dev, error);
|
||||
}
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_init (FpImageDevice *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
GError *error = NULL;
|
||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||
guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||
|
||||
upekdev->deactivating = FALSE;
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
/* TODO check that device has endpoints we're using */
|
||||
|
||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
||||
{
|
||||
fpi_image_device_open_complete (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (driver_data)
|
||||
{
|
||||
case UPEKTC_2015:
|
||||
self->ep_in = UPEKTC_EP_IN;
|
||||
self->ep_out = UPEKTC_EP_OUT;
|
||||
self->setup_commands = upektc_setup_commands;
|
||||
self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands);
|
||||
self->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||
break;
|
||||
|
||||
case UPEKTC_3001:
|
||||
self->ep_in = UPEKET_EP_IN;
|
||||
self->ep_out = UPEKET_EP_OUT;
|
||||
self->setup_commands = upeket_setup_commands;
|
||||
self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands);
|
||||
self->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_err ("Device variant %lu is not known\n", driver_data);
|
||||
g_assert_not_reached ();
|
||||
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
return;
|
||||
}
|
||||
fpi_image_device_open_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
static void
|
||||
dev_deinit (FpImageDevice *dev)
|
||||
{
|
||||
/* TODO check that device has endpoints we're using */
|
||||
int r;
|
||||
struct upektc_dev *upekdev;
|
||||
GError *error = NULL;
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
upekdev = g_malloc0(sizeof(struct upektc_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||
switch (driver_data) {
|
||||
case UPEKTC_2015:
|
||||
upekdev->ep_in = UPEKTC_EP_IN;
|
||||
upekdev->ep_out = UPEKTC_EP_OUT;
|
||||
upekdev->setup_commands = upektc_setup_commands;
|
||||
upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands);
|
||||
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||
break;
|
||||
case UPEKTC_3001:
|
||||
upekdev->ep_in = UPEKET_EP_IN;
|
||||
upekdev->ep_out = UPEKET_EP_OUT;
|
||||
upekdev->setup_commands = upeket_setup_commands;
|
||||
upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands);
|
||||
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||
break;
|
||||
default:
|
||||
fp_err("Device variant %lu is not known\n", driver_data);
|
||||
g_free(upekdev);
|
||||
fp_dev_set_instance_data(FP_DEV(dev), NULL);
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||
0, 0, &error);
|
||||
fpi_image_device_close_complete (dev, error);
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
void *user_data;
|
||||
user_data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(user_data);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x0483, .product = 0x2015, .driver_data = UPEKTC_2015 },
|
||||
{ .vendor = 0x147e, .product = 0x3001, .driver_data = UPEKTC_3001 },
|
||||
{ 0, 0, 0, },
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
|
||||
{ .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
struct fp_img_driver upektc_driver = {
|
||||
.driver = {
|
||||
.id = UPEKTC_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "UPEK TouchChip/Eikon Touch 300",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = IMAGE_HEIGHT,
|
||||
.img_width = IMAGE_WIDTH,
|
||||
static void
|
||||
fpi_device_upektc_init (FpiDeviceUpektc *self)
|
||||
{
|
||||
}
|
||||
static void
|
||||
fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
.bz3_threshold = 30,
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = dev_activate,
|
||||
.deactivate = dev_deactivate,
|
||||
};
|
||||
dev_class->id = "upektc";
|
||||
dev_class->full_name = "UPEK TouchChip/Eikon Touch 300";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
img_class->img_open = dev_init;
|
||||
img_class->img_close = dev_deinit;
|
||||
img_class->activate = dev_activate;
|
||||
img_class->deactivate = dev_deactivate;
|
||||
|
||||
img_class->bz3_threshold = 30;
|
||||
|
||||
img_class->img_width = IMAGE_WIDTH;
|
||||
img_class->img_height = IMAGE_HEIGHT;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,124 +21,124 @@
|
||||
#define __UPEKTC_IMG_H
|
||||
|
||||
static const unsigned char upek2020_init_1[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x04,
|
||||
0x00, 0x0d,
|
||||
0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0xda, 0xc1
|
||||
'C', 'i', 'a', 'o',
|
||||
0x04,
|
||||
0x00, 0x0d,
|
||||
0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0xda, 0xc1
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_init_2[] = {
|
||||
0x43, 0x69, 0x61, 0x6f,
|
||||
0x07,
|
||||
0x00, 0x01,
|
||||
0x01,
|
||||
0x3d, 0x72
|
||||
0x43, 0x69, 0x61, 0x6f,
|
||||
0x07,
|
||||
0x00, 0x01,
|
||||
0x01,
|
||||
0x3d, 0x72
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_init_3[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x04,
|
||||
0x00, 0x0d,
|
||||
0x01, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x55, 0x2f
|
||||
'C', 'i', 'a', 'o',
|
||||
0x04,
|
||||
0x00, 0x0d,
|
||||
0x01, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x55, 0x2f
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_init_4[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x00, 0x07,
|
||||
0x28, 0x04, 0x00, 0x00, 0x00, 0x06, 0x04,
|
||||
0xc0, 0xd6
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x00, 0x07,
|
||||
0x28, 0x04, 0x00, 0x00, 0x00, 0x06, 0x04,
|
||||
0xc0, 0xd6
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_deinit[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x07,
|
||||
0x00, 0x01,
|
||||
0x01,
|
||||
0x3d,
|
||||
0x72
|
||||
'C', 'i', 'a', 'o',
|
||||
0x07,
|
||||
0x00, 0x01,
|
||||
0x01,
|
||||
0x3d,
|
||||
0x72
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_init_capture[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x00, 0x0e, /* Seq = 7, len = 0x00e */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x0b, 0x00, /* Inner len = 0x000b */
|
||||
0x00, 0x00,
|
||||
0x0e, /* SUBCMD = 0x0e */
|
||||
0x02,
|
||||
0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */
|
||||
0x02,
|
||||
0x00, /* Wait for acceptable finger */
|
||||
0x02,
|
||||
0x14, 0x9a /* CRC */
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x00, 0x0e, /* Seq = 7, len = 0x00e */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x0b, 0x00, /* Inner len = 0x000b */
|
||||
0x00, 0x00,
|
||||
0x0e, /* SUBCMD = 0x0e */
|
||||
0x02,
|
||||
0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */
|
||||
0x02,
|
||||
0x00, /* Wait for acceptable finger */
|
||||
0x02,
|
||||
0x14, 0x9a /* CRC */
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const unsigned char finger_status[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x70, 0x14, /* Seq = 7, len = 0x014 */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x11, 0x00, /* Inner len = 0x0011 */
|
||||
0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x26, 0x03, /* CRC */
|
||||
0x00, 0x00, 0x00, /* Rest is garbage */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x70, 0x14, /* Seq = 7, len = 0x014 */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x11, 0x00, /* Inner len = 0x0011 */
|
||||
0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x26, 0x03, /* CRC */
|
||||
0x00, 0x00, 0x00, /* Rest is garbage */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static const unsigned char upek2020_ack_00_28[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x80, 0x08, /* Seq = 8, len = 0x008 */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x05, 0x00, /* Inner len = 0x0005 */
|
||||
0x00, 0x00, 0x00, 0x30, 0x01,
|
||||
0x6a, 0xc4 /* CRC */
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x80, 0x08, /* Seq = 8, len = 0x008 */
|
||||
0x28, /* CMD = 0x28 */
|
||||
0x05, 0x00, /* Inner len = 0x0005 */
|
||||
0x00, 0x00, 0x00, 0x30, 0x01,
|
||||
0x6a, 0xc4 /* CRC */
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* No seq should be tracked here */
|
||||
static const unsigned char got_finger[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x08,
|
||||
0x00, 0x00, /* Seq = 0, len = 0x000 */
|
||||
0xa1, 0xa9, /* CRC */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rest is garbage */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
'C', 'i', 'a', 'o',
|
||||
0x08,
|
||||
0x00, 0x00, /* Seq = 0, len = 0x000 */
|
||||
0xa1, 0xa9, /* CRC */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rest is garbage */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/* No seq should be put in there */
|
||||
static const unsigned char upek2020_ack_08[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x09,
|
||||
0x00, 0x00, /* Seq = 0, len = 0x0 */
|
||||
0x91, 0x9e /* CRC */
|
||||
'C', 'i', 'a', 'o',
|
||||
0x09,
|
||||
0x00, 0x00, /* Seq = 0, len = 0x0 */
|
||||
0x91, 0x9e /* CRC */
|
||||
};
|
||||
|
||||
static const unsigned char upek2020_ack_frame[] = {
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x50, 0x01, /* Seq = 5, len = 0x001 */
|
||||
0x30,
|
||||
0xac, 0x5b /* CRC */
|
||||
'C', 'i', 'a', 'o',
|
||||
0x00,
|
||||
0x50, 0x01, /* Seq = 5, len = 0x001 */
|
||||
0x30,
|
||||
0xac, 0x5b /* CRC */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -28,120 +28,90 @@
|
||||
* powerdown? does windows do anything special on exit?
|
||||
*/
|
||||
|
||||
#define CTRL_IN 0xc0
|
||||
#define CTRL_OUT 0x40
|
||||
#define CTRL_TIMEOUT 1000
|
||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define CTRL_TIMEOUT 1000
|
||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||
|
||||
#define IMG_WIDTH 300
|
||||
#define IMG_HEIGHT 288
|
||||
#define ROWS_PER_RQ 12
|
||||
#define NR_REQS (IMG_HEIGHT / ROWS_PER_RQ)
|
||||
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
||||
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
||||
#define IMG_WIDTH 300
|
||||
#define IMG_HEIGHT 288
|
||||
#define ROWS_PER_RQ 12
|
||||
#define NR_REQS (IMG_HEIGHT / ROWS_PER_RQ)
|
||||
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
||||
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
||||
|
||||
struct v5s_dev {
|
||||
int capture_iteration;
|
||||
struct fp_img *capture_img;
|
||||
gboolean loop_running;
|
||||
gboolean deactivating;
|
||||
struct _FpDeviceVcom5s
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
||||
int capture_iteration;
|
||||
FpImage *capture_img;
|
||||
gboolean loop_running;
|
||||
gboolean deactivating;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S,
|
||||
FpImageDevice);
|
||||
G_DEFINE_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE);
|
||||
|
||||
enum v5s_regs {
|
||||
/* when using gain 0x29:
|
||||
* a value of 0x00 produces mostly-black image
|
||||
* 0x09 destroys ridges (too white)
|
||||
* 0x01 or 0x02 seem good values */
|
||||
REG_CONTRAST = 0x02,
|
||||
/* when using gain 0x29:
|
||||
* a value of 0x00 produces mostly-black image
|
||||
* 0x09 destroys ridges (too white)
|
||||
* 0x01 or 0x02 seem good values */
|
||||
REG_CONTRAST = 0x02,
|
||||
|
||||
/* when using contrast 0x01:
|
||||
* a value of 0x00 will produce an all-black image.
|
||||
* 0x29 produces a good contrast image: ridges quite dark, but some
|
||||
* light grey noise as background
|
||||
* 0x46 produces all-white image with grey ridges (not very dark) */
|
||||
REG_GAIN = 0x03,
|
||||
/* when using contrast 0x01:
|
||||
* a value of 0x00 will produce an all-black image.
|
||||
* 0x29 produces a good contrast image: ridges quite dark, but some
|
||||
* light grey noise as background
|
||||
* 0x46 produces all-white image with grey ridges (not very dark) */
|
||||
REG_GAIN = 0x03,
|
||||
};
|
||||
|
||||
enum v5s_cmd {
|
||||
/* scan one row. has parameter, at a guess this is which row to scan? */
|
||||
CMD_SCAN_ONE_ROW = 0xc0,
|
||||
/* scan one row. has parameter, at a guess this is which row to scan? */
|
||||
CMD_SCAN_ONE_ROW = 0xc0,
|
||||
|
||||
/* scan whole image */
|
||||
CMD_SCAN = 0xc1,
|
||||
/* scan whole image */
|
||||
CMD_SCAN = 0xc1,
|
||||
};
|
||||
|
||||
/***** REGISTER I/O *****/
|
||||
|
||||
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
sm_write_reg (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
unsigned char reg,
|
||||
unsigned char value)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fp_dbg ("set %02x=%02x", reg, value);
|
||||
fpi_usb_transfer_fill_control (transfer,
|
||||
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
reg, value, 0, 0);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_write_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
unsigned char reg,
|
||||
unsigned char value)
|
||||
sm_exec_cmd (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
unsigned char cmd,
|
||||
unsigned char param)
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
fp_dbg("set %02x=%02x", reg, value);
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||
libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0);
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb,
|
||||
ssm, CTRL_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||
|
||||
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_exec_cmd(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
unsigned char cmd,
|
||||
unsigned char param)
|
||||
{
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
fp_dbg("cmd %02x param %02x", cmd, param);
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb,
|
||||
ssm, CTRL_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
fp_dbg ("cmd %02x param %02x", cmd, param);
|
||||
fpi_usb_transfer_fill_control (transfer,
|
||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
cmd, param, 0, 0);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
|
||||
/***** FINGER DETECTION *****/
|
||||
@@ -156,221 +126,242 @@ sm_exec_cmd(fpi_ssm *ssm,
|
||||
#define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
|
||||
#define FINGER_PRESENCE_THRESHOLD 100
|
||||
|
||||
static gboolean finger_is_present(unsigned char *data)
|
||||
static gboolean
|
||||
finger_is_present (unsigned char *data)
|
||||
{
|
||||
int row;
|
||||
uint16_t imgavg = 0;
|
||||
int row;
|
||||
guint16 imgavg = 0;
|
||||
|
||||
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) {
|
||||
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
||||
uint16_t rowavg = 0;
|
||||
int col;
|
||||
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++)
|
||||
{
|
||||
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
||||
guint16 rowavg = 0;
|
||||
int col;
|
||||
|
||||
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
||||
rowavg += rowdata[col];
|
||||
rowavg /= DETBOX_COLS;
|
||||
imgavg += rowavg;
|
||||
}
|
||||
imgavg /= DETBOX_ROWS;
|
||||
fp_dbg("img avg %d", imgavg);
|
||||
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
||||
rowavg += rowdata[col];
|
||||
rowavg /= DETBOX_COLS;
|
||||
imgavg += rowavg;
|
||||
}
|
||||
imgavg /= DETBOX_ROWS;
|
||||
fp_dbg ("img avg %d", imgavg);
|
||||
|
||||
return (imgavg <= FINGER_PRESENCE_THRESHOLD);
|
||||
return imgavg <= FINGER_PRESENCE_THRESHOLD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***** IMAGE ACQUISITION *****/
|
||||
|
||||
static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||
static void capture_iterate (FpiSsm *ssm,
|
||||
FpDevice *dev);
|
||||
|
||||
static void capture_cb(struct libusb_transfer *transfer)
|
||||
static void
|
||||
capture_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpImageDevice *imgdev = FP_IMAGE_DEVICE (device);
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (device);
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (++vdev->capture_iteration == NR_REQS) {
|
||||
struct fp_img *img = vdev->capture_img;
|
||||
/* must clear this early, otherwise the call chain takes us into
|
||||
* loopsm_complete where we would free it, when in fact we are
|
||||
* supposed to be handing off this image */
|
||||
vdev->capture_img = NULL;
|
||||
if (++self->capture_iteration == NR_REQS)
|
||||
{
|
||||
FpImage *img = self->capture_img;
|
||||
/* must clear this early, otherwise the call chain takes us into
|
||||
* loopsm_complete where we would free it, when in fact we are
|
||||
* supposed to be handing off this image */
|
||||
self->capture_img = NULL;
|
||||
|
||||
fpi_imgdev_report_finger_status(dev, finger_is_present(img->data));
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
capture_iterate(ssm, dev);
|
||||
}
|
||||
|
||||
out:
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_image_device_report_finger_status (imgdev,
|
||||
finger_is_present (img->data));
|
||||
fpi_image_device_image_captured (imgdev, img);
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
else
|
||||
{
|
||||
capture_iterate (transfer->ssm, device);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
capture_iterate(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
capture_iterate (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int iteration = vdev->capture_iteration;
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
int iteration = self->capture_iteration;
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
||||
capture_cb, ssm, CTRL_TIMEOUT);
|
||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_fill_bulk_full (transfer,
|
||||
EP_IN,
|
||||
self->capture_img->data + (RQ_SIZE * iteration),
|
||||
RQ_SIZE,
|
||||
NULL);
|
||||
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sm_do_capture(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
sm_do_capture (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
||||
vdev->capture_iteration = 0;
|
||||
capture_iterate(ssm, dev);
|
||||
G_DEBUG_HERE ();
|
||||
self->capture_img = fp_image_new (cls->img_width, cls->img_height);
|
||||
self->capture_iteration = 0;
|
||||
capture_iterate (ssm, dev);
|
||||
}
|
||||
|
||||
/***** CAPTURE LOOP *****/
|
||||
|
||||
enum loop_states {
|
||||
LOOP_SET_CONTRAST,
|
||||
LOOP_SET_GAIN,
|
||||
LOOP_CMD_SCAN,
|
||||
LOOP_CAPTURE,
|
||||
LOOP_CAPTURE_DONE,
|
||||
LOOP_NUM_STATES,
|
||||
LOOP_SET_CONTRAST,
|
||||
LOOP_SET_GAIN,
|
||||
LOOP_CMD_SCAN,
|
||||
LOOP_CAPTURE,
|
||||
LOOP_CAPTURE_DONE,
|
||||
LOOP_NUM_STATES,
|
||||
};
|
||||
|
||||
static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
loop_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case LOOP_SET_CONTRAST:
|
||||
sm_write_reg(ssm, dev, REG_CONTRAST, 0x01);
|
||||
break;
|
||||
case LOOP_SET_GAIN:
|
||||
sm_write_reg(ssm, dev, REG_GAIN, 0x29);
|
||||
break;
|
||||
case LOOP_CMD_SCAN:
|
||||
if (vdev->deactivating) {
|
||||
fp_dbg("deactivating, marking completed");
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else
|
||||
sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00);
|
||||
break;
|
||||
case LOOP_CAPTURE:
|
||||
sm_do_capture(ssm, dev);
|
||||
break;
|
||||
case LOOP_CAPTURE_DONE:
|
||||
fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN);
|
||||
break;
|
||||
}
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case LOOP_SET_CONTRAST:
|
||||
sm_write_reg (ssm, dev, REG_CONTRAST, 0x01);
|
||||
break;
|
||||
|
||||
case LOOP_SET_GAIN:
|
||||
sm_write_reg (ssm, dev, REG_GAIN, 0x29);
|
||||
break;
|
||||
|
||||
case LOOP_CMD_SCAN:
|
||||
if (self->deactivating)
|
||||
{
|
||||
fp_dbg ("deactivating, marking completed");
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sm_exec_cmd (ssm, dev, CMD_SCAN, 0x00);
|
||||
}
|
||||
break;
|
||||
|
||||
case LOOP_CAPTURE:
|
||||
sm_do_capture (ssm, dev);
|
||||
break;
|
||||
|
||||
case LOOP_CAPTURE_DONE:
|
||||
fpi_ssm_jump_to_state (ssm, LOOP_CMD_SCAN);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev);
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
fp_img_free(vdev->capture_img);
|
||||
vdev->capture_img = NULL;
|
||||
vdev->loop_running = FALSE;
|
||||
g_object_unref (self->capture_img);
|
||||
self->capture_img = NULL;
|
||||
self->loop_running = FALSE;
|
||||
|
||||
if (r)
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
if (error && !self->deactivating)
|
||||
fpi_image_device_session_error (imgdev, error);
|
||||
else if (error)
|
||||
g_error_free (error);
|
||||
|
||||
if (vdev->deactivating)
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
if (self->deactivating)
|
||||
fpi_image_device_deactivate_complete (imgdev, NULL);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
static void
|
||||
dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state,
|
||||
LOOP_NUM_STATES, dev);
|
||||
vdev->deactivating = FALSE;
|
||||
fpi_ssm_start(ssm, loopsm_complete);
|
||||
vdev->loop_running = TRUE;
|
||||
fpi_imgdev_activate_complete(dev, 0);
|
||||
return 0;
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, LOOP_NUM_STATES);
|
||||
|
||||
self->deactivating = FALSE;
|
||||
fpi_ssm_start (ssm, loopsm_complete);
|
||||
self->loop_running = TRUE;
|
||||
fpi_image_device_activate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
if (vdev->loop_running)
|
||||
vdev->deactivating = TRUE;
|
||||
else
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||
|
||||
if (self->loop_running)
|
||||
self->deactivating = TRUE;
|
||||
else
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
static void
|
||||
dev_init (FpImageDevice *dev)
|
||||
{
|
||||
int r;
|
||||
struct v5s_dev *v5s_dev;
|
||||
GError *error = NULL;
|
||||
|
||||
v5s_dev = g_malloc0(sizeof(struct v5s_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), v5s_dev);
|
||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0)
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
|
||||
if (r == 0)
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
|
||||
return r;
|
||||
fpi_image_device_open_complete (dev, error);
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_deinit (FpImageDevice *dev)
|
||||
{
|
||||
struct v5s_dev *v5s_dev;
|
||||
v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(v5s_dev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
GError *error = NULL;
|
||||
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||
0, 0, &error);
|
||||
|
||||
fpi_image_device_close_complete (dev, error);
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
{ .vendor = 0x061a, .product = 0x0110 },
|
||||
{ 0, 0, 0, },
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x061a, .pid = 0x0110, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
struct fp_img_driver vcom5s_driver = {
|
||||
.driver = {
|
||||
.id = VCOM5S_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "Veridicom 5thSense",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = IMG_HEIGHT,
|
||||
.img_width = IMG_WIDTH,
|
||||
static void
|
||||
fpi_device_vcom5s_init (FpDeviceVcom5s *self)
|
||||
{
|
||||
}
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = dev_activate,
|
||||
.deactivate = dev_deactivate,
|
||||
};
|
||||
static void
|
||||
fpi_device_vcom5s_class_init (FpDeviceVcom5sClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
dev_class->id = "vcom5s";
|
||||
dev_class->full_name = "Veridicom 5thSense";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
img_class->img_open = dev_init;
|
||||
img_class->img_close = dev_deinit;
|
||||
img_class->activate = dev_activate;
|
||||
img_class->deactivate = dev_deactivate;
|
||||
|
||||
img_class->img_width = IMG_WIDTH;
|
||||
img_class->img_height = IMG_HEIGHT;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-image-device.h"
|
||||
|
||||
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
||||
#define VFS_USB_TIMEOUT 100
|
||||
/* Timeout for usb abort */
|
||||
@@ -47,336 +51,336 @@
|
||||
#define EP3_IN 0x83
|
||||
|
||||
/* Fingerprint horizontal line */
|
||||
struct vfs_line {
|
||||
/* It must be always 0x01 */
|
||||
unsigned char _0x01;
|
||||
/* It must be always 0xfe */
|
||||
unsigned char _0xfe;
|
||||
struct vfs_line
|
||||
{
|
||||
/* It must be always 0x01 */
|
||||
unsigned char _0x01;
|
||||
/* It must be always 0xfe */
|
||||
unsigned char _0xfe;
|
||||
|
||||
/* line number starting from some number in Little-Endian */
|
||||
unsigned short id;
|
||||
/* line number starting from some number in Little-Endian */
|
||||
unsigned short id;
|
||||
|
||||
/* Some hashes which are useful to detect noise */
|
||||
unsigned char noise_hash_1;
|
||||
unsigned char noise_hash_2;
|
||||
/* Some hashes which are useful to detect noise */
|
||||
unsigned char noise_hash_1;
|
||||
unsigned char noise_hash_2;
|
||||
|
||||
/* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */
|
||||
unsigned short _somedata;
|
||||
/* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */
|
||||
unsigned short _somedata;
|
||||
|
||||
/* Fingerprint image */
|
||||
unsigned char data[VFS_IMAGE_WIDTH];
|
||||
/* Fingerprint image */
|
||||
unsigned char data[VFS_IMAGE_WIDTH];
|
||||
|
||||
/* Narrow fingerprint part from the center used for variable speed lines assembling */
|
||||
unsigned char next_line_part[VFS_NEXT_LINE_WIDTH];
|
||||
/* Narrow fingerprint part from the center used for variable speed lines assembling */
|
||||
unsigned char next_line_part[VFS_NEXT_LINE_WIDTH];
|
||||
|
||||
/* scan_data is 0xfb except some rare cases, it's skipped */
|
||||
unsigned char scan_data[8];
|
||||
} __attribute__ ((__packed__));
|
||||
/* scan_data is 0xfb except some rare cases, it's skipped */
|
||||
unsigned char scan_data[8];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* The main driver structure */
|
||||
struct vfs_dev_t {
|
||||
/* One if we were asked to read fingerprint, zero otherwise */
|
||||
char active;
|
||||
struct _FpDeviceVfs0050
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
||||
/* Control packet parameter for send_control_packet */
|
||||
unsigned char *control_packet;
|
||||
/* One if we were asked to read fingerprint, zero otherwise */
|
||||
char active;
|
||||
|
||||
/* For dev_deactivate to check whether ssm still running or not */
|
||||
char ssm_active;
|
||||
/* Control packet parameter for send_control_packet */
|
||||
unsigned char *control_packet;
|
||||
|
||||
/* Current async transfer */
|
||||
struct libusb_transfer *transfer;
|
||||
/* For dev_deactivate to check whether ssm still running or not */
|
||||
char ssm_active;
|
||||
|
||||
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
||||
char need_report;
|
||||
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
||||
char need_report;
|
||||
|
||||
/* Should we wait more for interrupt */
|
||||
char wait_interrupt;
|
||||
/* Received fingerprint raw lines */
|
||||
struct vfs_line *lines_buffer;
|
||||
|
||||
/* Received fingerprint raw lines */
|
||||
struct vfs_line *lines_buffer;
|
||||
/* Current number of received bytes and current memory used by data */
|
||||
int bytes, memory;
|
||||
|
||||
/* Current number of received bytes and current memory used by data */
|
||||
int bytes, memory;
|
||||
/* USB buffer for fingerprint */
|
||||
char *usb_buffer;
|
||||
|
||||
/* USB buffer for fingerprint */
|
||||
char *usb_buffer;
|
||||
|
||||
/* Received interrupt data */
|
||||
unsigned char interrupt[8];
|
||||
/* Received interrupt data */
|
||||
unsigned char interrupt[8];
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FPI, DEVICE_VFS0050, FpImageDevice)
|
||||
|
||||
/* SSM states for clear_ep2 */
|
||||
enum SUBSM1 {
|
||||
SUBSM1_COMMAND_04,
|
||||
SUBSM1_RETURN_CODE,
|
||||
SUBSM1_ABORT_2,
|
||||
SUBSM1_COMMAND_04,
|
||||
SUBSM1_RETURN_CODE,
|
||||
SUBSM1_ABORT_2,
|
||||
|
||||
SUBSM1_STATES,
|
||||
SUBSM1_STATES,
|
||||
};
|
||||
|
||||
/* SSM states for control */
|
||||
enum SUBSM2 {
|
||||
SUBSM2_SEND_CONTROL,
|
||||
SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */
|
||||
SUBSM2_SEND_CONTROL,
|
||||
SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */
|
||||
|
||||
SUBSM2_SEND_COMMIT,
|
||||
SUBSM2_COMMIT_RESPONSE,
|
||||
SUBSM2_READ_EMPTY_INTERRUPT,
|
||||
SUBSM2_ABORT_3,
|
||||
SUBSM2_CLEAR_EP2,
|
||||
SUBSM2_SEND_COMMIT,
|
||||
SUBSM2_COMMIT_RESPONSE,
|
||||
SUBSM2_READ_EMPTY_INTERRUPT,
|
||||
SUBSM2_ABORT_3,
|
||||
SUBSM2_CLEAR_EP2,
|
||||
|
||||
SUBSM2_STATES,
|
||||
SUBSM2_STATES,
|
||||
};
|
||||
|
||||
/* SSM states for activate_ssm */
|
||||
enum SSM_STATE {
|
||||
SSM_INITIAL_ABORT_1,
|
||||
SSM_INITIAL_ABORT_2,
|
||||
SSM_INITIAL_ABORT_3,
|
||||
SSM_CLEAR_EP2,
|
||||
SSM_TURN_OFF,
|
||||
SSM_INITIAL_ABORT_1,
|
||||
SSM_INITIAL_ABORT_2,
|
||||
SSM_INITIAL_ABORT_3,
|
||||
SSM_CLEAR_EP2,
|
||||
SSM_TURN_OFF,
|
||||
|
||||
/* Here the device is turned off; if not active, complete ssm */
|
||||
SSM_TURN_ON,
|
||||
/* Here the device is turned off; if not active, complete ssm */
|
||||
SSM_TURN_ON,
|
||||
|
||||
SSM_ASK_INTERRUPT,
|
||||
SSM_WAIT_INTERRUPT,
|
||||
SSM_ASK_INTERRUPT,
|
||||
SSM_WAIT_INTERRUPT,
|
||||
|
||||
SSM_RECEIVE_FINGER,
|
||||
SSM_SUBMIT_IMAGE,
|
||||
SSM_RECEIVE_FINGER,
|
||||
SSM_SUBMIT_IMAGE,
|
||||
|
||||
/* If not active, jump to CLEAR_EP2 */
|
||||
SSM_NEXT_RECEIVE,
|
||||
SSM_WAIT_ANOTHER_SCAN,
|
||||
/* Jump to TURN_ON */
|
||||
/* If not active, jump to CLEAR_EP2 */
|
||||
SSM_NEXT_RECEIVE,
|
||||
SSM_WAIT_ANOTHER_SCAN,
|
||||
/* Jump to TURN_ON */
|
||||
|
||||
SSM_STATES
|
||||
SSM_STATES
|
||||
};
|
||||
|
||||
/* Blocks of data from USB sniffer */
|
||||
|
||||
/* Turns on the light */
|
||||
static unsigned char turn_on[] = {
|
||||
0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0xD1, 0xD1, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF4, 0x01, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0xD1, 0xD1, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF4, 0x01, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* Power off */
|
||||
static unsigned char turn_off[] = {
|
||||
0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* Turns on orange light */
|
||||
static unsigned char next_receive_1[] = {
|
||||
0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* Packet directly after next_receive_1 */
|
||||
static unsigned char next_receive_2[] = {
|
||||
0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* Commit message */
|
||||
static unsigned char commit_out[] = {
|
||||
0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00,
|
||||
0x30, 0x1B, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x24, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x3C, 0x03, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00,
|
||||
0x30, 0x14, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x54, 0x03, 0x00,
|
||||
0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00,
|
||||
0x30, 0x90, 0x01, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x6C, 0x03, 0x00,
|
||||
0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00,
|
||||
0x30, 0x21, 0x80, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x80, 0x03, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00,
|
||||
0x30, 0x3A, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x90, 0x03, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1,
|
||||
0x01, 0x20, 0x00, 0x08,
|
||||
0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08,
|
||||
0x00, 0xA8, 0x03, 0x00,
|
||||
0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00,
|
||||
0x30, 0x64, 0x01, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0xB8, 0x03, 0x00,
|
||||
0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00,
|
||||
0x30, 0x05, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x08, 0x07, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x70, 0x0D, 0x00,
|
||||
0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B,
|
||||
0xED, 0x00, 0x00, 0x2B,
|
||||
0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24,
|
||||
0xBB, 0x3B, 0x0B, 0x24,
|
||||
0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0,
|
||||
0x00, 0x38, 0x80, 0x2C,
|
||||
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0,
|
||||
0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80,
|
||||
0x2E, 0x83, 0x24, 0xDB,
|
||||
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31,
|
||||
0x83, 0x2C, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4,
|
||||
0x00, 0x2F, 0x06, 0x84,
|
||||
0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00,
|
||||
0x30, 0xFF, 0xF0, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10,
|
||||
0x00, 0x20, 0x03, 0x00,
|
||||
0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x1C, 0x07, 0x00,
|
||||
0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00,
|
||||
0x30, 0xC3, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x80, 0x03, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77,
|
||||
0x77, 0x77, 0x78, 0x88,
|
||||
0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67,
|
||||
0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x77, 0x66, 0x66,
|
||||
0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56,
|
||||
0x66, 0x66, 0x56, 0x55,
|
||||
0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66,
|
||||
0x76, 0x76, 0x77, 0x77,
|
||||
0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56,
|
||||
0x65, 0x66, 0x65, 0x66,
|
||||
0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87,
|
||||
0x88, 0x77, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55,
|
||||
0x55, 0x55, 0x54, 0x45,
|
||||
0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77,
|
||||
0x66, 0x26, 0x00, 0x28,
|
||||
0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x30, 0x01, 0x02,
|
||||
0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02,
|
||||
0x00, 0x0B, 0x00, 0x19,
|
||||
0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00,
|
||||
0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00,
|
||||
0x30, 0x1B, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x24, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x3C, 0x03, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00,
|
||||
0x30, 0x14, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x54, 0x03, 0x00,
|
||||
0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00,
|
||||
0x30, 0x90, 0x01, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x6C, 0x03, 0x00,
|
||||
0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00,
|
||||
0x30, 0x21, 0x80, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x80, 0x03, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00,
|
||||
0x30, 0x3A, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x90, 0x03, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00,
|
||||
0x30, 0x08, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1,
|
||||
0x01, 0x20, 0x00, 0x08,
|
||||
0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08,
|
||||
0x00, 0xA8, 0x03, 0x00,
|
||||
0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00,
|
||||
0x30, 0x64, 0x01, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0xB8, 0x03, 0x00,
|
||||
0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00,
|
||||
0x30, 0x05, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x08, 0x07, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x70, 0x0D, 0x00,
|
||||
0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B,
|
||||
0xED, 0x00, 0x00, 0x2B,
|
||||
0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24,
|
||||
0xBB, 0x3B, 0x0B, 0x24,
|
||||
0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0,
|
||||
0x00, 0x38, 0x80, 0x2C,
|
||||
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0,
|
||||
0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80,
|
||||
0x2E, 0x83, 0x24, 0xDB,
|
||||
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31,
|
||||
0x83, 0x2C, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4,
|
||||
0x00, 0x2F, 0x06, 0x84,
|
||||
0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00,
|
||||
0x30, 0xFF, 0xF0, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10,
|
||||
0x00, 0x20, 0x03, 0x00,
|
||||
0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00,
|
||||
0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x1C, 0x07, 0x00,
|
||||
0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00,
|
||||
0x30, 0xC3, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||
0x00, 0x80, 0x03, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77,
|
||||
0x77, 0x77, 0x78, 0x88,
|
||||
0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67,
|
||||
0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x77, 0x66, 0x66,
|
||||
0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56,
|
||||
0x66, 0x66, 0x56, 0x55,
|
||||
0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66,
|
||||
0x76, 0x76, 0x77, 0x77,
|
||||
0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56,
|
||||
0x65, 0x66, 0x65, 0x66,
|
||||
0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87,
|
||||
0x88, 0x77, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55,
|
||||
0x55, 0x55, 0x54, 0x45,
|
||||
0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77,
|
||||
0x66, 0x26, 0x00, 0x28,
|
||||
0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x30, 0x01, 0x02,
|
||||
0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02,
|
||||
0x00, 0x0B, 0x00, 0x19,
|
||||
0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00,
|
||||
};
|
||||
|
||||
/* Known interrupts */
|
||||
|
||||
static unsigned char empty_interrupt[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static unsigned char interrupt1[] = {
|
||||
0x02, 0x00, 0x0E, 0x00, 0xF0,
|
||||
0x02, 0x00, 0x0E, 0x00, 0xF0,
|
||||
};
|
||||
|
||||
static unsigned char interrupt2[] = {
|
||||
0x02, 0x04, 0x0A, 0x00, 0xF0,
|
||||
0x02, 0x04, 0x0A, 0x00, 0xF0,
|
||||
};
|
||||
|
||||
static unsigned char interrupt3[] = {
|
||||
0x02, 0x00, 0x0A, 0x00, 0xF0,
|
||||
0x02, 0x00, 0x0A, 0x00, 0xF0,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,269 +22,260 @@
|
||||
#define FP_COMPONENT "vfs301"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "vfs301_proto.h"
|
||||
#include "vfs301.h"
|
||||
|
||||
G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE)
|
||||
|
||||
/************************** GENERIC STUFF *************************************/
|
||||
|
||||
/* Submit asynchronous sleep */
|
||||
static void
|
||||
async_sleep(unsigned int msec,
|
||||
fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
/* Add timeout */
|
||||
if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) {
|
||||
/* Failed to add timeout */
|
||||
fp_err("failed to add timeout");
|
||||
fpi_imgdev_session_error(dev, -ETIME);
|
||||
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
submit_image(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
submit_image (FpiSsm *ssm,
|
||||
FpImageDevice *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int height;
|
||||
struct fp_img *img;
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||
int height;
|
||||
FpImage *img;
|
||||
|
||||
#if 0
|
||||
/* XXX: This is probably handled by libfprint automagically? */
|
||||
if (vdev->scanline_count < 20) {
|
||||
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
||||
return 0;
|
||||
}
|
||||
/* XXX: This is probably handled by libfprint automagically? */
|
||||
if (vdev->scanline_count < 20)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
img = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count);
|
||||
if (img == NULL)
|
||||
return 0;
|
||||
img = fp_image_new (VFS301_FP_OUTPUT_WIDTH, self->scanline_count);
|
||||
if (img == NULL)
|
||||
return 0;
|
||||
|
||||
vfs301_extract_image(vdev, img->data, &height);
|
||||
vfs301_extract_image (self, img->data, &height);
|
||||
|
||||
/* TODO: how to detect flip? should the resulting image be
|
||||
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
||||
* or to the finger when I look at it?) */
|
||||
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED;
|
||||
/* TODO: how to detect flip? should the resulting image be
|
||||
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
||||
* or to the finger when I look at it?) */
|
||||
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
|
||||
|
||||
img->width = VFS301_FP_OUTPUT_WIDTH;
|
||||
img->height = height;
|
||||
/* The image buffer is larger at this point, but that does not
|
||||
* matter. */
|
||||
img->width = VFS301_FP_OUTPUT_WIDTH;
|
||||
img->height = height;
|
||||
|
||||
img = fpi_img_realloc(img, img->height * img->width);
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_image_device_image_captured (dev, img);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Loop ssm states */
|
||||
enum
|
||||
{
|
||||
/* Step 0 - Scan finger */
|
||||
M_REQUEST_PRINT,
|
||||
M_WAIT_PRINT,
|
||||
M_CHECK_PRINT,
|
||||
M_READ_PRINT_START,
|
||||
M_READ_PRINT_WAIT,
|
||||
M_READ_PRINT_POLL,
|
||||
M_SUBMIT_PRINT,
|
||||
enum {
|
||||
/* Step 0 - Scan finger */
|
||||
M_REQUEST_PRINT,
|
||||
M_WAIT_PRINT,
|
||||
M_CHECK_PRINT,
|
||||
M_READ_PRINT_START,
|
||||
M_READ_PRINT_WAIT,
|
||||
M_READ_PRINT_POLL,
|
||||
M_SUBMIT_PRINT,
|
||||
|
||||
/* Number of states */
|
||||
M_LOOP_NUM_STATES,
|
||||
/* Number of states */
|
||||
M_LOOP_NUM_STATES,
|
||||
};
|
||||
|
||||
/* Exec loop sequential state machine */
|
||||
static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case M_REQUEST_PRINT:
|
||||
vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case M_REQUEST_PRINT:
|
||||
vfs301_proto_request_fingerprint (self);
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case M_WAIT_PRINT:
|
||||
/* Wait fingerprint scanning */
|
||||
async_sleep(200, ssm, dev);
|
||||
break;
|
||||
case M_WAIT_PRINT:
|
||||
/* Wait fingerprint scanning */
|
||||
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||
break;
|
||||
|
||||
case M_CHECK_PRINT:
|
||||
if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev))
|
||||
fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case M_CHECK_PRINT:
|
||||
if (!vfs301_proto_peek_event (self))
|
||||
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_START:
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case M_READ_PRINT_START:
|
||||
fpi_image_device_report_finger_status (dev, TRUE);
|
||||
vfs301_proto_process_event_start (self);
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_WAIT:
|
||||
/* Wait fingerprint scanning */
|
||||
async_sleep(200, ssm, dev);
|
||||
break;
|
||||
case M_READ_PRINT_WAIT:
|
||||
/* Wait fingerprint scanning */
|
||||
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_POLL:
|
||||
{
|
||||
int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
g_assert(rv != VFS301_FAILURE);
|
||||
if (rv == VFS301_ONGOING)
|
||||
fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
break;
|
||||
case M_READ_PRINT_POLL:
|
||||
{
|
||||
int rv = vfs301_proto_process_event_poll (self);
|
||||
g_assert (rv != VFS301_FAILURE);
|
||||
if (rv == VFS301_ONGOING)
|
||||
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
break;
|
||||
|
||||
case M_SUBMIT_PRINT:
|
||||
if (submit_image(ssm, dev)) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
/* NOTE: finger off is expected only after submitting image... */
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
} else {
|
||||
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case M_SUBMIT_PRINT:
|
||||
if (submit_image (ssm, dev))
|
||||
{
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
/* NOTE: finger off is expected only after submitting image... */
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Complete loop sequential state machine */
|
||||
static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
{
|
||||
/* Free sequential state machine */
|
||||
fpi_ssm_free(ssm);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("State machine completed with an error: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
/* Free sequential state machine */
|
||||
}
|
||||
|
||||
/* Exec init sequential state machine */
|
||||
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
||||
|
||||
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
|
||||
g_assert (fpi_ssm_get_cur_state (ssm) == 0);
|
||||
|
||||
vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
vfs301_proto_init (self);
|
||||
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
}
|
||||
|
||||
/* Complete init sequential state machine */
|
||||
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
fpi_ssm *ssm_loop;
|
||||
FpiSsm *ssm_loop;
|
||||
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
/* Notify activate complete */
|
||||
fpi_imgdev_activate_complete(dev, 0);
|
||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
||||
if (!error)
|
||||
{
|
||||
/* Notify activate complete */
|
||||
|
||||
/* Start loop ssm */
|
||||
ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm_loop, m_loop_complete);
|
||||
}
|
||||
/* Start loop ssm */
|
||||
ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES);
|
||||
fpi_ssm_start (ssm_loop, m_loop_complete);
|
||||
}
|
||||
|
||||
/* Free sequential state machine */
|
||||
fpi_ssm_free(ssm);
|
||||
/* Free sequential state machine */
|
||||
}
|
||||
|
||||
/* Activate device */
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
static void
|
||||
dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
fpi_ssm *ssm;
|
||||
FpiSsm *ssm;
|
||||
|
||||
/* Start init ssm */
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev);
|
||||
fpi_ssm_start(ssm, m_init_complete);
|
||||
|
||||
return 0;
|
||||
/* Start init ssm */
|
||||
ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1);
|
||||
fpi_ssm_start (ssm, m_init_complete);
|
||||
}
|
||||
|
||||
/* Deactivate device */
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev;
|
||||
FpDeviceVfs301 *self;
|
||||
|
||||
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
self = FPI_DEVICE_VFS301 (dev);
|
||||
vfs301_proto_deinit (self);
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
static void
|
||||
dev_open (FpImageDevice *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev = NULL;
|
||||
int r;
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Claim usb interface */
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
/* Interface not claimed, return error */
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
/* Claim usb interface */
|
||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||
|
||||
/* Initialize private structure */
|
||||
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), vdev);
|
||||
/* Initialize private structure */
|
||||
self->scanline_count = 0;
|
||||
|
||||
vdev->scanline_buf = malloc(0);
|
||||
vdev->scanline_count = 0;
|
||||
|
||||
/* Notify open complete */
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
|
||||
return 0;
|
||||
/* Notify open complete */
|
||||
fpi_image_device_open_complete (dev, error);
|
||||
}
|
||||
|
||||
static void dev_close(struct fp_img_dev *dev)
|
||||
static void
|
||||
dev_close (FpImageDevice *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev;
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Release private structure */
|
||||
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
free(vdev->scanline_buf);
|
||||
g_free(vdev);
|
||||
/* Release private structure */
|
||||
g_clear_pointer (&self->scanline_buf, g_free);
|
||||
|
||||
/* Release usb interface */
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
/* Release usb interface */
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||
0, 0, &error);
|
||||
|
||||
/* Notify close complete */
|
||||
fpi_imgdev_close_complete(dev);
|
||||
/* Notify close complete */
|
||||
fpi_image_device_close_complete (dev, error);
|
||||
}
|
||||
|
||||
/* Usb id table of device */
|
||||
static const struct usb_id id_table[] =
|
||||
{
|
||||
{ .vendor = 0x138a, .product = 0x0005 /* vfs301 */ },
|
||||
{ .vendor = 0x138a, .product = 0x0008 /* vfs300 */ },
|
||||
{ 0, 0, 0, },
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ /* vfs301 */ .vid = 0x138a, .pid = 0x0005, },
|
||||
{ /* vfs300 */ .vid = 0x138a, .pid = 0x0008, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
/* Device driver definition */
|
||||
struct fp_img_driver vfs301_driver =
|
||||
static void
|
||||
fpi_device_vfs301_init (FpDeviceVfs301 *self)
|
||||
{
|
||||
/* Driver specification */
|
||||
.driver =
|
||||
{
|
||||
.id = VFS301_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "Validity VFS301",
|
||||
.bus = BUS_TYPE_USB,
|
||||
.id_table.usb = id_table,
|
||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||
},
|
||||
}
|
||||
static void
|
||||
fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
/* Image specification */
|
||||
.flags = 0,
|
||||
.img_width = VFS301_FP_WIDTH,
|
||||
.img_height = -1,
|
||||
.bz3_threshold = 24,
|
||||
dev_class->id = "vfs301";
|
||||
dev_class->full_name = "Validity VFS301";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||
|
||||
/* Routine specification */
|
||||
.open = dev_open,
|
||||
.close = dev_close,
|
||||
.activate = dev_activate,
|
||||
.deactivate = dev_deactivate,
|
||||
};
|
||||
img_class->img_open = dev_open;
|
||||
img_class->img_close = dev_close;
|
||||
img_class->activate = dev_activate;
|
||||
img_class->deactivate = dev_deactivate;
|
||||
|
||||
img_class->bz3_threshold = 24;
|
||||
|
||||
img_class->img_width = VFS301_FP_WIDTH;
|
||||
img_class->img_height = -1;
|
||||
}
|
||||
|
||||
142
libfprint/drivers/vfs301.h
Normal file
142
libfprint/drivers/vfs301.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* vfs301/vfs300 fingerprint reader driver
|
||||
* https://github.com/andree182/vfs301
|
||||
*
|
||||
* Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-usb-transfer.h"
|
||||
#include "fpi-image-device.h"
|
||||
|
||||
enum {
|
||||
VFS301_DEFAULT_WAIT_TIMEOUT = 300,
|
||||
|
||||
VFS301_SEND_ENDPOINT = 0x01,
|
||||
VFS301_RECEIVE_ENDPOINT_CTRL = 0x81,
|
||||
VFS301_RECEIVE_ENDPOINT_DATA = 0x82
|
||||
};
|
||||
|
||||
#define VFS301_FP_RECV_LEN_1 (84032)
|
||||
#define VFS301_FP_RECV_LEN_2 (84096)
|
||||
|
||||
struct _FpDeviceVfs301
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
||||
/* buffer to hold raw scanlines */
|
||||
unsigned char *scanline_buf;
|
||||
int scanline_count;
|
||||
|
||||
enum {
|
||||
VFS301_ONGOING = 0,
|
||||
VFS301_ENDED = 1,
|
||||
VFS301_FAILURE = -1
|
||||
} recv_progress;
|
||||
int recv_exp_amt;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVfs301, fpi_device_vfs301, FPI, DEVICE_VFS301, FpImageDevice)
|
||||
|
||||
enum {
|
||||
/* Width of the scanned data in px */
|
||||
VFS301_FP_WIDTH = 200,
|
||||
|
||||
/* sizeof(fp_line_t) */
|
||||
VFS301_FP_FRAME_SIZE = 288,
|
||||
/* Width of output line */
|
||||
#ifndef OUTPUT_RAW
|
||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH,
|
||||
#else
|
||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE,
|
||||
#endif
|
||||
|
||||
VFS301_FP_SUM_LINES = 3,
|
||||
|
||||
#ifdef SCAN_FINISH_DETECTION
|
||||
/* TODO: The following changes (seen ~60 and ~80) In that
|
||||
* case we'll need to calibrate this from empty data somehow... */
|
||||
VFS301_FP_SUM_MEDIAN = 60,
|
||||
VFS301_FP_SUM_EMPTY_RANGE = 5,
|
||||
#endif
|
||||
|
||||
/* Minimum average difference between returned lines */
|
||||
VFS301_FP_LINE_DIFF_THRESHOLD = 15,
|
||||
|
||||
/* Maximum waiting time for a single fingerprint frame */
|
||||
VFS301_FP_RECV_TIMEOUT = 2000
|
||||
};
|
||||
|
||||
/* Arrays of this structure is returned during the initialization as a response
|
||||
* to the 0x02D0 messages.
|
||||
* It seems to be always the same - what is it for? Some kind of confirmation?
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned char sync_0x01;
|
||||
unsigned char sync_0xfe;
|
||||
|
||||
unsigned char counter_lo;
|
||||
unsigned char counter_hi; /* FIXME ? */
|
||||
|
||||
unsigned char flags[3];
|
||||
|
||||
unsigned char sync_0x00;
|
||||
|
||||
unsigned char scan[VFS301_FP_WIDTH];
|
||||
} vfs301_init_line_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char sync_0x01;
|
||||
unsigned char sync_0xfe;
|
||||
|
||||
unsigned char counter_lo;
|
||||
unsigned char counter_hi;
|
||||
|
||||
unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */
|
||||
/* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */
|
||||
unsigned char flag_1;
|
||||
unsigned char sync_0x00;
|
||||
|
||||
unsigned char scan[VFS301_FP_WIDTH];
|
||||
|
||||
/* A offsetted, stretched, inverted copy of scan... probably could
|
||||
* serve finger motion speed detection?
|
||||
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
||||
unsigned char mirror[64];
|
||||
|
||||
/* Some kind of sum of the scan, very low contrast */
|
||||
unsigned char sum1[2];
|
||||
unsigned char sum2[11];
|
||||
unsigned char sum3[3];
|
||||
} vfs301_line_t;
|
||||
|
||||
void vfs301_proto_init (FpDeviceVfs301 *dev);
|
||||
void vfs301_proto_deinit (FpDeviceVfs301 *dev);
|
||||
|
||||
void vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev);
|
||||
|
||||
/** returns 0 if no event is ready, or 1 if there is one... */
|
||||
int vfs301_proto_peek_event (FpDeviceVfs301 *dev);
|
||||
void vfs301_proto_process_event_start (FpDeviceVfs301 *dev);
|
||||
int vfs301_proto_process_event_poll (FpDeviceVfs301 *dev);
|
||||
|
||||
void vfs301_extract_image (FpDeviceVfs301 *vfs,
|
||||
unsigned char *output,
|
||||
int *output_height);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* vfs301/vfs300 fingerprint reader driver
|
||||
* https://github.com/andree182/vfs301
|
||||
*
|
||||
* Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
enum {
|
||||
VFS301_DEFAULT_WAIT_TIMEOUT = 300,
|
||||
|
||||
VFS301_SEND_ENDPOINT = 0x01,
|
||||
VFS301_RECEIVE_ENDPOINT_CTRL = 0x81,
|
||||
VFS301_RECEIVE_ENDPOINT_DATA = 0x82
|
||||
};
|
||||
|
||||
#define VFS301_FP_RECV_LEN_1 (84032)
|
||||
#define VFS301_FP_RECV_LEN_2 (84096)
|
||||
|
||||
typedef struct {
|
||||
/* buffer for received data */
|
||||
unsigned char recv_buf[0x20000];
|
||||
int recv_len;
|
||||
|
||||
/* buffer to hold raw scanlines */
|
||||
unsigned char *scanline_buf;
|
||||
int scanline_count;
|
||||
|
||||
enum {
|
||||
VFS301_ONGOING = 0,
|
||||
VFS301_ENDED = 1,
|
||||
VFS301_FAILURE = -1
|
||||
} recv_progress;
|
||||
int recv_exp_amt;
|
||||
} vfs301_dev_t;
|
||||
|
||||
enum {
|
||||
/* Width of the scanned data in px */
|
||||
VFS301_FP_WIDTH = 200,
|
||||
|
||||
/* sizeof(fp_line_t) */
|
||||
VFS301_FP_FRAME_SIZE = 288,
|
||||
/* Width of output line */
|
||||
#ifndef OUTPUT_RAW
|
||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH,
|
||||
#else
|
||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE,
|
||||
#endif
|
||||
|
||||
VFS301_FP_SUM_LINES = 3,
|
||||
|
||||
#ifdef SCAN_FINISH_DETECTION
|
||||
/* TODO: The following changes (seen ~60 and ~80) In that
|
||||
* case we'll need to calibrate this from empty data somehow... */
|
||||
VFS301_FP_SUM_MEDIAN = 60,
|
||||
VFS301_FP_SUM_EMPTY_RANGE = 5,
|
||||
#endif
|
||||
|
||||
/* Minimum average difference between returned lines */
|
||||
VFS301_FP_LINE_DIFF_THRESHOLD = 15,
|
||||
|
||||
/* Maximum waiting time for a single fingerprint frame */
|
||||
VFS301_FP_RECV_TIMEOUT = 2000
|
||||
};
|
||||
|
||||
/* Arrays of this structure is returned during the initialization as a response
|
||||
* to the 0x02D0 messages.
|
||||
* It seems to be always the same - what is it for? Some kind of confirmation?
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char sync_0x01;
|
||||
unsigned char sync_0xfe;
|
||||
|
||||
unsigned char counter_lo;
|
||||
unsigned char counter_hi; /* FIXME ? */
|
||||
|
||||
unsigned char flags[3];
|
||||
|
||||
unsigned char sync_0x00;
|
||||
|
||||
unsigned char scan[VFS301_FP_WIDTH];
|
||||
} vfs301_init_line_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned char sync_0x01;
|
||||
unsigned char sync_0xfe;
|
||||
|
||||
unsigned char counter_lo;
|
||||
unsigned char counter_hi;
|
||||
|
||||
unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */
|
||||
/* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */
|
||||
unsigned char flag_1;
|
||||
unsigned char sync_0x00;
|
||||
|
||||
unsigned char scan[VFS301_FP_WIDTH];
|
||||
|
||||
/* A offseted, stretched, inverted copy of scan... probably could
|
||||
* serve finger motion speed detection?
|
||||
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
||||
unsigned char mirror[64];
|
||||
|
||||
/* Some kind of sum of the scan, very low contrast */
|
||||
unsigned char sum1[2];
|
||||
unsigned char sum2[11];
|
||||
unsigned char sum3[3];
|
||||
} vfs301_line_t;
|
||||
|
||||
void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
void vfs301_proto_deinit(struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
|
||||
void vfs301_proto_request_fingerprint(
|
||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
|
||||
/** returns 0 if no event is ready, or 1 if there is one... */
|
||||
int vfs301_proto_peek_event(
|
||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
void vfs301_proto_process_event_start(
|
||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
int vfs301_proto_process_event_poll(
|
||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
||||
|
||||
void vfs301_extract_image(vfs301_dev_t *vfs, unsigned char *output, int *output_height);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
315
libfprint/drivers/virtual-image.c
Normal file
315
libfprint/drivers/virtual-image.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Virtual driver for image device debugging
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the image based drivers. A small
|
||||
* python script is provided to connect to it via a socket, allowing
|
||||
* prints to be sent to this device programatically.
|
||||
* Using this it is possible to test libfprint and fprintd.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_image"
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "../fpi-image.h"
|
||||
#include "../fpi-image-device.h"
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixsocketaddress.h>
|
||||
|
||||
struct _FpDeviceVirtualImage
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
||||
GSocketListener *listener;
|
||||
GSocketConnection *connection;
|
||||
GCancellable *cancellable;
|
||||
|
||||
gint socket_fd;
|
||||
gint client_fd;
|
||||
|
||||
FpImage *recv_img;
|
||||
gint recv_img_hdr[2];
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
|
||||
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
|
||||
|
||||
static void start_listen (FpDeviceVirtualImage *dev);
|
||||
static void recv_image (FpDeviceVirtualImage *dev,
|
||||
GInputStream *stream);
|
||||
|
||||
static void
|
||||
recv_image_img_recv_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualImage *self;
|
||||
FpImageDevice *device;
|
||||
gboolean success;
|
||||
gsize bytes = 0;
|
||||
|
||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||
|
||||
if (!success || bytes == 0)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
g_warning ("Error receiving header for image data: %s", error->message);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
}
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
return;
|
||||
}
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
device = FP_IMAGE_DEVICE (self);
|
||||
|
||||
fpi_image_device_report_finger_status (device, TRUE);
|
||||
fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img));
|
||||
fpi_image_device_report_finger_status (device, FALSE);
|
||||
|
||||
/* And, listen for more images from the same client. */
|
||||
recv_image (self, G_INPUT_STREAM (source_object));
|
||||
}
|
||||
|
||||
static void
|
||||
recv_image_hdr_recv_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualImage *self;
|
||||
gboolean success;
|
||||
gsize bytes;
|
||||
|
||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||
|
||||
if (!success || bytes == 0)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
g_warning ("Error receiving header for image data: %s", error->message);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
}
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
return;
|
||||
}
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
|
||||
{
|
||||
g_warning ("Image header suggests an unrealistically large image, disconnecting client.");
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
}
|
||||
|
||||
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
||||
{
|
||||
switch (self->recv_img_hdr[0])
|
||||
{
|
||||
case -1:
|
||||
/* -1 is a retry error, just pass it through */
|
||||
fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), self->recv_img_hdr[1]);
|
||||
break;
|
||||
|
||||
case -2:
|
||||
/* -2 is a fatal error, just pass it through*/
|
||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (self),
|
||||
fpi_device_error_new (self->recv_img_hdr[1]));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* disconnect client, it didn't play fair */
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
}
|
||||
|
||||
/* And, listen for more images from the same client. */
|
||||
recv_image (self, G_INPUT_STREAM (source_object));
|
||||
return;
|
||||
}
|
||||
|
||||
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
|
||||
g_debug ("image data: %p", self->recv_img->data);
|
||||
g_input_stream_read_all_async (G_INPUT_STREAM (source_object),
|
||||
(guint8 *) self->recv_img->data,
|
||||
self->recv_img->width * self->recv_img->height,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
recv_image_img_recv_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
|
||||
{
|
||||
g_input_stream_read_all_async (stream,
|
||||
dev->recv_img_hdr,
|
||||
sizeof (dev->recv_img_hdr),
|
||||
G_PRIORITY_DEFAULT,
|
||||
dev->cancellable,
|
||||
recv_image_hdr_recv_cb,
|
||||
dev);
|
||||
}
|
||||
|
||||
static void
|
||||
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
GSocketConnection *connection;
|
||||
GInputStream *stream;
|
||||
FpDeviceVirtualImage *dev = user_data;
|
||||
|
||||
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
|
||||
res,
|
||||
NULL,
|
||||
&error);
|
||||
if (!connection)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
g_warning ("Error accepting a new connection: %s", error->message);
|
||||
start_listen (dev);
|
||||
}
|
||||
|
||||
/* Always further connections (but we disconnect them immediately
|
||||
* if we already have a connection). */
|
||||
start_listen (dev);
|
||||
if (dev->connection)
|
||||
{
|
||||
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
|
||||
g_object_unref (connection);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->connection = connection;
|
||||
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
|
||||
|
||||
recv_image (dev, stream);
|
||||
|
||||
fp_dbg ("Got a new connection!");
|
||||
}
|
||||
|
||||
static void
|
||||
start_listen (FpDeviceVirtualImage *dev)
|
||||
{
|
||||
g_socket_listener_accept_async (dev->listener,
|
||||
dev->cancellable,
|
||||
new_connection_cb,
|
||||
dev);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_init (FpImageDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GSocketListener) listener = NULL;
|
||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||
const char *env;
|
||||
g_autoptr(GSocketAddress) addr = NULL;
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->client_fd = -1;
|
||||
|
||||
env = fpi_device_get_virtual_env (FP_DEVICE (self));
|
||||
|
||||
listener = g_socket_listener_new ();
|
||||
g_socket_listener_set_backlog (listener, 1);
|
||||
|
||||
/* Remove any left over socket. */
|
||||
g_unlink (env);
|
||||
|
||||
addr = g_unix_socket_address_new (env);
|
||||
|
||||
if (!g_socket_listener_add_address (listener,
|
||||
addr,
|
||||
G_SOCKET_TYPE_STREAM,
|
||||
G_SOCKET_PROTOCOL_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Could not listen on unix socket: %s", error->message);
|
||||
|
||||
fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self->listener = g_steal_pointer (&listener);
|
||||
self->cancellable = g_cancellable_new ();
|
||||
|
||||
start_listen (self);
|
||||
|
||||
fpi_image_device_open_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_deinit (FpImageDevice *dev)
|
||||
{
|
||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
g_clear_object (&self->listener);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
fpi_image_device_close_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
|
||||
{
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_IMAGE" },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual image device for debugging";
|
||||
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
|
||||
dev_class->id_table = driver_ids;
|
||||
|
||||
img_class->img_open = dev_init;
|
||||
img_class->img_close = dev_deinit;
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Virtual driver for image device debugging
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the image based drivers. A small
|
||||
* python script is provided to connect to it via a socket, allowing
|
||||
* prints to be sent to this device programatically.
|
||||
* Using this it is possible to test libfprint and fprintd.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_imgdev"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include "drivers_api.h"
|
||||
|
||||
struct virt_dev {
|
||||
fpi_io_condition *socket_io_cond;
|
||||
fpi_io_condition *client_io_cond;
|
||||
|
||||
gint socket_fd;
|
||||
gint client_fd;
|
||||
|
||||
struct fp_img *recv_img;
|
||||
gssize recv_img_data_bytes;
|
||||
gssize recv_img_hdr_bytes;
|
||||
gint recv_img_hdr[2];
|
||||
};
|
||||
|
||||
static void
|
||||
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
gboolean nodata = FALSE;
|
||||
gssize len;
|
||||
|
||||
if (!virt->recv_img) {
|
||||
/* Reading the header, i.e. width/height. */
|
||||
len = read(fd,
|
||||
(guint8*)virt->recv_img_hdr + virt->recv_img_hdr_bytes,
|
||||
sizeof(virt->recv_img_hdr) - virt->recv_img_hdr_bytes);
|
||||
fp_dbg("Received %zi bytes from client!", len);
|
||||
|
||||
if (len > 0) {
|
||||
virt->recv_img_hdr_bytes += len;
|
||||
/* Got the full header, create an image for further processing. */
|
||||
if (virt->recv_img_hdr_bytes == sizeof(virt->recv_img_hdr)) {
|
||||
virt->recv_img_data_bytes = 0;
|
||||
virt->recv_img = fpi_img_new (virt->recv_img_hdr[0] * virt->recv_img_hdr[1]);
|
||||
virt->recv_img->width = virt->recv_img_hdr[0];
|
||||
virt->recv_img->height = virt->recv_img_hdr[1];
|
||||
virt->recv_img->flags = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
len = read(fd,
|
||||
(guint8*)virt->recv_img->data + virt->recv_img_data_bytes,
|
||||
virt->recv_img->length - virt->recv_img_data_bytes);
|
||||
fp_dbg("Received %zi bytes from client!", len);
|
||||
|
||||
if (len > 0) {
|
||||
virt->recv_img_data_bytes += len;
|
||||
if (virt->recv_img_data_bytes == virt->recv_img->length) {
|
||||
/* Submit received image to frontend */
|
||||
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), TRUE);
|
||||
fpi_imgdev_image_captured(FP_IMG_DEV (dev), virt->recv_img);
|
||||
virt->recv_img = NULL;
|
||||
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
fp_dbg("Client disconnected!");
|
||||
close (virt->client_fd);
|
||||
virt->client_fd = -1;
|
||||
|
||||
virt->recv_img_hdr_bytes = 0;
|
||||
if (virt->recv_img)
|
||||
fp_img_free (virt->recv_img);
|
||||
virt->recv_img = NULL;
|
||||
|
||||
fpi_io_condition_remove (virt->client_io_cond);
|
||||
virt->client_io_cond = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
int new_client_fd;
|
||||
|
||||
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
|
||||
fp_dbg("Got a new connection!");
|
||||
|
||||
/* Already have a connection, reject this one */
|
||||
if (virt->client_fd >= 0) {
|
||||
fp_warn("Rejecting new connection as we already have one!");
|
||||
close (new_client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
virt->client_fd = new_client_fd;
|
||||
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
struct virt_dev *virt;
|
||||
const char *env;
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX
|
||||
};
|
||||
G_DEBUG_HERE();
|
||||
|
||||
virt = g_new0(struct virt_dev, 1);
|
||||
fp_dev_set_instance_data(FP_DEV(dev), virt);
|
||||
|
||||
virt->client_fd = -1;
|
||||
|
||||
env = fpi_dev_get_virtual_env (FP_DEV (dev));
|
||||
|
||||
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||
if (virt->socket_fd < 0) {
|
||||
fp_err("Could not create socket: %m");
|
||||
return virt->socket_fd;
|
||||
}
|
||||
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
|
||||
|
||||
unlink(env);
|
||||
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
|
||||
fp_err("Could not bind address '%s': %m", addr.sun_path);
|
||||
close (virt->socket_fd);
|
||||
virt->socket_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (virt->socket_fd, 1) < 0) {
|
||||
fp_err("Could not open socket for listening: %m");
|
||||
close (virt->socket_fd);
|
||||
virt->socket_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, FP_DEV (dev), NULL);
|
||||
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->client_fd >= 0) {
|
||||
fpi_io_condition_remove (virt->client_io_cond);
|
||||
close (virt->client_fd);
|
||||
}
|
||||
|
||||
if (virt->socket_fd >= 0) {
|
||||
fpi_io_condition_remove (virt->socket_io_cond);
|
||||
close (virt->socket_fd);
|
||||
}
|
||||
|
||||
g_free(virt);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
fpi_imgdev_activate_complete (dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
fpi_imgdev_deactivate_complete (dev);
|
||||
}
|
||||
|
||||
struct fp_img_driver virtual_imgdev_driver = {
|
||||
.driver = {
|
||||
.id = VIRTUAL_IMG_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "Virtual image device for debugging",
|
||||
.bus = BUS_TYPE_VIRTUAL,
|
||||
.id_table.virtual_envvar = "FP_VIRTUAL_IMGDEV",
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
},
|
||||
.flags = 0,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = dev_activate,
|
||||
.deactivate = dev_deactivate,
|
||||
};
|
||||
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
* Virtual match-in-sensor device with internal storage
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug features that are relevant for
|
||||
* match-in-sensor (MIS) devices that store data on the sensor itself.
|
||||
* In this case data needs to be deleted both locally and from the device
|
||||
* and we should support garbage collection.
|
||||
*
|
||||
* The protocol is line based, when a verify/enroll/etc. command is started
|
||||
* (or is active when connecting) then we send the command and the UUID
|
||||
* terminated by a newline.
|
||||
*
|
||||
* IDLE\n
|
||||
* VERIFY UUID\n
|
||||
* ENROLL UUID\n
|
||||
* DELETE UUID\n (planned)
|
||||
* LIST (planned)
|
||||
*
|
||||
* The other end simply responds with an integer (terminated by newline)
|
||||
* that matches the internal fprint return codes.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_misdev"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include "drivers_api.h"
|
||||
#include "fpi-async.h"
|
||||
|
||||
#define VIRT_ENROLL_STAGES 1
|
||||
|
||||
enum virtdev_state {
|
||||
STATE_IDLE = 0,
|
||||
STATE_VERIFY,
|
||||
STATE_ENROLL,
|
||||
STATE_DELETE,
|
||||
};
|
||||
|
||||
struct virt_dev {
|
||||
enum virtdev_state state;
|
||||
|
||||
gchar *curr_uuid;
|
||||
|
||||
fpi_io_condition *socket_io_cond;
|
||||
fpi_io_condition *client_io_cond;
|
||||
|
||||
gint socket_fd;
|
||||
gint client_fd;
|
||||
|
||||
gssize recv_len;
|
||||
guchar *recv_buf;
|
||||
};
|
||||
|
||||
static void send_status(struct fp_dev *dev);
|
||||
|
||||
static void
|
||||
handle_response (struct fp_dev *dev, guchar *buf, gssize len)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
gint result = atoi ((gchar*) buf);
|
||||
|
||||
switch (virt->state) {
|
||||
case STATE_IDLE:
|
||||
fp_info ("Received unexpected status code %i\n", virt->state);
|
||||
break;
|
||||
case STATE_VERIFY:
|
||||
fp_info ("Reporting verify results back %i\n", result);
|
||||
fpi_drvcb_report_verify_result (dev, result, NULL);
|
||||
break;
|
||||
case STATE_ENROLL: {
|
||||
struct fp_print_data * fdata = NULL;
|
||||
|
||||
fp_info ("Reporting enroll results back %i\n", result);
|
||||
|
||||
/* If the enroll is "done", then report back the UUID for the print. */
|
||||
if (result == FP_ENROLL_COMPLETE) {
|
||||
struct fp_print_data_item *item = NULL;
|
||||
|
||||
fdata = fpi_print_data_new (dev);
|
||||
|
||||
item = fpi_print_data_item_new(strlen(virt->curr_uuid));
|
||||
memcpy(item->data, virt->curr_uuid, strlen(virt->curr_uuid));
|
||||
fpi_print_data_add_item(fdata, item);
|
||||
}
|
||||
|
||||
fpi_drvcb_enroll_stage_completed (dev, result, fdata, NULL);
|
||||
break;
|
||||
}
|
||||
case STATE_DELETE:
|
||||
fp_info ("Reporting delete results back %i\n", result);
|
||||
|
||||
virt->state = STATE_IDLE;
|
||||
g_free (virt->curr_uuid);
|
||||
virt->curr_uuid = NULL;
|
||||
|
||||
fpi_drvcb_delete_complete (dev, result);
|
||||
|
||||
send_status(dev);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_status(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
gchar *msg = NULL;
|
||||
|
||||
if (virt->client_fd < 0)
|
||||
return;
|
||||
|
||||
switch (virt->state) {
|
||||
case STATE_IDLE:
|
||||
msg = g_strdup ("IDLE\n");
|
||||
break;
|
||||
case STATE_ENROLL:
|
||||
msg = g_strdup_printf ("ENROLL %s\n", virt->curr_uuid);
|
||||
break;
|
||||
case STATE_VERIFY:
|
||||
msg = g_strdup_printf ("VERIFY %s\n", virt->curr_uuid);
|
||||
break;
|
||||
case STATE_DELETE:
|
||||
msg = g_strdup_printf ("DELETE %s\n", virt->curr_uuid);
|
||||
break;
|
||||
}
|
||||
|
||||
send(virt->client_fd, msg, strlen(msg), MSG_NOSIGNAL);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
static void
|
||||
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
guchar *pos;
|
||||
guchar buf[512];
|
||||
gssize len;
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
fp_dbg("Received %zi bytes from client!", len);
|
||||
|
||||
if (len > 0) {
|
||||
virt->recv_buf = g_realloc(virt->recv_buf, virt->recv_len + len);
|
||||
memcpy(virt->recv_buf + virt->recv_len, buf, len);
|
||||
virt->recv_len += len;
|
||||
|
||||
while ((pos = memmem(virt->recv_buf, virt->recv_len, "\n", 1))) {
|
||||
/* Found a newline, parse the command */
|
||||
fp_dbg("got a command response! %p %p", virt->recv_buf, pos);
|
||||
*pos = '\0';
|
||||
handle_response(dev, virt->recv_buf, pos - virt->recv_buf);
|
||||
|
||||
/* And remove the parsed part from the buffer */
|
||||
virt->recv_len = virt->recv_len - (pos - virt->recv_buf) - 1;
|
||||
memmove(pos, virt->recv_buf, virt->recv_len);
|
||||
virt->recv_buf = realloc(virt->recv_buf, virt->recv_len);
|
||||
}
|
||||
} else {
|
||||
fp_dbg("Client disconnected!");
|
||||
close (virt->client_fd);
|
||||
virt->client_fd = -1;
|
||||
|
||||
fpi_io_condition_remove (virt->client_io_cond);
|
||||
virt->client_io_cond = NULL;
|
||||
|
||||
g_free(virt->recv_buf);
|
||||
virt->recv_buf = NULL;
|
||||
virt->recv_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
int new_client_fd;
|
||||
|
||||
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
|
||||
fp_dbg("Got a new connection!");
|
||||
|
||||
/* Already have a connection, reject this one */
|
||||
if (virt->client_fd >= 0) {
|
||||
fp_warn("Rejecting new connection as we already have one!");
|
||||
close (new_client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
virt->client_fd = new_client_fd;
|
||||
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
|
||||
|
||||
send_status(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
struct virt_dev *virt;
|
||||
const char *env;
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX
|
||||
};
|
||||
G_DEBUG_HERE();
|
||||
|
||||
fpi_dev_set_nr_enroll_stages(dev, VIRT_ENROLL_STAGES);
|
||||
|
||||
virt = g_new0(struct virt_dev, 1);
|
||||
fp_dev_set_instance_data(dev, virt);
|
||||
|
||||
virt->client_fd = -1;
|
||||
|
||||
env = fpi_dev_get_virtual_env (dev);
|
||||
|
||||
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||
if (virt->socket_fd < 0) {
|
||||
fp_err("Could not create socket: %m");
|
||||
return virt->socket_fd;
|
||||
}
|
||||
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
|
||||
|
||||
unlink(env);
|
||||
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
|
||||
fp_err("Could not bind address '%s': %m", addr.sun_path);
|
||||
close (virt->socket_fd);
|
||||
virt->socket_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (virt->socket_fd, 1) < 0) {
|
||||
fp_err("Could not open socket for listening: %m");
|
||||
close (virt->socket_fd);
|
||||
virt->socket_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, dev, NULL);
|
||||
|
||||
fpi_drvcb_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->client_fd >= 0) {
|
||||
fpi_io_condition_remove (virt->client_io_cond);
|
||||
close (virt->client_fd);
|
||||
}
|
||||
|
||||
if (virt->socket_fd >= 0) {
|
||||
fpi_io_condition_remove (virt->socket_io_cond);
|
||||
close (virt->socket_fd);
|
||||
}
|
||||
|
||||
g_free (virt->curr_uuid);
|
||||
virt->curr_uuid = NULL;
|
||||
|
||||
g_free(virt);
|
||||
fpi_drvcb_close_complete(dev);
|
||||
}
|
||||
|
||||
static int enroll_start(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->state != STATE_IDLE)
|
||||
return -1;
|
||||
|
||||
g_assert (virt->curr_uuid == NULL);
|
||||
|
||||
virt->state = STATE_ENROLL;
|
||||
|
||||
virt->curr_uuid = g_uuid_string_random ();
|
||||
send_status(dev);
|
||||
|
||||
fpi_drvcb_enroll_started(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enroll_stop(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->state != STATE_ENROLL)
|
||||
return -1;
|
||||
|
||||
virt->state = STATE_IDLE;
|
||||
g_free (virt->curr_uuid);
|
||||
virt->curr_uuid = NULL;
|
||||
send_status(dev);
|
||||
|
||||
fpi_drvcb_enroll_stopped(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_start(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
struct fp_print_data *print;
|
||||
struct fp_print_data_item *item;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->state != STATE_IDLE)
|
||||
return -1;
|
||||
|
||||
g_assert (virt->curr_uuid == NULL);
|
||||
|
||||
virt->state = STATE_VERIFY;
|
||||
|
||||
print = fpi_dev_get_verify_data(dev);
|
||||
item = fpi_print_data_get_item(print);
|
||||
|
||||
/* We expecte a UUID, that means 36 bytes. */
|
||||
g_assert(item->length == 36);
|
||||
|
||||
virt->curr_uuid = g_malloc(37);
|
||||
virt->curr_uuid[36] = '\0';
|
||||
memcpy(virt->curr_uuid, item->data, 36);
|
||||
|
||||
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
|
||||
|
||||
send_status(dev);
|
||||
|
||||
fpi_drvcb_verify_started(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->state != STATE_VERIFY)
|
||||
return -1;
|
||||
|
||||
virt->state = STATE_IDLE;
|
||||
g_free (virt->curr_uuid);
|
||||
virt->curr_uuid = NULL;
|
||||
|
||||
send_status(dev);
|
||||
|
||||
fpi_drvcb_verify_stopped(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delete_finger(struct fp_dev *dev)
|
||||
{
|
||||
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
|
||||
struct fp_print_data *print;
|
||||
struct fp_print_data_item *item;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (virt->state != STATE_IDLE)
|
||||
return -1;
|
||||
|
||||
g_assert (virt->curr_uuid == NULL);
|
||||
|
||||
virt->state = STATE_DELETE;
|
||||
|
||||
print = fpi_dev_get_delete_data(dev);
|
||||
item = fpi_print_data_get_item(print);
|
||||
|
||||
/* We expecte a UUID, that means 36 bytes. */
|
||||
g_assert(item->length == 36);
|
||||
|
||||
virt->curr_uuid = g_malloc(37);
|
||||
virt->curr_uuid[36] = '\0';
|
||||
memcpy(virt->curr_uuid, item->data, 36);
|
||||
|
||||
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
|
||||
|
||||
send_status(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fp_driver virtual_misdev_driver = {
|
||||
.id = VIRTUAL_MIS_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "Virtual match-in-sensor device with internal storage",
|
||||
.bus = BUS_TYPE_VIRTUAL,
|
||||
.id_table.virtual_envvar = "FP_VIRTUAL_MISDEV",
|
||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.enroll_start = enroll_start,
|
||||
.enroll_stop = enroll_stop,
|
||||
.verify_start = verify_start,
|
||||
.verify_stop = verify_stop,
|
||||
.delete_finger = delete_finger,
|
||||
};
|
||||
@@ -23,17 +23,12 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "fprint.h"
|
||||
#include "fp_internal.h"
|
||||
|
||||
#include "fpi-log.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-dev-img.h"
|
||||
#include "fpi-core.h"
|
||||
#include "fpi-usb-transfer.h"
|
||||
#include "fpi-ssm.h"
|
||||
#include "fpi-poll.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-usb.h"
|
||||
#include "fpi-img.h"
|
||||
#include "fpi-assembling.h"
|
||||
#include "drivers/driver_ids.h"
|
||||
#include "fpi-image-device.h"
|
||||
|
||||
#endif
|
||||
|
||||
366
libfprint/fp-context.c
Normal file
366
libfprint/fp-context.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* FpContext - A FPrint context
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "context"
|
||||
#include <fpi-log.h>
|
||||
|
||||
#include "fpi-context.h"
|
||||
#include "fpi-device.h"
|
||||
#include <gusb.h>
|
||||
|
||||
/**
|
||||
* SECTION: fp-context
|
||||
* @title: FpContext
|
||||
* @short_description: Discover fingerprint devices
|
||||
*
|
||||
* The #FpContext allows you to discover fingerprint scanning hardware. This
|
||||
* is the starting point when integrating libfprint into your software.
|
||||
*
|
||||
* The <link linkend="device-added">device-added</link> and device-removed signals allow you to handle devices
|
||||
* that may be hotplugged at runtime.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GUsbContext *usb_ctx;
|
||||
GCancellable *cancellable;
|
||||
|
||||
gint pending_devices;
|
||||
gboolean enumerated;
|
||||
|
||||
GArray *drivers;
|
||||
GPtrArray *devices;
|
||||
} FpContextPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (FpContext, fp_context, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
DEVICE_ADDED_SIGNAL,
|
||||
DEVICE_REMOVED_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDevice *device;
|
||||
FpContext *context;
|
||||
FpContextPrivate *priv;
|
||||
|
||||
device = (FpDevice *) g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error);
|
||||
if (!device)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
context = FP_CONTEXT (user_data);
|
||||
priv = fp_context_get_instance_private (context);
|
||||
priv->pending_devices--;
|
||||
g_message ("Ignoring device due to initialization error: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
context = FP_CONTEXT (user_data);
|
||||
priv = fp_context_get_instance_private (context);
|
||||
priv->pending_devices--;
|
||||
g_ptr_array_add (priv->devices, device);
|
||||
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||
{
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||
GType found_driver = G_TYPE_NONE;
|
||||
const FpIdEntry *found_entry = NULL;
|
||||
gint found_score = 0;
|
||||
gint i;
|
||||
guint16 pid, vid;
|
||||
|
||||
pid = g_usb_device_get_pid (device);
|
||||
vid = g_usb_device_get_vid (device);
|
||||
|
||||
/* Find the best driver to handle this USB device. */
|
||||
for (i = 0; i < priv->drivers->len; i++)
|
||||
{
|
||||
GType driver = g_array_index (priv->drivers, GType, i);
|
||||
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||
const FpIdEntry *entry;
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
{
|
||||
g_type_class_unref (cls);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (entry = cls->id_table; entry->pid; entry++)
|
||||
{
|
||||
gint driver_score = 50;
|
||||
|
||||
if (entry->pid != pid || entry->vid != vid)
|
||||
continue;
|
||||
|
||||
if (cls->usb_discover)
|
||||
driver_score = cls->usb_discover (device);
|
||||
|
||||
/* Is this driver better than the one we had? */
|
||||
if (driver_score <= found_score)
|
||||
continue;
|
||||
|
||||
found_score = driver_score;
|
||||
found_driver = driver;
|
||||
found_entry = entry;
|
||||
}
|
||||
|
||||
g_type_class_unref (cls);
|
||||
}
|
||||
|
||||
if (found_driver == G_TYPE_NONE)
|
||||
{
|
||||
g_debug ("No driver found for USB device %04X:%04X", pid, vid);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->pending_devices++;
|
||||
g_async_initable_new_async (found_driver,
|
||||
G_PRIORITY_LOW,
|
||||
priv->cancellable,
|
||||
async_device_init_done_cb,
|
||||
self,
|
||||
"fp-usb-device", device,
|
||||
"fp-driver-data", found_entry->driver_data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||
{
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||
gint i;
|
||||
|
||||
/* Do the lazy way and just look at each device. */
|
||||
for (i = 0; i < priv->devices->len; i++)
|
||||
{
|
||||
FpDevice *dev = g_ptr_array_index (priv->devices, i);
|
||||
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (dev);
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
continue;
|
||||
|
||||
if (fpi_device_get_usb_device (dev) == device)
|
||||
{
|
||||
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
|
||||
g_ptr_array_remove_index_fast (priv->devices, i);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_context_finalize (GObject *object)
|
||||
{
|
||||
FpContext *self = (FpContext *) object;
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->devices, g_ptr_array_unref);
|
||||
|
||||
g_cancellable_cancel (priv->cancellable);
|
||||
g_clear_object (&priv->cancellable);
|
||||
g_clear_pointer (&priv->drivers, g_array_unref);
|
||||
|
||||
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
||||
g_clear_object (&priv->usb_ctx);
|
||||
|
||||
G_OBJECT_CLASS (fp_context_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_context_class_init (FpContextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_context_finalize;
|
||||
|
||||
/**
|
||||
* FpContext::device-added:
|
||||
* @context: the #FpContext instance that emitted the signal
|
||||
* @device: A #FpDevice
|
||||
*
|
||||
* This signal is emitted when a fingerprint reader is added.
|
||||
**/
|
||||
signals[DEVICE_ADDED_SIGNAL] = g_signal_new ("device-added",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (FpContextClass, device_added),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
FP_TYPE_DEVICE);
|
||||
|
||||
/**
|
||||
* FpContext::device-removed:
|
||||
* @context: the #FpContext instance that emitted the signal
|
||||
* @device: A #FpDevice
|
||||
*
|
||||
* This signal is emitted when a fingerprint reader is removed.
|
||||
**/
|
||||
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (FpContextClass, device_removed),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
FP_TYPE_DEVICE);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_context_init (FpContext *self)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||
|
||||
priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType));
|
||||
fpi_get_driver_types (priv->drivers);
|
||||
|
||||
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
priv->cancellable = g_cancellable_new ();
|
||||
priv->usb_ctx = g_usb_context_new (&error);
|
||||
if (!priv->usb_ctx)
|
||||
{
|
||||
fp_warn ("Could not initialise USB Subsystem: %s", error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_usb_context_set_debug (priv->usb_ctx, G_LOG_LEVEL_INFO);
|
||||
g_signal_connect_object (priv->usb_ctx,
|
||||
"device-added",
|
||||
G_CALLBACK (usb_device_added_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (priv->usb_ctx,
|
||||
"device-removed",
|
||||
G_CALLBACK (usb_device_removed_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_context_new:
|
||||
*
|
||||
* Create a new #FpContext.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #FpContext
|
||||
*/
|
||||
FpContext *
|
||||
fp_context_new (void)
|
||||
{
|
||||
return g_object_new (FP_TYPE_CONTEXT, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_context_enumerate:
|
||||
* @context: a #FpContext
|
||||
*
|
||||
* Enumerate all devices. You should call this function exactly once
|
||||
* at startup. Please note that it iterates the mainloop until all
|
||||
* devices are enumerated.
|
||||
*/
|
||||
void
|
||||
fp_context_enumerate (FpContext *context)
|
||||
{
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (context);
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (FP_IS_CONTEXT (context));
|
||||
|
||||
if (priv->enumerated)
|
||||
return;
|
||||
|
||||
priv->enumerated = TRUE;
|
||||
|
||||
/* USB devices are handled from callbacks */
|
||||
g_usb_context_enumerate (priv->usb_ctx);
|
||||
|
||||
/* Handle Virtual devices based on environment variables */
|
||||
for (i = 0; i < priv->drivers->len; i++)
|
||||
{
|
||||
GType driver = g_array_index (priv->drivers, GType, i);
|
||||
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||
const FpIdEntry *entry;
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
|
||||
continue;
|
||||
|
||||
for (entry = cls->id_table; entry->pid; entry++)
|
||||
{
|
||||
const gchar *val;
|
||||
|
||||
val = g_getenv (entry->virtual_envvar);
|
||||
if (!val || val[0] == '\0')
|
||||
continue;
|
||||
|
||||
g_debug ("Found virtual environment device: %s, %s", entry->virtual_envvar, val);
|
||||
priv->pending_devices++;
|
||||
g_async_initable_new_async (driver,
|
||||
G_PRIORITY_LOW,
|
||||
priv->cancellable,
|
||||
async_device_init_done_cb,
|
||||
context,
|
||||
"fp-environ", val,
|
||||
"fp-driver-data", entry->driver_data,
|
||||
NULL);
|
||||
g_debug ("created");
|
||||
}
|
||||
|
||||
g_type_class_unref (cls);
|
||||
}
|
||||
|
||||
while (priv->pending_devices)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_context_get_devices:
|
||||
* @context: a #FpContext
|
||||
*
|
||||
* Get all devices. fp_context_enumerate() will be called as needed.
|
||||
*
|
||||
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's.
|
||||
*/
|
||||
GPtrArray *
|
||||
fp_context_get_devices (FpContext *context)
|
||||
{
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (FP_IS_CONTEXT (context), NULL);
|
||||
|
||||
fp_context_enumerate (context);
|
||||
|
||||
return priv->devices;
|
||||
}
|
||||
52
libfprint/fp-context.h
Normal file
52
libfprint/fp-context.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* FpContext - A FPrint context
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fp-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_CONTEXT (fp_context_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpContext, fp_context, FP, CONTEXT, GObject)
|
||||
|
||||
/**
|
||||
* FpContextClass:
|
||||
* @device_added: Called when a new device is added
|
||||
* @device_removed: Called when a device is removed
|
||||
*
|
||||
* Class structure for #FpContext instances.
|
||||
*/
|
||||
struct _FpContextClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*device_added) (FpContext *context,
|
||||
FpDevice *device);
|
||||
void (*device_removed) (FpContext *context,
|
||||
FpDevice *device);
|
||||
};
|
||||
|
||||
FpContext *fp_context_new (void);
|
||||
|
||||
void fp_context_enumerate (FpContext *context);
|
||||
|
||||
GPtrArray *fp_context_get_devices (FpContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
2608
libfprint/fp-device.c
Normal file
2608
libfprint/fp-device.c
Normal file
File diff suppressed because it is too large
Load Diff
255
libfprint/fp-device.h
Normal file
255
libfprint/fp-device.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* FpDevice - A fingerprint reader device
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fp-image.h"
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_DEVICE (fp_device_get_type ())
|
||||
#define FP_DEVICE_RETRY (fp_device_retry_quark ())
|
||||
#define FP_DEVICE_ERROR (fp_device_error_quark ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
||||
|
||||
#include "fp-print.h"
|
||||
|
||||
/* NOTE: We keep the class struct private! */
|
||||
|
||||
/**
|
||||
* FpDeviceType:
|
||||
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
||||
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||
*/
|
||||
typedef enum {
|
||||
FP_DEVICE_TYPE_VIRTUAL,
|
||||
FP_DEVICE_TYPE_USB,
|
||||
} FpDeviceType;
|
||||
|
||||
/**
|
||||
* FpScanType:
|
||||
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
||||
* @FP_SCAN_TYPE_PRESS: Sensor requires placing/pressing down the finger.
|
||||
*/
|
||||
typedef enum {
|
||||
FP_SCAN_TYPE_SWIPE,
|
||||
FP_SCAN_TYPE_PRESS,
|
||||
} FpScanType;
|
||||
|
||||
/**
|
||||
* FpDeviceRetry:
|
||||
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
||||
* or other general user scanning problem.
|
||||
* @FP_DEVICE_RETRY_TOO_SHORT: The scan did not succeed because the finger
|
||||
* swipe was too short.
|
||||
* @FP_DEVICE_RETRY_CENTER_FINGER: The scan did not succeed because the finger
|
||||
* was not centered on the scanner.
|
||||
* @FP_DEVICE_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or
|
||||
* pressure problems; the user should remove their finger from the scanner
|
||||
* before retrying.
|
||||
*
|
||||
* Error codes representing scan failures resulting in the user needing to
|
||||
* retry.
|
||||
*/
|
||||
typedef enum {
|
||||
FP_DEVICE_RETRY_GENERAL,
|
||||
FP_DEVICE_RETRY_TOO_SHORT,
|
||||
FP_DEVICE_RETRY_CENTER_FINGER,
|
||||
FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||
} FpDeviceRetry;
|
||||
|
||||
/**
|
||||
* FpDeviceError:
|
||||
* @FP_DEVICE_ERROR_GENERAL: A general error occured.
|
||||
* @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested
|
||||
* operation.
|
||||
* @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this
|
||||
* operation.
|
||||
* @FP_DEVICE_ERROR_ALREADY_OPEN: The device has already been opened.
|
||||
* @FP_DEVICE_ERROR_BUSY: The device is busy with another request.
|
||||
* @FP_DEVICE_ERROR_PROTO: Protocol error
|
||||
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
||||
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
|
||||
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
|
||||
*
|
||||
* Error codes for device operations. More specific errors from other domains
|
||||
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||
*/
|
||||
typedef enum {
|
||||
FP_DEVICE_ERROR_GENERAL,
|
||||
FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||
FP_DEVICE_ERROR_NOT_OPEN,
|
||||
FP_DEVICE_ERROR_ALREADY_OPEN,
|
||||
FP_DEVICE_ERROR_BUSY,
|
||||
FP_DEVICE_ERROR_PROTO,
|
||||
FP_DEVICE_ERROR_DATA_INVALID,
|
||||
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
||||
FP_DEVICE_ERROR_DATA_FULL,
|
||||
} FpDeviceError;
|
||||
|
||||
GQuark fp_device_retry_quark (void);
|
||||
GQuark fp_device_error_quark (void);
|
||||
|
||||
/**
|
||||
* FpEnrollProgress:
|
||||
* @device: a #FpDevice
|
||||
* @completed_stages: Number of completed stages
|
||||
* @print: (nullable) (transfer none): The last scaned print
|
||||
* @user_data: (nullable) (transfer none): User provided data
|
||||
* @error: (nullable) (transfer none): #GError or %NULL
|
||||
*
|
||||
* The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set.
|
||||
*/
|
||||
typedef void (*FpEnrollProgress) (FpDevice *device,
|
||||
gint completed_stages,
|
||||
FpPrint *print,
|
||||
gpointer user_data,
|
||||
GError *error);
|
||||
|
||||
|
||||
const gchar *fp_device_get_driver (FpDevice *device);
|
||||
const gchar *fp_device_get_device_id (FpDevice *device);
|
||||
const gchar *fp_device_get_name (FpDevice *device);
|
||||
FpScanType fp_device_get_scan_type (FpDevice *device);
|
||||
gint fp_device_get_nr_enroll_stages (FpDevice *device);
|
||||
|
||||
gboolean fp_device_supports_identify (FpDevice *device);
|
||||
gboolean fp_device_supports_capture (FpDevice *device);
|
||||
gboolean fp_device_has_storage (FpDevice *device);
|
||||
|
||||
/* Opening the device */
|
||||
void fp_device_open (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_close (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_enroll (FpDevice *device,
|
||||
FpPrint *template_print,
|
||||
GCancellable *cancellable,
|
||||
FpEnrollProgress progress_cb,
|
||||
gpointer progress_data,
|
||||
GDestroyNotify progress_destroy,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_verify (FpDevice *device,
|
||||
FpPrint *enrolled_print,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_identify (FpDevice *device,
|
||||
GPtrArray *prints,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_capture (FpDevice *device,
|
||||
gboolean wait_for_finger,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_delete_print (FpDevice *device,
|
||||
FpPrint *enrolled_print,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void fp_device_list_prints (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean fp_device_open_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
gboolean fp_device_close_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
FpPrint *fp_device_enroll_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
gboolean fp_device_verify_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
gboolean *match,
|
||||
FpPrint **print,
|
||||
GError **error);
|
||||
gboolean fp_device_identify_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
FpPrint **match,
|
||||
FpPrint **print,
|
||||
GError **error);
|
||||
FpImage * fp_device_capture_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
gboolean fp_device_delete_print_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
|
||||
gboolean fp_device_open_sync (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean fp_device_close_sync (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
FpPrint * fp_device_enroll_sync (FpDevice *device,
|
||||
FpPrint *template_print,
|
||||
GCancellable *cancellable,
|
||||
FpEnrollProgress progress_cb,
|
||||
gpointer progress_data,
|
||||
GError **error);
|
||||
gboolean fp_device_verify_sync (FpDevice *device,
|
||||
FpPrint *enrolled_print,
|
||||
GCancellable *cancellable,
|
||||
gboolean *match,
|
||||
FpPrint **print,
|
||||
GError **error);
|
||||
gboolean fp_device_identify_sync (FpDevice *device,
|
||||
GPtrArray *prints,
|
||||
GCancellable *cancellable,
|
||||
FpPrint **match,
|
||||
FpPrint **print,
|
||||
GError **error);
|
||||
FpImage * fp_device_capture_sync (FpDevice *device,
|
||||
gboolean wait_for_finger,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean fp_device_delete_print_sync (FpDevice *device,
|
||||
FpPrint *enrolled_print,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
846
libfprint/fp-image-device.c
Normal file
846
libfprint/fp-image-device.c
Normal file
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
* FpImageDevice - An image based fingerprint reader device
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "image_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fpi-image-device.h"
|
||||
#include "fpi-enums.h"
|
||||
#include "fpi-print.h"
|
||||
#include "fpi-image.h"
|
||||
|
||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||
#define IMG_ENROLL_STAGES 5
|
||||
|
||||
/**
|
||||
* SECTION: fp-image-device
|
||||
* @title: FpImageDevice
|
||||
* @short_description: Image device subclass
|
||||
*
|
||||
* This is a helper class for the commonly found image based devices.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION: fpi-image-device
|
||||
* @title: Internal FpImageDevice
|
||||
* @short_description: Internal image device routines
|
||||
*
|
||||
* See #FpImageDeviceClass for more details. Also see the public
|
||||
* #FpImageDevice routines.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FpImageDeviceState state;
|
||||
gboolean active;
|
||||
|
||||
gint enroll_stage;
|
||||
|
||||
guint pending_activation_timeout_id;
|
||||
gboolean pending_activation_timeout_waiting_finger_off;
|
||||
|
||||
gint bz3_threshold;
|
||||
} FpImageDevicePrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_FPI_STATE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
enum {
|
||||
FPI_STATE_CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* TODO:
|
||||
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
||||
**/
|
||||
|
||||
/* Static helper functions */
|
||||
|
||||
static void
|
||||
fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
/* Cannot change to inactive using this function. */
|
||||
g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
|
||||
/* We might have been waiting for the finger to go OFF to start the
|
||||
* next operation. */
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
|
||||
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
|
||||
|
||||
priv->state = state;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
||||
g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->state);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_activate (FpImageDevice *self)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_assert (!priv->active);
|
||||
|
||||
/* We don't have a neutral ACTIVE state, but we always will
|
||||
* go into WAIT_FINGER_ON afterwards. */
|
||||
priv->state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
||||
|
||||
/* We might have been waiting for deactivation to finish before
|
||||
* starting the next operation. */
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
|
||||
fp_dbg ("Activating image device\n");
|
||||
cls->activate (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_deactivate (FpDevice *device)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||
|
||||
if (!priv->active)
|
||||
{
|
||||
/* XXX: We currently deactivate both from minutiae scan result
|
||||
* and finger off report. */
|
||||
fp_dbg ("Already deactivated, ignoring request.");
|
||||
return;
|
||||
}
|
||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
||||
|
||||
fp_dbg ("Deactivating image device\n");
|
||||
cls->deactivate (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pending_activation_timeout (gpointer user_data)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
priv->pending_activation_timeout_id = 0;
|
||||
|
||||
if (priv->pending_activation_timeout_waiting_finger_off)
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||
"Remove finger before requesting another scan operation"));
|
||||
else
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/* Callbacks/vfuncs */
|
||||
static void
|
||||
fp_image_device_open (FpDevice *device)
|
||||
{
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||
|
||||
/* Nothing special about opening an image device, just
|
||||
* forward the request. */
|
||||
cls->img_open (FP_IMAGE_DEVICE (device));
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_close (FpDevice *device)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
/* In the close case we may need to wait/force deactivation first.
|
||||
* Three possible cases:
|
||||
* 1. We are inactive
|
||||
* -> immediately close
|
||||
* 2. We are waiting for finger off
|
||||
* -> imediately deactivate
|
||||
* 3. We are deactivating
|
||||
* -> handled by deactivate_complete */
|
||||
|
||||
if (!priv->active)
|
||||
cls->img_close (self);
|
||||
else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
fp_image_device_deactivate (device);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_cancel_action (FpDevice *device)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||
FpDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (device);
|
||||
|
||||
/* We can only cancel capture operations, in that case, deactivate and return
|
||||
* an error immediately. */
|
||||
if (action == FP_DEVICE_ACTION_ENROLL ||
|
||||
action == FP_DEVICE_ACTION_VERIFY ||
|
||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FP_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
fp_image_device_deactivate (FP_DEVICE (self));
|
||||
|
||||
/* XXX: Some nicer way of doing this would be good. */
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
g_error_new (G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED,
|
||||
"Device operation was cancelled"));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_start_capture_action (FpDevice *device)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
/* There is just one action that we cannot support out
|
||||
* of the box, which is a capture without first waiting
|
||||
* for a finger to be on the device.
|
||||
*/
|
||||
action = fpi_device_get_current_action (device);
|
||||
if (action == FP_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
gboolean wait_for_finger;
|
||||
|
||||
fpi_device_get_capture_data (device, &wait_for_finger);
|
||||
|
||||
if (!wait_for_finger)
|
||||
{
|
||||
fpi_device_action_error (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (action == FP_DEVICE_ACTION_ENROLL)
|
||||
{
|
||||
FpPrint *enroll_print = NULL;
|
||||
|
||||
fpi_device_get_enroll_data (device, &enroll_print);
|
||||
fpi_print_set_type (enroll_print, FP_PRINT_NBIS);
|
||||
}
|
||||
|
||||
priv->enroll_stage = 0;
|
||||
|
||||
/* The device might still be deactivating from a previous call.
|
||||
* In that situation, try to wait for a bit before reporting back an
|
||||
* error (which will usually say that the user should remove the
|
||||
* finger).
|
||||
*/
|
||||
if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
|
||||
{
|
||||
g_debug ("Got a new request while the device was still active");
|
||||
g_assert (priv->pending_activation_timeout_id == 0);
|
||||
priv->pending_activation_timeout_id =
|
||||
g_timeout_add (100, pending_activation_timeout, device);
|
||||
|
||||
if (priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
priv->pending_activation_timeout_waiting_finger_off = TRUE;
|
||||
else
|
||||
priv->pending_activation_timeout_waiting_finger_off = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
||||
* to be called when done (or immediately). */
|
||||
fp_image_device_activate (self);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
static void
|
||||
fp_image_device_finalize (GObject *object)
|
||||
{
|
||||
FpImageDevice *self = (FpImageDevice *) object;
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
g_assert (priv->active == FALSE);
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_default_activate (FpImageDevice *self)
|
||||
{
|
||||
fpi_image_device_activate_complete (self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_default_deactivate (FpImageDevice *self)
|
||||
{
|
||||
fpi_image_device_deactivate_complete (self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (object);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FPI_STATE:
|
||||
g_value_set_enum (value, priv->state);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_image_device_finalize;
|
||||
object_class->get_property = fp_image_device_get_property;
|
||||
|
||||
fp_device_class->open = fp_image_device_open;
|
||||
fp_device_class->close = fp_image_device_close;
|
||||
fp_device_class->enroll = fp_image_device_start_capture_action;
|
||||
fp_device_class->verify = fp_image_device_start_capture_action;
|
||||
fp_device_class->identify = fp_image_device_start_capture_action;
|
||||
fp_device_class->capture = fp_image_device_start_capture_action;
|
||||
|
||||
fp_device_class->cancel = fp_image_device_cancel_action;
|
||||
|
||||
/* Default implementations */
|
||||
klass->activate = fp_image_device_default_activate;
|
||||
klass->deactivate = fp_image_device_default_deactivate;
|
||||
|
||||
properties[PROP_FPI_STATE] =
|
||||
g_param_spec_enum ("fp-image-device-state",
|
||||
"Image Device State",
|
||||
"Private: The state of the image device",
|
||||
FP_TYPE_IMAGE_DEVICE_STATE,
|
||||
FP_IMAGE_DEVICE_STATE_INACTIVE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
signals[FPI_STATE_CHANGED] =
|
||||
g_signal_new ("fp-image-device-state-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_init (FpImageDevice *self)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
|
||||
/* Set default values. */
|
||||
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
|
||||
|
||||
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
||||
if (cls->bz3_threshold > 0)
|
||||
priv->bz3_threshold = cls->bz3_threshold;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
g_autoptr(FpImage) image = FP_IMAGE (source_object);
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
GError *error = NULL;
|
||||
FpDevice *device = FP_DEVICE (user_data);
|
||||
FpImageDevicePrivate *priv;
|
||||
FpDeviceAction action;
|
||||
|
||||
/* Note: We rely on the device to not disappear during an operation. */
|
||||
|
||||
if (!fp_image_detect_minutiae_finish (image, res, &error))
|
||||
{
|
||||
/* Cancel operation . */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
fpi_device_action_error (device, g_steal_pointer (&error));
|
||||
fp_image_device_deactivate (device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace error with a retry condition. */
|
||||
g_warning ("Failed to detect minutiae: %s", error->message);
|
||||
g_clear_pointer (&error, g_error_free);
|
||||
|
||||
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
|
||||
}
|
||||
|
||||
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
||||
action = fpi_device_get_current_action (device);
|
||||
|
||||
if (action == FP_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
|
||||
fp_image_device_deactivate (device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
print = fp_print_new (device);
|
||||
fpi_print_set_type (print, FP_PRINT_NBIS);
|
||||
if (!fpi_print_add_from_image (print, image, &error))
|
||||
g_clear_object (&print);
|
||||
}
|
||||
|
||||
if (action == FP_DEVICE_ACTION_ENROLL)
|
||||
{
|
||||
FpPrint *enroll_print;
|
||||
fpi_device_get_enroll_data (device, &enroll_print);
|
||||
|
||||
if (print)
|
||||
{
|
||||
fpi_print_add_print (enroll_print, print);
|
||||
priv->enroll_stage += 1;
|
||||
}
|
||||
|
||||
fpi_device_enroll_progress (device, priv->enroll_stage,
|
||||
g_steal_pointer (&print), error);
|
||||
|
||||
if (priv->enroll_stage == IMG_ENROLL_STAGES)
|
||||
{
|
||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||
fp_image_device_deactivate (device);
|
||||
}
|
||||
}
|
||||
else if (action == FP_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
FpPrint *template;
|
||||
FpiMatchResult result;
|
||||
|
||||
fpi_device_get_verify_data (device, &template);
|
||||
if (print)
|
||||
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
|
||||
else
|
||||
result = FPI_MATCH_ERROR;
|
||||
|
||||
fpi_device_verify_complete (device, result, g_steal_pointer (&print), error);
|
||||
fp_image_device_deactivate (device);
|
||||
}
|
||||
else if (action == FP_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
gint i;
|
||||
GPtrArray *templates;
|
||||
FpPrint *result = NULL;
|
||||
|
||||
fpi_device_get_identify_data (device, &templates);
|
||||
for (i = 0; !error && i < templates->len; i++)
|
||||
{
|
||||
FpPrint *template = g_ptr_array_index (templates, i);
|
||||
|
||||
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
|
||||
{
|
||||
result = g_object_ref (template);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fpi_device_identify_complete (device, result, g_steal_pointer (&print), error);
|
||||
fp_image_device_deactivate (device);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX: This can be hit currently due to a race condition in the enroll code!
|
||||
* In that case we scan a further image even though the minutiae for the previous
|
||||
* one have not yet been detected.
|
||||
* We need to keep track on the pending minutiae detection and the fact that
|
||||
* it will finish eventually (or we may need to retry on error and activate the
|
||||
* device again). */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/* Private API */
|
||||
|
||||
/**
|
||||
* fpi_image_device_set_bz3_threshold:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @bz3_threshold: BZ3 threshold to use
|
||||
*
|
||||
* Dynamically adjust the bz3 threshold. This is only needed for drivers
|
||||
* that support devices with different properties. It should generally be
|
||||
* called from the probe callback, but is acceptable to call from the open
|
||||
* callback.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
|
||||
gint bz3_threshold)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
|
||||
g_return_if_fail (bz3_threshold > 0);
|
||||
|
||||
priv->bz3_threshold = bz3_threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_report_finger_status:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @present: whether the finger is present on the sensor
|
||||
*
|
||||
* Reports from the driver whether the user's finger is on
|
||||
* the sensor.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||
gboolean present)
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
{
|
||||
/* Do we really want to always ignore such reports? We could
|
||||
* also track the state in case the user had the finger on
|
||||
* the device at initialisation time and the driver reports
|
||||
* this early.
|
||||
*/
|
||||
g_debug ("Ignoring finger presence report as the device is not active!");
|
||||
return;
|
||||
}
|
||||
|
||||
action = fpi_device_get_current_action (device);
|
||||
|
||||
g_assert (action != FP_DEVICE_ACTION_OPEN);
|
||||
g_assert (action != FP_DEVICE_ACTION_CLOSE);
|
||||
|
||||
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
||||
|
||||
if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
{
|
||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE);
|
||||
}
|
||||
else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
{
|
||||
/* We need to deactivate or continue to await finger */
|
||||
|
||||
/* There are three possible situations:
|
||||
* 1. We are deactivating the device and the action is still in progress
|
||||
* (minutiae detection).
|
||||
* 2. We are still deactivating the device after an action completed
|
||||
* 3. We were waiting for finger removal to start the new action
|
||||
* Either way, we always end up deactivating except for the enroll case.
|
||||
* XXX: This is not quite correct though, as we assume we need another finger
|
||||
* scan even though we might be processing the last one (successfully).
|
||||
*/
|
||||
if (action != FP_DEVICE_ACTION_ENROLL)
|
||||
fp_image_device_deactivate (device);
|
||||
else
|
||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_image_captured:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @image: whether the finger is present on the sensor
|
||||
*
|
||||
* Reports an image capture. Only use this function if the image was
|
||||
* captured successfully. If there was an issue where the user should
|
||||
* retry, use fpi_image_device_retry_scan() to report the retry condition.
|
||||
*
|
||||
* In the event of a fatal error for the operation use
|
||||
* fpi_image_device_session_error(). This will abort the entire operation
|
||||
* including e.g. an enroll operation which captures multiple images during
|
||||
* one session.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (image != NULL);
|
||||
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE);
|
||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||
action == FP_DEVICE_ACTION_VERIFY ||
|
||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FP_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||
|
||||
g_debug ("Image device captured an image");
|
||||
|
||||
/* XXX: We also detect minutiae in capture mode, we solely do this
|
||||
* to normalize the image which will happen as a by-product. */
|
||||
fp_image_detect_minutiae (image,
|
||||
fpi_device_get_cancellable (FP_DEVICE (self)),
|
||||
fpi_image_device_minutiae_detected,
|
||||
self);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_retry_scan:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @retry: The #FpDeviceRetry error code to report
|
||||
*
|
||||
* Reports a scan failure to the user. This may or may not abort the
|
||||
* current session. It is the equivalent of fpi_image_device_image_captured()
|
||||
* in the case of a retryable error condition (e.g. short swipe).
|
||||
*/
|
||||
void
|
||||
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
GError *error;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
/* We might be waiting for a finger at this point, so just accept
|
||||
* all but INACTIVE */
|
||||
g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||
action == FP_DEVICE_ACTION_VERIFY ||
|
||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FP_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
error = fpi_device_retry_new (retry);
|
||||
|
||||
if (action == FP_DEVICE_ACTION_ENROLL)
|
||||
{
|
||||
g_debug ("Reporting retry during enroll");
|
||||
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We abort the operation and let the surrounding code retry in the
|
||||
* non-enroll case (this is identical to a session error). */
|
||||
g_debug ("Abort current operation due to retry (non-enroll case)");
|
||||
fp_image_device_deactivate (FP_DEVICE (self));
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_session_error:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @error: The #GError to report
|
||||
*
|
||||
* Report an error while interacting with the device. This effectively
|
||||
* aborts the current ongoing action.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_session_error (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (self);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
g_warning ("Driver did not provide an error, generating a generic one");
|
||||
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
|
||||
}
|
||||
|
||||
if (!priv->active)
|
||||
{
|
||||
FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
g_warning ("Driver reported session error, but device is inactive.");
|
||||
|
||||
if (action != FP_DEVICE_ACTION_NONE)
|
||||
{
|
||||
g_warning ("Translating to activation failure!");
|
||||
fpi_image_device_activate_complete (self, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
{
|
||||
g_warning ("Driver reported session error; translating to deactivation failure.");
|
||||
fpi_image_device_deactivate_complete (self, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error->domain == FP_DEVICE_RETRY)
|
||||
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
||||
|
||||
fp_image_device_deactivate (FP_DEVICE (self));
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_activate_complete:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of device activation.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (priv->active == FALSE);
|
||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||
action == FP_DEVICE_ACTION_VERIFY ||
|
||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FP_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_debug ("Image device activation failed");
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_debug ("Image device activation completed");
|
||||
|
||||
priv->active = TRUE;
|
||||
|
||||
/* We always want to capture at this point, move to AWAIT_FINGER
|
||||
* state. */
|
||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_deactivate_complete:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of device deactivation.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
g_return_if_fail (priv->active == TRUE);
|
||||
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
|
||||
g_debug ("Image device deactivation completed");
|
||||
|
||||
priv->active = FALSE;
|
||||
|
||||
/* Deactivation completed. As we deactivate in the background
|
||||
* there may already be a new task pending. Check whether we
|
||||
* need to do anything. */
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
/* Special case, if we should be closing, but didn't due to a running
|
||||
* deactivation, then do so now. */
|
||||
if (action == FP_DEVICE_ACTION_CLOSE)
|
||||
{
|
||||
cls->img_close (self);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We might be waiting to be able to activate again. */
|
||||
if (priv->pending_activation_timeout_id)
|
||||
{
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
priv->pending_activation_timeout_id =
|
||||
g_idle_add ((GSourceFunc) fp_image_device_activate, self);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_open_complete:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of open operation.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (priv->active == FALSE);
|
||||
g_return_if_fail (action == FP_DEVICE_ACTION_OPEN);
|
||||
|
||||
g_debug ("Image device open completed");
|
||||
|
||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_image_device_close_complete:
|
||||
* @self: a #FpImageDevice imaging fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of close operation.
|
||||
*/
|
||||
void
|
||||
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_debug ("Image device close completed");
|
||||
|
||||
g_return_if_fail (priv->active == FALSE);
|
||||
g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE);
|
||||
|
||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
||||
|
||||
fpi_device_close_complete (FP_DEVICE (self), error);
|
||||
}
|
||||
29
libfprint/fp-image-device.h
Normal file
29
libfprint/fp-image-device.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* FpImageDevice - An image based fingerprint reader device
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fp-device.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_IMAGE_DEVICE (fp_image_device_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpImageDevice, fp_image_device, FP, IMAGE_DEVICE, FpDevice)
|
||||
|
||||
G_END_DECLS
|
||||
610
libfprint/fp-image.c
Normal file
610
libfprint/fp-image.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
* FPrint Image
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fpi-image.h"
|
||||
|
||||
#include "nbis/include/lfs.h"
|
||||
|
||||
#if HAVE_PIXMAN
|
||||
#include <pixman.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION: fp-image
|
||||
* @title: FpImage
|
||||
* @short_description: Internal Image handling routines
|
||||
*
|
||||
* Some devices will provide the image data corresponding to a print
|
||||
* this object allows accessing this data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION: fpi-image
|
||||
* @title: Internal FpImage
|
||||
* @short_description: Internal image handling routines
|
||||
*
|
||||
* Internal image handling routines. Also see the public <ulink
|
||||
* url="libfprint-FpImage.html">FpImage routines</ulink>.
|
||||
*/
|
||||
|
||||
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
FpImage *
|
||||
fp_image_new (gint width, gint height)
|
||||
{
|
||||
return g_object_new (FP_TYPE_IMAGE,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_finalize (GObject *object)
|
||||
{
|
||||
FpImage *self = (FpImage *) object;
|
||||
|
||||
g_clear_pointer (&self->data, g_free);
|
||||
g_clear_pointer (&self->binarized, g_free);
|
||||
g_clear_pointer (&self->minutiae, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (fp_image_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_constructed (GObject *object)
|
||||
{
|
||||
FpImage *self = (FpImage *) object;
|
||||
|
||||
self->data = g_malloc0 (self->width * self->height);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpImage *self = FP_IMAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WIDTH:
|
||||
g_value_set_uint (value, self->width);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_uint (value, self->height);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpImage *self = FP_IMAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WIDTH:
|
||||
self->width = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
self->height = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_class_init (FpImageClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_image_finalize;
|
||||
object_class->constructed = fp_image_constructed;
|
||||
object_class->set_property = fp_image_set_property;
|
||||
object_class->get_property = fp_image_get_property;
|
||||
|
||||
properties[PROP_WIDTH] =
|
||||
g_param_spec_uint ("width",
|
||||
"Width",
|
||||
"The width of the image",
|
||||
0,
|
||||
G_MAXUINT16,
|
||||
0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
properties[PROP_HEIGHT] =
|
||||
g_param_spec_uint ("height",
|
||||
"Height",
|
||||
"The height of the image",
|
||||
0,
|
||||
G_MAXUINT16,
|
||||
0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_init (FpImage *self)
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GAsyncReadyCallback user_cb;
|
||||
struct fp_minutiae *minutiae;
|
||||
gint width, height;
|
||||
gdouble ppmm;
|
||||
FpiImageFlags flags;
|
||||
guchar *image;
|
||||
guchar *binarized;
|
||||
} DetectMinutiaeData;
|
||||
|
||||
static void
|
||||
fp_image_detect_minutiae_free (DetectMinutiaeData *data)
|
||||
{
|
||||
g_clear_pointer (&data->image, g_free);
|
||||
g_clear_pointer (&data->minutiae, free_minutiae);
|
||||
g_clear_pointer (&data->binarized, g_free);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_detect_minutiae_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task = G_TASK (res);
|
||||
FpImage *image;
|
||||
DetectMinutiaeData *data = g_task_get_task_data (task);
|
||||
GCancellable *cancellable;
|
||||
|
||||
cancellable = g_task_get_cancellable (task);
|
||||
if (!cancellable || !g_cancellable_is_cancelled (cancellable))
|
||||
{
|
||||
gint i;
|
||||
image = FP_IMAGE (source_object);
|
||||
|
||||
image->flags = data->flags;
|
||||
|
||||
g_clear_pointer (&image->data, g_free);
|
||||
image->data = g_steal_pointer (&data->image);
|
||||
|
||||
g_clear_pointer (&image->binarized, g_free);
|
||||
image->binarized = g_steal_pointer (&data->binarized);
|
||||
|
||||
g_clear_pointer (&image->minutiae, g_ptr_array_unref);
|
||||
image->minutiae = g_ptr_array_new_full (data->minutiae->num,
|
||||
(GDestroyNotify) free_minutia);
|
||||
|
||||
for (i = 0; i < data->minutiae->num; i++)
|
||||
g_ptr_array_add (image->minutiae,
|
||||
g_steal_pointer (&data->minutiae->list[i]));
|
||||
|
||||
/* Don't let it delete anything. */
|
||||
data->minutiae->num = 0;
|
||||
}
|
||||
|
||||
if (data->user_cb)
|
||||
data->user_cb (source_object, res, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
vflip (guint8 *data, gint width, gint height)
|
||||
{
|
||||
int data_len = width * height;
|
||||
unsigned char rowbuf[width];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < height / 2; i++)
|
||||
{
|
||||
int offset = i * width;
|
||||
int swap_offset = data_len - (width * (i + 1));
|
||||
|
||||
/* copy top row into buffer */
|
||||
memcpy (rowbuf, data + offset, width);
|
||||
|
||||
/* copy lower row over upper row */
|
||||
memcpy (data + offset, data + swap_offset, width);
|
||||
|
||||
/* copy buffer over lower row */
|
||||
memcpy (data + swap_offset, rowbuf, width);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hflip (guint8 *data, gint width, gint height)
|
||||
{
|
||||
unsigned char rowbuf[width];
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
int offset = i * width;
|
||||
|
||||
memcpy (rowbuf, data + offset, width);
|
||||
for (j = 0; j < width; j++)
|
||||
data[offset + j] = rowbuf[width - j - 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
invert_colors (guint8 *data, gint width, gint height)
|
||||
{
|
||||
int data_len = width * height;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data_len; i++)
|
||||
data[i] = 0xff - data[i];
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_detect_minutiae_thread_func (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autoptr(GTimer) timer = NULL;
|
||||
DetectMinutiaeData *data = task_data;
|
||||
struct fp_minutiae *minutiae = NULL;
|
||||
g_autofree gint *direction_map = NULL;
|
||||
g_autofree gint *low_contrast_map = NULL;
|
||||
g_autofree gint *low_flow_map = NULL;
|
||||
g_autofree gint *high_curve_map = NULL;
|
||||
g_autofree gint *quality_map = NULL;
|
||||
g_autofree guchar *bdata = NULL;
|
||||
gint map_w, map_h;
|
||||
gint bw, bh, bd;
|
||||
gint r;
|
||||
|
||||
/* Normalize the image first */
|
||||
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
||||
hflip (data->image, data->width, data->height);
|
||||
|
||||
if (data->flags & FPI_IMAGE_V_FLIPPED)
|
||||
vflip (data->image, data->width, data->height);
|
||||
|
||||
if (data->flags & FPI_IMAGE_COLORS_INVERTED)
|
||||
invert_colors (data->image, data->width, data->height);
|
||||
|
||||
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
|
||||
|
||||
timer = g_timer_new ();
|
||||
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
||||
&low_contrast_map, &low_flow_map, &high_curve_map,
|
||||
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
||||
data->image, data->width, data->height, 8,
|
||||
data->ppmm, &g_lfsparms_V2);
|
||||
g_timer_stop (timer);
|
||||
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||
|
||||
data->binarized = g_steal_pointer (&bdata);
|
||||
data->minutiae = minutiae;
|
||||
|
||||
if (r)
|
||||
{
|
||||
fp_err ("get minutiae failed, code %d", r);
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Minutiae scan failed with code %d", r);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_height:
|
||||
* @self: A #FpImage
|
||||
*
|
||||
* Gets the pixel height of an image.
|
||||
*
|
||||
* Returns: the height of the image
|
||||
*/
|
||||
guint
|
||||
fp_image_get_height (FpImage *self)
|
||||
{
|
||||
return self->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_width:
|
||||
* @self: A #FpImage
|
||||
*
|
||||
* Gets the pixel width of an image.
|
||||
*
|
||||
* Returns: the width of the image
|
||||
*/
|
||||
guint
|
||||
fp_image_get_width (FpImage *self)
|
||||
{
|
||||
return self->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_ppmm:
|
||||
* @self: A #FpImage
|
||||
*
|
||||
* Gets the resolution of the image. Note that this is assumed to
|
||||
* be fixed to 500 points per inch (~19.685 p/mm) for most drivers.
|
||||
*
|
||||
* Returns: the resolution of the image in points per millimeter
|
||||
*/
|
||||
gdouble
|
||||
fp_image_get_ppmm (FpImage *self)
|
||||
{
|
||||
return self->ppmm;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_data:
|
||||
* @self: A #FpImage
|
||||
* @len: (out) (optional): Return location for length or %NULL
|
||||
*
|
||||
* Gets the greyscale data for an image. This data must not be modified or
|
||||
* freed.
|
||||
*
|
||||
* Returns: (transfer none) (array length=len): The image data
|
||||
*/
|
||||
const guchar *
|
||||
fp_image_get_data (FpImage *self, gsize *len)
|
||||
{
|
||||
if (len)
|
||||
*len = self->width * self->height;
|
||||
|
||||
return self->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_binarized:
|
||||
* @self: A #FpImage
|
||||
* @len: (out) (optional): Return location for length or %NULL
|
||||
*
|
||||
* Gets the binarized data for an image. This data must not be modified or
|
||||
* freed. You need to first detect the minutiae using
|
||||
* fp_image_detect_minutiae().
|
||||
*
|
||||
* Returns: (transfer none) (array length=len): The binarized image data
|
||||
*/
|
||||
const guchar *
|
||||
fp_image_get_binarized (FpImage *self, gsize *len)
|
||||
{
|
||||
if (len && self->binarized)
|
||||
*len = self->width * self->height;
|
||||
|
||||
return self->binarized;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_get_minutiae:
|
||||
* @self: A #FpImage
|
||||
*
|
||||
* Gets the minutiae for an image. This data must not be modified or
|
||||
* freed. You need to first detect the minutiae using
|
||||
* fp_image_detect_minutiae().
|
||||
*
|
||||
* Returns: (transfer none) (element-type FpMinutia): The detected minutiae
|
||||
*/
|
||||
GPtrArray *
|
||||
fp_image_get_minutiae (FpImage *self)
|
||||
{
|
||||
return self->minutiae;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_detect_minutiae:
|
||||
* @self: A #FpImage
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: the function to call on completion
|
||||
* @user_data: the data to pass to @callback
|
||||
*
|
||||
* Detects the minutiae found in an image.
|
||||
*/
|
||||
void
|
||||
fp_image_detect_minutiae (FpImage *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
DetectMinutiaeData *data = g_new0 (DetectMinutiaeData, 1);
|
||||
|
||||
task = g_task_new (self, cancellable, fp_image_detect_minutiae_cb, user_data);
|
||||
|
||||
data->image = g_malloc (self->width * self->height);
|
||||
memcpy (data->image, self->data, self->width * self->height);
|
||||
data->flags = self->flags;
|
||||
data->width = self->width;
|
||||
data->height = self->height;
|
||||
data->ppmm = self->ppmm;
|
||||
data->user_cb = callback;
|
||||
|
||||
g_task_set_task_data (task, data, (GDestroyNotify) fp_image_detect_minutiae_free);
|
||||
g_task_run_in_thread (task, fp_image_detect_minutiae_thread_func);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_image_detect_minutiae_finish:
|
||||
* @self: A #FpImage
|
||||
* @result: A #GAsyncResult
|
||||
* @error: Return location for errors, or %NULL to ignore
|
||||
*
|
||||
* Finish minutiae detection in an image
|
||||
*
|
||||
* Returns: %TRUE on success
|
||||
*/
|
||||
gboolean
|
||||
fp_image_detect_minutiae_finish (FpImage *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* fpi_std_sq_dev:
|
||||
* @buf: buffer (usually bitmap, one byte per pixel)
|
||||
* @size: size of @buffer
|
||||
*
|
||||
* Calculates the squared standard deviation of the individual
|
||||
* pixels in the buffer, as per the following formula:
|
||||
* |[<!-- -->
|
||||
* mean = sum (buf[0..size]) / size
|
||||
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
||||
* ]|
|
||||
* This function is usually used to determine whether image
|
||||
* is empty.
|
||||
*
|
||||
* Returns: the squared standard deviation for @buffer
|
||||
*/
|
||||
gint
|
||||
fpi_std_sq_dev (const guint8 *buf,
|
||||
gint size)
|
||||
{
|
||||
guint64 res = 0, mean = 0;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
mean += buf[i];
|
||||
|
||||
mean /= size;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
int dev = (int) buf[i] - mean;
|
||||
res += dev * dev;
|
||||
}
|
||||
|
||||
return res / size;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_mean_sq_diff_norm:
|
||||
* @buf1: buffer (usually bitmap, one byte per pixel)
|
||||
* @buf2: buffer (usually bitmap, one byte per pixel)
|
||||
* @size: buffer size of smallest buffer
|
||||
*
|
||||
* This function calculates the normalized mean square difference of
|
||||
* two buffers, usually two lines, as per the following formula:
|
||||
* |[<!-- -->
|
||||
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
||||
* ]|
|
||||
*
|
||||
* This functions is usually used to get numerical difference
|
||||
* between two images.
|
||||
*
|
||||
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
||||
*/
|
||||
gint
|
||||
fpi_mean_sq_diff_norm (const guint8 *buf1,
|
||||
const guint8 *buf2,
|
||||
gint size)
|
||||
{
|
||||
int res = 0, i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
int dev = (int) buf1[i] - (int) buf2[i];
|
||||
res += dev * dev;
|
||||
}
|
||||
|
||||
return res / size;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_minutia_get_coords:
|
||||
* @min: A #FpMinutia
|
||||
* @x: (out): x position in image
|
||||
* @y: (out): y position in image
|
||||
*
|
||||
* Returns the coordinates of the found minutia. This is only useful for
|
||||
* debugging purposes and the API is not considered stable for production.
|
||||
*/
|
||||
void
|
||||
fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
|
||||
{
|
||||
if (x)
|
||||
*x = min->x;
|
||||
if (y)
|
||||
*y = min->y;
|
||||
}
|
||||
|
||||
#if HAVE_PIXMAN
|
||||
FpImage *
|
||||
fpi_image_resize (FpImage *orig_img,
|
||||
guint w_factor,
|
||||
guint h_factor)
|
||||
{
|
||||
int new_width = orig_img->width * w_factor;
|
||||
int new_height = orig_img->height * h_factor;
|
||||
pixman_image_t *orig, *resized;
|
||||
pixman_transform_t transform;
|
||||
FpImage *newimg;
|
||||
|
||||
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
|
||||
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
|
||||
|
||||
pixman_transform_init_identity (&transform);
|
||||
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
|
||||
pixman_image_set_transform (orig, &transform);
|
||||
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
||||
pixman_image_composite32 (PIXMAN_OP_SRC,
|
||||
orig, /* src */
|
||||
NULL, /* mask */
|
||||
resized, /* dst */
|
||||
0, 0, /* src x y */
|
||||
0, 0, /* mask x y */
|
||||
0, 0, /* dst x y */
|
||||
new_width, new_height /* width height */
|
||||
);
|
||||
|
||||
newimg = fp_image_new (new_width, new_height);
|
||||
newimg->flags = orig_img->flags;
|
||||
|
||||
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
|
||||
|
||||
pixman_image_unref (orig);
|
||||
pixman_image_unref (resized);
|
||||
|
||||
return newimg;
|
||||
}
|
||||
#endif
|
||||
59
libfprint/fp-image.h
Normal file
59
libfprint/fp-image.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* FPrint Image
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_IMAGE (fp_image_get_type ())
|
||||
|
||||
typedef struct fp_minutia FpMinutia;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpImage, fp_image, FP, IMAGE, GObject)
|
||||
|
||||
FpImage *fp_image_new (gint width,
|
||||
gint height);
|
||||
|
||||
guint fp_image_get_width (FpImage *self);
|
||||
guint fp_image_get_height (FpImage *self);
|
||||
gdouble fp_image_get_ppmm (FpImage *self);
|
||||
|
||||
GPtrArray * fp_image_get_minutiae (FpImage *self);
|
||||
|
||||
void fp_image_detect_minutiae (FpImage *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean fp_image_detect_minutiae_finish (FpImage *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
const guchar * fp_image_get_data (FpImage *self,
|
||||
gsize *len);
|
||||
const guchar * fp_image_get_binarized (FpImage *self,
|
||||
gsize *len);
|
||||
|
||||
void fp_minutia_get_coords (FpMinutia *min,
|
||||
gint *x,
|
||||
gint *y);
|
||||
|
||||
G_END_DECLS
|
||||
1120
libfprint/fp-print.c
Normal file
1120
libfprint/fp-print.c
Normal file
File diff suppressed because it is too large
Load Diff
101
libfprint/fp-print.h
Normal file
101
libfprint/fp-print.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* FPrint Print handling
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fp-image.h"
|
||||
#include "fp-enums.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_PRINT (fp_print_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
|
||||
|
||||
#include "fp-device.h"
|
||||
|
||||
/**
|
||||
* FpFinger:
|
||||
* @FP_FINGER_UNKNOWN: The finger is unknown
|
||||
* @FP_FINGER_LEFT_THUMB: Left thumb
|
||||
* @FP_FINGER_LEFT_INDEX: Left index finger
|
||||
* @FP_FINGER_LEFT_MIDDLE: Left middle finger
|
||||
* @FP_FINGER_LEFT_RING: Left ring finger
|
||||
* @FP_FINGER_LEFT_LITTLE: Left little finger
|
||||
* @FP_FINGER_RIGHT_THUMB: Right thumb
|
||||
* @FP_FINGER_RIGHT_INDEX: Right index finger
|
||||
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
|
||||
* @FP_FINGER_RIGHT_RING: Right ring finger
|
||||
* @FP_FINGER_RIGHT_LITTLE: Right little finger
|
||||
*/
|
||||
typedef enum {
|
||||
FP_FINGER_UNKNOWN = 0,
|
||||
FP_FINGER_LEFT_THUMB,
|
||||
FP_FINGER_LEFT_INDEX,
|
||||
FP_FINGER_LEFT_MIDDLE,
|
||||
FP_FINGER_LEFT_RING,
|
||||
FP_FINGER_LEFT_LITTLE,
|
||||
FP_FINGER_RIGHT_THUMB,
|
||||
FP_FINGER_RIGHT_INDEX,
|
||||
FP_FINGER_RIGHT_MIDDLE,
|
||||
FP_FINGER_RIGHT_RING,
|
||||
FP_FINGER_RIGHT_LITTLE,
|
||||
} FpFinger;
|
||||
|
||||
FpPrint *fp_print_new (FpDevice *device);
|
||||
|
||||
FpPrint *fp_print_new_from_data (guchar *data,
|
||||
gsize length);
|
||||
gboolean fp_print_to_data (guchar **data,
|
||||
gsize length);
|
||||
|
||||
const gchar *fp_print_get_driver (FpPrint *print);
|
||||
const gchar *fp_print_get_device_id (FpPrint *print);
|
||||
FpImage *fp_print_get_image (FpPrint *print);
|
||||
|
||||
FpFinger fp_print_get_finger (FpPrint *print);
|
||||
const gchar *fp_print_get_username (FpPrint *print);
|
||||
const gchar *fp_print_get_description (FpPrint *print);
|
||||
const GDate *fp_print_get_enroll_date (FpPrint *print);
|
||||
gboolean fp_print_get_device_stored (FpPrint *print);
|
||||
|
||||
void fp_print_set_finger (FpPrint *print,
|
||||
FpFinger finger);
|
||||
void fp_print_set_username (FpPrint *print,
|
||||
const gchar *username);
|
||||
void fp_print_set_description (FpPrint *print,
|
||||
const gchar *description);
|
||||
void fp_print_set_enroll_date (FpPrint *print,
|
||||
const GDate *enroll_date);
|
||||
|
||||
gboolean fp_print_compatible (FpPrint *self,
|
||||
FpDevice *device);
|
||||
gboolean fp_print_equal (FpPrint *self,
|
||||
FpPrint *other);
|
||||
|
||||
gboolean fp_print_serialize (FpPrint *print,
|
||||
guchar **data,
|
||||
gsize *length,
|
||||
GError **error);
|
||||
|
||||
FpPrint *fp_print_deserialize (const guchar *data,
|
||||
gsize length,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -20,238 +20,35 @@
|
||||
#ifndef __FPRINT_INTERNAL_H__
|
||||
#define __FPRINT_INTERNAL_H__
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "nbis-helpers.h"
|
||||
#include "fprint.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-core.h"
|
||||
#include "fpi-log.h"
|
||||
#include "fpi-dev-img.h"
|
||||
#include "fpi-data.h"
|
||||
#include "fpi-img.h"
|
||||
#include "drivers/driver_ids.h"
|
||||
|
||||
/* Global variables */
|
||||
extern libusb_context *fpi_usb_ctx;
|
||||
extern GSList *opened_devices;
|
||||
|
||||
/* fp_print_data structure definition */
|
||||
enum fp_print_data_type {
|
||||
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
||||
PRINT_DATA_NBIS_MINUTIAE
|
||||
};
|
||||
|
||||
struct fp_print_data {
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
enum fp_print_data_type type;
|
||||
GSList *prints;
|
||||
};
|
||||
|
||||
/* fp_dev structure definition */
|
||||
enum fp_dev_state {
|
||||
DEV_STATE_INITIAL = 0,
|
||||
DEV_STATE_ERROR,
|
||||
DEV_STATE_INITIALIZING,
|
||||
DEV_STATE_INITIALIZED,
|
||||
DEV_STATE_DEINITIALIZING,
|
||||
DEV_STATE_DEINITIALIZED,
|
||||
DEV_STATE_ENROLL_STARTING,
|
||||
DEV_STATE_ENROLLING,
|
||||
DEV_STATE_ENROLL_STOPPING,
|
||||
DEV_STATE_VERIFY_STARTING,
|
||||
DEV_STATE_VERIFYING,
|
||||
DEV_STATE_VERIFY_DONE,
|
||||
DEV_STATE_VERIFY_STOPPING,
|
||||
DEV_STATE_IDENTIFY_STARTING,
|
||||
DEV_STATE_IDENTIFYING,
|
||||
DEV_STATE_IDENTIFY_DONE,
|
||||
DEV_STATE_IDENTIFY_STOPPING,
|
||||
DEV_STATE_CAPTURE_STARTING,
|
||||
DEV_STATE_CAPTURING,
|
||||
DEV_STATE_CAPTURE_DONE,
|
||||
DEV_STATE_CAPTURE_STOPPING,
|
||||
DEV_STATE_DELETING,
|
||||
DEV_STATE_DELETE_DONE,
|
||||
DEV_STATE_DELETE_STOPPING,
|
||||
};
|
||||
|
||||
struct fp_dev {
|
||||
struct fp_driver *drv;
|
||||
uint32_t devtype;
|
||||
|
||||
/* only valid if drv->type == DRIVER_IMAGING */
|
||||
struct fp_img_dev *img_dev;
|
||||
/* Link to the instance specific struct */
|
||||
void *instance_data;
|
||||
|
||||
int nr_enroll_stages;
|
||||
|
||||
enum fp_bus_type bus;
|
||||
union {
|
||||
libusb_device_handle *usb;
|
||||
const char *virtual_env;
|
||||
int i2c;
|
||||
} device;
|
||||
|
||||
/* read-only to drivers */
|
||||
struct fp_print_data *verify_data;
|
||||
struct fp_print_data *delete_data;
|
||||
|
||||
/* drivers should not mess with any of the below */
|
||||
enum fp_dev_state state;
|
||||
int __enroll_stage;
|
||||
int unconditional_capture;
|
||||
|
||||
/* async I/O callbacks and data */
|
||||
/* FIXME: convert this to generic state operational data mechanism? */
|
||||
fp_dev_open_cb open_cb;
|
||||
void *open_cb_data;
|
||||
fp_operation_stop_cb close_cb;
|
||||
void *close_cb_data;
|
||||
fp_enroll_stage_cb enroll_stage_cb;
|
||||
void *enroll_stage_cb_data;
|
||||
fp_operation_stop_cb enroll_stop_cb;
|
||||
void *enroll_stop_cb_data;
|
||||
fp_img_operation_cb verify_cb;
|
||||
void *verify_cb_data;
|
||||
fp_operation_stop_cb verify_stop_cb;
|
||||
void *verify_stop_cb_data;
|
||||
fp_identify_cb identify_cb;
|
||||
void *identify_cb_data;
|
||||
fp_operation_stop_cb identify_stop_cb;
|
||||
void *identify_stop_cb_data;
|
||||
fp_img_operation_cb capture_cb;
|
||||
void *capture_cb_data;
|
||||
fp_operation_stop_cb capture_stop_cb;
|
||||
void *capture_stop_cb_data;
|
||||
fp_delete_cb delete_cb;
|
||||
void *delete_cb_data;
|
||||
|
||||
/* FIXME: better place to put this? */
|
||||
struct fp_print_data **identify_gallery;
|
||||
};
|
||||
|
||||
/* fp_img_dev structure definition */
|
||||
struct fp_img_dev {
|
||||
struct fp_dev *parent;
|
||||
|
||||
enum fp_imgdev_action action;
|
||||
int action_state;
|
||||
|
||||
struct fp_print_data *acquire_data;
|
||||
struct fp_print_data *enroll_data;
|
||||
struct fp_img *acquire_img;
|
||||
int enroll_stage;
|
||||
int action_result;
|
||||
|
||||
/* FIXME: better place to put this? */
|
||||
size_t identify_match_offset;
|
||||
};
|
||||
|
||||
/* fp_driver structure definition */
|
||||
|
||||
/* fp_img_driver structure definition */
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
#define fpi_driver_to_img_driver(drv) \
|
||||
container_of((drv), struct fp_img_driver, driver)
|
||||
|
||||
/* fp_dscv_dev structure definition */
|
||||
struct fp_dscv_dev {
|
||||
enum fp_bus_type bus;
|
||||
union {
|
||||
struct libusb_device *usb;
|
||||
const char *virtual_env;
|
||||
char *spi_path;
|
||||
} desc;
|
||||
|
||||
struct fp_driver *drv;
|
||||
unsigned long driver_data;
|
||||
uint32_t devtype;
|
||||
};
|
||||
|
||||
/* fp_dscv_print structure definition */
|
||||
struct fp_dscv_print {
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
enum fp_finger finger;
|
||||
char *path;
|
||||
};
|
||||
#include "nbis-helpers.h"
|
||||
#include "fpi-image.h"
|
||||
#include "fpi-image-device.h"
|
||||
|
||||
/* fp_minutia structure definition */
|
||||
struct fp_minutia {
|
||||
int x;
|
||||
int y;
|
||||
int ex;
|
||||
int ey;
|
||||
int direction;
|
||||
double reliability;
|
||||
int type;
|
||||
int appearing;
|
||||
int feature_id;
|
||||
int *nbrs;
|
||||
int *ridge_counts;
|
||||
int num_nbrs;
|
||||
struct fp_minutia
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int ex;
|
||||
int ey;
|
||||
int direction;
|
||||
double reliability;
|
||||
int type;
|
||||
int appearing;
|
||||
int feature_id;
|
||||
int *nbrs;
|
||||
int *ridge_counts;
|
||||
int num_nbrs;
|
||||
};
|
||||
|
||||
/* fp_minutiae structure definition */
|
||||
struct fp_minutiae {
|
||||
int alloc;
|
||||
int num;
|
||||
struct fp_minutia **list;
|
||||
struct fp_minutiae
|
||||
{
|
||||
int alloc;
|
||||
int num;
|
||||
struct fp_minutia **list;
|
||||
};
|
||||
|
||||
/* Defined in fpi-dev-img.c */
|
||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
||||
|
||||
/* Exported for use in command-line tools
|
||||
* Defined in fpi-core.c */
|
||||
struct fp_driver **fprint_get_drivers (void);
|
||||
|
||||
/* Defined in fpi-core.c */
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
||||
|
||||
/* Defined in fpi-data.c */
|
||||
void fpi_data_exit(void);
|
||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
||||
enum fp_print_data_type type2);
|
||||
|
||||
/* Defined in fpi-img.c */
|
||||
gboolean fpi_img_is_sane(struct fp_img *img);
|
||||
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||
struct fp_print_data **ret);
|
||||
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
||||
struct fp_print_data *new_print);
|
||||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
||||
struct fp_print_data **gallery, int match_threshold, size_t *match_offset);
|
||||
|
||||
/* Defined in fpi-poll.c */
|
||||
void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev);
|
||||
void fpi_poll_init(void);
|
||||
void fpi_poll_exit(void);
|
||||
|
||||
/* Defined in fpi-async.c */
|
||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
||||
struct fp_img *img);
|
||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||
size_t match_offset, struct fp_img *img);
|
||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
||||
|
||||
#include "drivers_definitions.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,12 +23,8 @@
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "fpi-assembling.h"
|
||||
|
||||
/**
|
||||
@@ -42,132 +38,141 @@
|
||||
* data in small stripes.
|
||||
*/
|
||||
|
||||
static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *first_frame,
|
||||
struct fpi_frame *second_frame,
|
||||
int dx,
|
||||
int dy)
|
||||
static unsigned int
|
||||
calc_error (struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *first_frame,
|
||||
struct fpi_frame *second_frame,
|
||||
int dx,
|
||||
int dy)
|
||||
{
|
||||
unsigned int width, height;
|
||||
unsigned int x1, y1, x2, y2, err, i, j;
|
||||
unsigned int width, height;
|
||||
unsigned int x1, y1, x2, y2, err, i, j;
|
||||
|
||||
width = ctx->frame_width - (dx > 0 ? dx : -dx);
|
||||
height = ctx->frame_height - dy;
|
||||
width = ctx->frame_width - (dx > 0 ? dx : -dx);
|
||||
height = ctx->frame_height - dy;
|
||||
|
||||
y1 = 0;
|
||||
y2 = dy;
|
||||
i = 0;
|
||||
err = 0;
|
||||
do {
|
||||
x1 = dx < 0 ? 0 : dx;
|
||||
x2 = dx < 0 ? -dx : 0;
|
||||
j = 0;
|
||||
y1 = 0;
|
||||
y2 = dy;
|
||||
i = 0;
|
||||
err = 0;
|
||||
do
|
||||
{
|
||||
x1 = dx < 0 ? 0 : dx;
|
||||
x2 = dx < 0 ? -dx : 0;
|
||||
j = 0;
|
||||
|
||||
do {
|
||||
unsigned char v1, v2;
|
||||
do
|
||||
{
|
||||
unsigned char v1, v2;
|
||||
|
||||
|
||||
v1 = ctx->get_pixel(ctx, first_frame, x1, y1);
|
||||
v2 = ctx->get_pixel(ctx, second_frame, x2, y2);
|
||||
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
||||
j++;
|
||||
x1++;
|
||||
x2++;
|
||||
v1 = ctx->get_pixel (ctx, first_frame, x1, y1);
|
||||
v2 = ctx->get_pixel (ctx, second_frame, x2, y2);
|
||||
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
||||
j++;
|
||||
x1++;
|
||||
x2++;
|
||||
|
||||
} while (j < width);
|
||||
i++;
|
||||
y1++;
|
||||
y2++;
|
||||
} while (i < height);
|
||||
}
|
||||
while (j < width);
|
||||
i++;
|
||||
y1++;
|
||||
y2++;
|
||||
}
|
||||
while (i < height);
|
||||
|
||||
/* Normalize error */
|
||||
err *= (ctx->frame_height * ctx->frame_width);
|
||||
err /= (height * width);
|
||||
/* Normalize error */
|
||||
err *= (ctx->frame_height * ctx->frame_width);
|
||||
err /= (height * width);
|
||||
|
||||
if (err == 0)
|
||||
return INT_MAX;
|
||||
if (err == 0)
|
||||
return INT_MAX;
|
||||
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function is rather CPU-intensive. It's better to use hardware
|
||||
* to detect movement direction when possible.
|
||||
*/
|
||||
static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *first_frame,
|
||||
struct fpi_frame *second_frame,
|
||||
unsigned int *min_error)
|
||||
static void
|
||||
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *first_frame,
|
||||
struct fpi_frame *second_frame,
|
||||
unsigned int *min_error)
|
||||
{
|
||||
int dx, dy;
|
||||
unsigned int err;
|
||||
*min_error = 255 * ctx->frame_height * ctx->frame_width;
|
||||
int dx, dy;
|
||||
unsigned int err;
|
||||
|
||||
/* Seeking in horizontal and vertical dimensions,
|
||||
* for horizontal dimension we'll check only 8 pixels
|
||||
* in both directions. For vertical direction diff is
|
||||
* rarely less than 2, so start with it.
|
||||
*/
|
||||
for (dy = 2; dy < ctx->frame_height; dy++) {
|
||||
for (dx = -8; dx < 8; dx++) {
|
||||
err = calc_error(ctx, first_frame, second_frame,
|
||||
dx, dy);
|
||||
if (err < *min_error) {
|
||||
*min_error = err;
|
||||
second_frame->delta_x = -dx;
|
||||
second_frame->delta_y = dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
*min_error = 255 * ctx->frame_height * ctx->frame_width;
|
||||
|
||||
/* Seeking in horizontal and vertical dimensions,
|
||||
* for horizontal dimension we'll check only 8 pixels
|
||||
* in both directions. For vertical direction diff is
|
||||
* rarely less than 2, so start with it.
|
||||
*/
|
||||
for (dy = 2; dy < ctx->frame_height; dy++)
|
||||
{
|
||||
for (dx = -8; dx < 8; dx++)
|
||||
{
|
||||
err = calc_error (ctx, first_frame, second_frame,
|
||||
dx, dy);
|
||||
if (err < *min_error)
|
||||
{
|
||||
*min_error = err;
|
||||
second_frame->delta_x = -dx;
|
||||
second_frame->delta_y = dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes,
|
||||
gboolean reverse)
|
||||
static unsigned int
|
||||
do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, gboolean reverse)
|
||||
{
|
||||
GSList *list_entry = stripes;
|
||||
GTimer *timer;
|
||||
int frame = 1;
|
||||
struct fpi_frame *prev_stripe = list_entry->data;
|
||||
unsigned int min_error;
|
||||
/* Max error is width * height * 255, for AES2501 which has the largest
|
||||
* sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before
|
||||
* we might get int overflow. Use 64bit value here to prevent integer overflow
|
||||
*/
|
||||
unsigned long long total_error = 0;
|
||||
GSList *l;
|
||||
GTimer *timer;
|
||||
guint num_frames = 0;
|
||||
struct fpi_frame *prev_stripe;
|
||||
unsigned int min_error;
|
||||
/* Max error is width * height * 255, for AES2501 which has the largest
|
||||
* sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before
|
||||
* we might get int overflow. Use 64bit value here to prevent integer overflow
|
||||
*/
|
||||
unsigned long long total_error = 0;
|
||||
|
||||
list_entry = g_slist_next(list_entry);
|
||||
timer = g_timer_new ();
|
||||
prev_stripe = stripes->data;
|
||||
for (l = stripes; l != NULL; l = l->next, num_frames++)
|
||||
{
|
||||
struct fpi_frame *cur_stripe = l->data;
|
||||
|
||||
timer = g_timer_new();
|
||||
do {
|
||||
struct fpi_frame *cur_stripe = list_entry->data;
|
||||
if (reverse)
|
||||
{
|
||||
find_overlap (ctx, prev_stripe, cur_stripe, &min_error);
|
||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
find_overlap (ctx, cur_stripe, prev_stripe, &min_error);
|
||||
}
|
||||
total_error += min_error;
|
||||
|
||||
if (reverse) {
|
||||
find_overlap(ctx, prev_stripe, cur_stripe, &min_error);
|
||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
||||
}
|
||||
else
|
||||
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
|
||||
total_error += min_error;
|
||||
prev_stripe = cur_stripe;
|
||||
}
|
||||
|
||||
frame++;
|
||||
prev_stripe = cur_stripe;
|
||||
list_entry = g_slist_next(list_entry);
|
||||
g_timer_stop (timer);
|
||||
fp_dbg ("calc delta completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||
g_timer_destroy (timer);
|
||||
|
||||
} while (frame < num_stripes);
|
||||
|
||||
g_timer_stop(timer);
|
||||
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
|
||||
g_timer_destroy(timer);
|
||||
|
||||
return total_error / num_stripes;
|
||||
return total_error / num_frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_do_movement_estimation:
|
||||
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||
* @stripes: a singly-linked list of #fpi_frame
|
||||
* @num_stripes: number of items in @stripes to process
|
||||
*
|
||||
* fpi_do_movement_estimation() estimates the movement between adjacent
|
||||
* frames, populating @delta_x and @delta_y values for each #fpi_frame.
|
||||
@@ -175,221 +180,231 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
* This function is used for devices that don't do movement estimation
|
||||
* in hardware. If hardware movement estimation is supported, the driver
|
||||
* should populate @delta_x and @delta_y instead.
|
||||
*
|
||||
* Note that @num_stripes might be shorter than the length of the list,
|
||||
* if some stripes should be skipped.
|
||||
*/
|
||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes)
|
||||
void
|
||||
fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes)
|
||||
{
|
||||
int err, rev_err;
|
||||
err = do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
||||
rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE);
|
||||
fp_dbg("errors: %d rev: %d", err, rev_err);
|
||||
if (err < rev_err) {
|
||||
do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
||||
}
|
||||
int err, rev_err;
|
||||
|
||||
err = do_movement_estimation (ctx, stripes, FALSE);
|
||||
rev_err = do_movement_estimation (ctx, stripes, TRUE);
|
||||
fp_dbg ("errors: %d rev: %d", err, rev_err);
|
||||
if (err < rev_err)
|
||||
do_movement_estimation (ctx, stripes, FALSE);
|
||||
}
|
||||
|
||||
static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fp_img *img,
|
||||
struct fpi_frame *stripe,
|
||||
int x, int y)
|
||||
static inline void
|
||||
aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
|
||||
FpImage *img,
|
||||
struct fpi_frame *stripe,
|
||||
int x, int y)
|
||||
{
|
||||
unsigned int ix, iy;
|
||||
unsigned int fx, fy;
|
||||
unsigned int width, height;
|
||||
unsigned int ix, iy;
|
||||
unsigned int fx, fy;
|
||||
unsigned int width, height;
|
||||
|
||||
/* Find intersection */
|
||||
if (x < 0) {
|
||||
width = ctx->frame_width + x;
|
||||
ix = 0;
|
||||
fx = -x;
|
||||
} else {
|
||||
ix = x;
|
||||
fx = 0;
|
||||
width = ctx->frame_width;
|
||||
}
|
||||
if ((ix + width) > img->width)
|
||||
width = img->width - ix;
|
||||
/* Find intersection */
|
||||
if (x < 0)
|
||||
{
|
||||
width = ctx->frame_width + x;
|
||||
ix = 0;
|
||||
fx = -x;
|
||||
}
|
||||
else
|
||||
{
|
||||
ix = x;
|
||||
fx = 0;
|
||||
width = ctx->frame_width;
|
||||
}
|
||||
if ((ix + width) > img->width)
|
||||
width = img->width - ix;
|
||||
|
||||
if (y < 0) {
|
||||
iy = 0;
|
||||
fy = -y;
|
||||
height = ctx->frame_height + y;
|
||||
} else {
|
||||
iy = y;
|
||||
fy = 0;
|
||||
height = ctx->frame_height;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
iy = 0;
|
||||
fy = -y;
|
||||
height = ctx->frame_height + y;
|
||||
}
|
||||
else
|
||||
{
|
||||
iy = y;
|
||||
fy = 0;
|
||||
height = ctx->frame_height;
|
||||
}
|
||||
|
||||
if (fx > ctx->frame_width)
|
||||
return;
|
||||
if (fx > ctx->frame_width)
|
||||
return;
|
||||
|
||||
if (fy > ctx->frame_height)
|
||||
return;
|
||||
if (fy > ctx->frame_height)
|
||||
return;
|
||||
|
||||
if (ix > img->width)
|
||||
return;
|
||||
if (ix > img->width)
|
||||
return;
|
||||
|
||||
if (iy > img->height)
|
||||
return;
|
||||
if (iy > img->height)
|
||||
return;
|
||||
|
||||
if ((iy + height) > img->height)
|
||||
height = img->height - iy;
|
||||
if ((iy + height) > img->height)
|
||||
height = img->height - iy;
|
||||
|
||||
for (; fy < height; fy++, iy++) {
|
||||
if (x < 0) {
|
||||
ix = 0;
|
||||
fx = -x;
|
||||
} else {
|
||||
ix = x;
|
||||
fx = 0;
|
||||
}
|
||||
for (; fx < width; fx++, ix++) {
|
||||
img->data[ix + (iy * img->width)] = ctx->get_pixel(ctx, stripe, fx, fy);
|
||||
}
|
||||
}
|
||||
for (; fy < height; fy++, iy++)
|
||||
{
|
||||
if (x < 0)
|
||||
{
|
||||
ix = 0;
|
||||
fx = -x;
|
||||
}
|
||||
else
|
||||
{
|
||||
ix = x;
|
||||
fx = 0;
|
||||
}
|
||||
for (; fx < width; fx++, ix++)
|
||||
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_assemble_frames:
|
||||
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||
* @stripes: linked list of #fpi_frame
|
||||
* @num_stripes: number of items in @stripes to process
|
||||
*
|
||||
* fpi_assemble_frames() assembles individual frames into a single image.
|
||||
* It expects @delta_x and @delta_y of #fpi_frame to be populated.
|
||||
*
|
||||
* Note that @num_stripes might be shorter than the length of the list,
|
||||
* if some stripes should be skipped.
|
||||
*
|
||||
* Returns: a newly allocated #fp_img.
|
||||
*/
|
||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes)
|
||||
FpImage *
|
||||
fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes)
|
||||
{
|
||||
GSList *stripe;
|
||||
struct fp_img *img;
|
||||
int height = 0;
|
||||
int i, y, x;
|
||||
gboolean reverse = FALSE;
|
||||
struct fpi_frame *fpi_frame;
|
||||
GSList *l;
|
||||
FpImage *img;
|
||||
int height = 0;
|
||||
int y, x;
|
||||
gboolean reverse = FALSE;
|
||||
struct fpi_frame *fpi_frame;
|
||||
|
||||
//FIXME g_return_if_fail
|
||||
BUG_ON(num_stripes == 0);
|
||||
BUG_ON(ctx->image_width < ctx->frame_width);
|
||||
//FIXME g_return_if_fail
|
||||
g_return_val_if_fail (stripes != NULL, NULL);
|
||||
BUG_ON (ctx->image_width < ctx->frame_width);
|
||||
|
||||
/* Calculate height */
|
||||
i = 0;
|
||||
stripe = stripes;
|
||||
/* No offset for 1st image */
|
||||
fpi_frame = stripes->data;
|
||||
fpi_frame->delta_x = 0;
|
||||
fpi_frame->delta_y = 0;
|
||||
for (l = stripes; l != NULL; l = l->next)
|
||||
{
|
||||
fpi_frame = l->data;
|
||||
|
||||
/* No offset for 1st image */
|
||||
fpi_frame = stripe->data;
|
||||
fpi_frame->delta_x = 0;
|
||||
fpi_frame->delta_y = 0;
|
||||
do {
|
||||
fpi_frame = stripe->data;
|
||||
height += fpi_frame->delta_y;
|
||||
}
|
||||
|
||||
height += fpi_frame->delta_y;
|
||||
i++;
|
||||
stripe = g_slist_next(stripe);
|
||||
} while (i < num_stripes);
|
||||
fp_dbg ("height is %d", height);
|
||||
|
||||
fp_dbg("height is %d", height);
|
||||
if (height < 0)
|
||||
{
|
||||
reverse = TRUE;
|
||||
height = -height;
|
||||
}
|
||||
|
||||
if (height < 0) {
|
||||
reverse = TRUE;
|
||||
height = -height;
|
||||
}
|
||||
/* For last frame */
|
||||
height += ctx->frame_height;
|
||||
|
||||
/* For last frame */
|
||||
height += ctx->frame_height;
|
||||
/* Create buffer big enough for max image */
|
||||
img = fp_image_new (ctx->image_width, height);
|
||||
img->flags = FPI_IMAGE_COLORS_INVERTED;
|
||||
img->flags |= reverse ? 0 : FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED;
|
||||
img->width = ctx->image_width;
|
||||
img->height = height;
|
||||
|
||||
/* Create buffer big enough for max image */
|
||||
img = fpi_img_new(ctx->image_width * height);
|
||||
img->flags = FP_IMG_COLORS_INVERTED;
|
||||
img->flags |= reverse ? 0 : FP_IMG_H_FLIPPED | FP_IMG_V_FLIPPED;
|
||||
img->width = ctx->image_width;
|
||||
img->height = height;
|
||||
/* Assemble stripes */
|
||||
y = reverse ? (height - ctx->frame_height) : 0;
|
||||
x = (ctx->image_width - ctx->frame_width) / 2;
|
||||
|
||||
/* Assemble stripes */
|
||||
i = 0;
|
||||
stripe = stripes;
|
||||
y = reverse ? (height - ctx->frame_height) : 0;
|
||||
x = (ctx->image_width - ctx->frame_width) / 2;
|
||||
for (l = stripes; l != NULL; l = l->next)
|
||||
{
|
||||
fpi_frame = l->data;
|
||||
|
||||
do {
|
||||
fpi_frame = stripe->data;
|
||||
if(reverse)
|
||||
{
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
|
||||
if(reverse) {
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
aes_blit_stripe (ctx, img, fpi_frame, x, y);
|
||||
|
||||
aes_blit_stripe(ctx, img, fpi_frame, x, y);
|
||||
if(!reverse)
|
||||
{
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
}
|
||||
|
||||
if(!reverse) {
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
|
||||
stripe = g_slist_next(stripe);
|
||||
i++;
|
||||
} while (i < num_stripes);
|
||||
|
||||
return img;
|
||||
return img;
|
||||
}
|
||||
|
||||
static int cmpint(const void *p1, const void *p2, gpointer data)
|
||||
static int
|
||||
cmpint (const void *p1, const void *p2, gpointer data)
|
||||
{
|
||||
int a = *((int *)p1);
|
||||
int b = *((int *)p2);
|
||||
if (a < b)
|
||||
return -1;
|
||||
else if (a == b)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
int a = *((int *) p1);
|
||||
int b = *((int *) p2);
|
||||
|
||||
if (a < b)
|
||||
return -1;
|
||||
else if (a == b)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void median_filter(int *data, int size, int filtersize)
|
||||
static void
|
||||
median_filter (int *data, int size, int filtersize)
|
||||
{
|
||||
int i;
|
||||
int *result = (int *)g_malloc0(size*sizeof(int));
|
||||
int *sortbuf = (int *)g_malloc0(filtersize*sizeof(int));
|
||||
for (i = 0; i < size; i++) {
|
||||
int i1 = i - (filtersize-1)/2;
|
||||
int i2 = i + (filtersize-1)/2;
|
||||
if (i1 < 0)
|
||||
i1 = 0;
|
||||
if (i2 >= size)
|
||||
i2 = size-1;
|
||||
g_memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int));
|
||||
g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL);
|
||||
result[i] = sortbuf[(i2-i1+1)/2];
|
||||
}
|
||||
memmove(data, result, size*sizeof(int));
|
||||
g_free(result);
|
||||
g_free(sortbuf);
|
||||
int i;
|
||||
int *result = (int *) g_malloc0 (size * sizeof (int));
|
||||
int *sortbuf = (int *) g_malloc0 (filtersize * sizeof (int));
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
int i1 = i - (filtersize - 1) / 2;
|
||||
int i2 = i + (filtersize - 1) / 2;
|
||||
if (i1 < 0)
|
||||
i1 = 0;
|
||||
if (i2 >= size)
|
||||
i2 = size - 1;
|
||||
memmove (sortbuf, data + i1, (i2 - i1 + 1) * sizeof (int));
|
||||
g_qsort_with_data (sortbuf, i2 - i1 + 1, sizeof (int), cmpint, NULL);
|
||||
result[i] = sortbuf[(i2 - i1 + 1) / 2];
|
||||
}
|
||||
memmove (data, result, size * sizeof (int));
|
||||
g_free (result);
|
||||
g_free (sortbuf);
|
||||
}
|
||||
|
||||
static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1, float y1, GSList *line2,
|
||||
float y2, unsigned char *output, float yi, int size)
|
||||
static void
|
||||
interpolate_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1, gint32 y1_f,
|
||||
GSList *line2, gint32 y2_f,
|
||||
unsigned char *output, gint32 yi_f,
|
||||
int size)
|
||||
{
|
||||
int i;
|
||||
unsigned char p1, p2;
|
||||
int i;
|
||||
unsigned char p1, p2;
|
||||
|
||||
if (!line1 || !line2)
|
||||
return;
|
||||
if (!line1 || !line2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
p1 = ctx->get_pixel(ctx, line1, i);
|
||||
p2 = ctx->get_pixel(ctx, line2, i);
|
||||
output[i] = (float)p1
|
||||
+ (yi - y1)/(y2 - y1)*(p2 - p1);
|
||||
}
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
gint unscaled;
|
||||
p1 = ctx->get_pixel (ctx, line1, i);
|
||||
p2 = ctx->get_pixel (ctx, line2, i);
|
||||
|
||||
unscaled = (yi_f - y1_f) * p2 + (y2_f - yi_f) * p1;
|
||||
output[i] = (unscaled) / (y2_f - y1_f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,82 +421,95 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
*
|
||||
* Returns: a newly allocated #fp_img.
|
||||
*/
|
||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *lines, size_t num_lines)
|
||||
FpImage *
|
||||
fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *lines, size_t num_lines)
|
||||
{
|
||||
/* Number of output lines per distance between two scanners */
|
||||
int i;
|
||||
GSList *row1, *row2;
|
||||
float y = 0.0;
|
||||
int line_ind = 0;
|
||||
int *offsets = (int *)g_malloc0((num_lines / 2) * sizeof(int));
|
||||
unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height);
|
||||
struct fp_img *img;
|
||||
/* Number of output lines per distance between two scanners */
|
||||
int i;
|
||||
GSList *row1, *row2;
|
||||
/* The y coordinate is tracked as a 16.16 fixed point number. All
|
||||
* variables postfixed with _f follow this format here and in
|
||||
* interpolate_lines.
|
||||
* We could also use floating point here, but using fixed point means
|
||||
* we get consistent results across architectures.
|
||||
*/
|
||||
gint32 y_f = 0;
|
||||
int line_ind = 0;
|
||||
int *offsets = g_new0 (int, num_lines / 2);
|
||||
unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height);
|
||||
FpImage *img;
|
||||
|
||||
g_return_val_if_fail (lines != NULL, NULL);
|
||||
g_return_val_if_fail (num_lines >= 2, NULL);
|
||||
g_return_val_if_fail (lines != NULL, NULL);
|
||||
g_return_val_if_fail (num_lines >= 2, NULL);
|
||||
|
||||
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
|
||||
fp_dbg ("%"G_GINT64_FORMAT, g_get_real_time ());
|
||||
|
||||
row1 = lines;
|
||||
for (i = 0; (i < num_lines - 1) && row1; i += 2) {
|
||||
int bestmatch = i;
|
||||
int bestdiff = 0;
|
||||
int j, firstrow, lastrow;
|
||||
row1 = lines;
|
||||
for (i = 0; (i < num_lines - 1) && row1; i += 2)
|
||||
{
|
||||
int bestmatch = i;
|
||||
int bestdiff = 0;
|
||||
int j, firstrow, lastrow;
|
||||
|
||||
firstrow = i + 1;
|
||||
lastrow = MIN(i + ctx->max_search_offset, num_lines - 1);
|
||||
firstrow = i + 1;
|
||||
lastrow = MIN (i + ctx->max_search_offset, num_lines - 1);
|
||||
|
||||
row2 = g_slist_next(row1);
|
||||
for (j = firstrow; j <= lastrow; j++) {
|
||||
int diff = ctx->get_deviation(ctx,
|
||||
row1,
|
||||
row2);
|
||||
if ((j == firstrow) || (diff < bestdiff)) {
|
||||
bestdiff = diff;
|
||||
bestmatch = j;
|
||||
}
|
||||
row2 = g_slist_next(row2);
|
||||
}
|
||||
offsets[i / 2] = bestmatch - i;
|
||||
fp_dbg("%d", offsets[i / 2]);
|
||||
row1 = g_slist_next(row1);
|
||||
if (row1)
|
||||
row1 = g_slist_next(row1);
|
||||
}
|
||||
row2 = g_slist_next (row1);
|
||||
for (j = firstrow; j <= lastrow; j++)
|
||||
{
|
||||
int diff = ctx->get_deviation (ctx,
|
||||
row1,
|
||||
row2);
|
||||
if ((j == firstrow) || (diff < bestdiff))
|
||||
{
|
||||
bestdiff = diff;
|
||||
bestmatch = j;
|
||||
}
|
||||
row2 = g_slist_next (row2);
|
||||
}
|
||||
offsets[i / 2] = bestmatch - i;
|
||||
fp_dbg ("%d", offsets[i / 2]);
|
||||
row1 = g_slist_next (row1);
|
||||
if (row1)
|
||||
row1 = g_slist_next (row1);
|
||||
}
|
||||
|
||||
median_filter(offsets, (num_lines / 2) - 1, ctx->median_filter_size);
|
||||
median_filter (offsets, (num_lines / 2) - 1, ctx->median_filter_size);
|
||||
|
||||
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
|
||||
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
||||
fp_dbg("%d", offsets[i]);
|
||||
row1 = lines;
|
||||
for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next(row1)) {
|
||||
int offset = offsets[i/2];
|
||||
if (offset > 0) {
|
||||
float ynext = y + (float)ctx->resolution / offset;
|
||||
while (line_ind < ynext) {
|
||||
if (line_ind > ctx->max_height - 1)
|
||||
goto out;
|
||||
interpolate_lines(ctx,
|
||||
row1, y,
|
||||
g_slist_next(row1),
|
||||
ynext,
|
||||
output + line_ind * ctx->line_width,
|
||||
line_ind,
|
||||
ctx->line_width);
|
||||
line_ind++;
|
||||
}
|
||||
y = ynext;
|
||||
}
|
||||
}
|
||||
fp_dbg ("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time ());
|
||||
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
||||
fp_dbg ("%d", offsets[i]);
|
||||
row1 = lines;
|
||||
for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next (row1))
|
||||
{
|
||||
int offset = offsets[i / 2];
|
||||
if (offset > 0)
|
||||
{
|
||||
gint32 ynext_f = y_f + (ctx->resolution << 16) / offset;
|
||||
while ((line_ind << 16) < ynext_f)
|
||||
{
|
||||
if (line_ind > ctx->max_height - 1)
|
||||
goto out;
|
||||
interpolate_lines (ctx,
|
||||
row1, y_f,
|
||||
g_slist_next (row1),
|
||||
ynext_f,
|
||||
output + line_ind * ctx->line_width,
|
||||
line_ind << 16,
|
||||
ctx->line_width);
|
||||
line_ind++;
|
||||
}
|
||||
y_f = ynext_f;
|
||||
}
|
||||
}
|
||||
out:
|
||||
img = fpi_img_new(ctx->line_width * line_ind);
|
||||
img->height = line_ind;
|
||||
img->width = ctx->line_width;
|
||||
img->flags = FP_IMG_V_FLIPPED;
|
||||
g_memmove(img->data, output, ctx->line_width * line_ind);
|
||||
g_free(offsets);
|
||||
g_free(output);
|
||||
return img;
|
||||
img = fp_image_new (ctx->line_width, line_ind);
|
||||
img->height = line_ind;
|
||||
img->width = ctx->line_width;
|
||||
img->flags = FPI_IMAGE_V_FLIPPED;
|
||||
memmove (img->data, output, ctx->line_width * line_ind);
|
||||
g_free (offsets);
|
||||
g_free (output);
|
||||
return img;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user