Commit b46d336d authored by Marco Trevisan's avatar Marco Trevisan Committed by Benjamin Berg
Browse files

examples: Add back examples using the async APIs

Add the examples back by using the new async API, support verification and
enroll for devices with own storage.
parent 7d6b0c13
......@@ -6,6 +6,10 @@
int main (int argc, char **argv)
{
fp_init ();
FpContext *ctx;
ctx = fp_context_new ();
g_object_unref (ctx);
return 0;
}
......@@ -2,6 +2,7 @@
* Example fingerprint enrollment program
* Enrolls your right index 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,91 +20,128 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
#include "storage.h"
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
typedef struct _EnrollData {
GMainLoop *loop;
int ret_value;
} EnrollData;
static void
enroll_data_free (EnrollData *enroll_data)
{
g_main_loop_unref (enroll_data->loop);
g_free (enroll_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free)
FpDevice *discover_device (GPtrArray *devices)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
FpDevice *dev;
if (!devices->len)
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;
dev = g_ptr_array_index (devices, 0);
printf("Found device claimed by %s driver\n", fp_device_get_driver (dev));
return dev;
}
struct fp_print_data *enroll(struct fp_dev *dev) {
struct fp_print_data *enrolled_print = NULL;
int r;
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) {
EnrollData *enroll_data = user_data;
g_autoptr(GError) error = NULL;
printf("You will need to successfully scan your finger %d times to "
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
fp_device_close_finish (dev, res, &error);
do {
struct fp_img *img = NULL;
if (error)
g_warning ("Failed closing device %s\n", error->message);
printf("\nScan your finger now.\n");
g_main_loop_quit (enroll_data->loop);
}
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;
}
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);
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;
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, FP_FINGER_RIGHT_INDEX);
if (r < 0) {
g_warning("Data save failed, code %d", r);
enroll_data->ret_value = EXIT_FAILURE;
}
}
} while (r != FP_ENROLL_COMPLETE);
} else {
g_warning("Enroll failed with error %s\n", error->message);
}
if (!enrolled_print) {
fprintf(stderr, "Enroll complete but no print?\n");
return NULL;
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("Enrollment completed!\n\n");
return enrolled_print;
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 finger %d times to "
"complete the process.\n\n", fp_device_get_nr_enroll_stages (dev));
printf ("Scan your finger now.\n");
print_template = print_create_template (dev, FP_FINGER_RIGHT_INDEX);
fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL,
NULL, (GAsyncReadyCallback) on_enroll_completed,
enroll_data);
}
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;
g_autoptr (FpContext) ctx = NULL;
g_autoptr (EnrollData) enroll_data = NULL;
GPtrArray *devices;
FpDevice *dev;
printf("This program will enroll your right index finger, "
"unconditionally overwriting any right-index print that was enrolled "
......@@ -112,48 +150,29 @@ int main(void)
getchar();
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;
}
ctx = fp_context_new ();
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
devices = fp_context_get_devices (ctx);
if (!devices) {
g_warning("Impossible to get devices");
return EXIT_FAILURE;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
dev = discover_device (devices);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
g_warning("No devices detected.");
return EXIT_FAILURE;
}
printf("Opened device. It's now time to enroll your finger.\n\n");
data = enroll(dev);
if (!data)
goto out_close;
r = print_data_save(data, RIGHT_INDEX);
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;
}
enroll_data = g_new0 (EnrollData, 1);
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;
}
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
examples = [ 'enroll', 'verify', 'manage-prints' ]
foreach example: examples
executable(example,
[example + '.c', 'storage.c'],
dependencies: [libfprint_dep],
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)
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',
......
......@@ -2,6 +2,7 @@
* 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
......@@ -18,41 +19,41 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <glib.h>
#include <libfprint/fprint.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
#define STORAGE_FILE "test-storage.variant"
static char *
get_print_data_descriptor (struct fp_print_data *data, struct fp_dev *dev, enum fp_finger finger)
get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
{
gint drv_id;
gint devtype;
const char *driver;
const char *dev_id;
if (data) {
drv_id = fp_print_data_get_driver_id (data);
devtype = fp_print_data_get_devtype (data);
if (print) {
driver = fp_print_get_driver (print);
dev_id = fp_print_get_device_id (print);
} else {
drv_id = fp_driver_get_driver_id(fp_dev_get_driver (dev));
devtype = fp_dev_get_devtype (dev);
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
}
return g_strdup_printf("%x/%08x/%x",
drv_id,
devtype,
return g_strdup_printf("%s/%s/%x",
driver,
dev_id,
finger);
}
static GVariantDict*
static GVariantDict *
load_data(void)
{
GVariantDict *res;
GVariant *var;
gchar *contents = NULL;
g_autofree gchar *contents = NULL;
gssize length = 0;
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) {
......@@ -88,49 +89,125 @@ save_data(GVariant *data)
}
int
print_data_save(struct fp_print_data *fp_data, enum fp_finger finger)
print_data_save(FpPrint *print, FpFinger finger)
{
gchar *descr = get_print_data_descriptor (fp_data, NULL, finger);
GVariantDict *dict;
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;
guchar *data;
gsize size;
int res;
dict = load_data();
size = fp_print_data_get_data(fp_data, &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));
g_variant_dict_unref(dict);
return res;
}
struct fp_print_data*
print_data_load(struct fp_dev *dev, enum fp_finger finger)
FpPrint *
print_data_load(FpDevice *dev, FpFinger finger)
{
gchar *descr = get_print_data_descriptor (NULL, dev, finger);
GVariantDict *dict;
guchar *stored_data;
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;
GVariant *val;
struct fp_print_data *res = NULL;
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);
res = fp_print_data_from_data(stored_data, stored_len);
print = fp_print_deserialize (stored_data, stored_len, &error);
g_variant_unref(val);
if (error)
g_warning ("Error deserializing data: %s", error->message);
return print;
}
g_variant_dict_unref(dict);
g_free(descr);
return NULL;
}
return res;
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;
}
......@@ -21,7 +21,10 @@
#ifndef __STORAGE_H
#define __STORAGE_H
int print_data_save(struct fp_print_data *fp_data, enum fp_finger finger);
struct fp_print_data* print_data_load(struct fp_dev *dev, enum fp_finger finger);
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 /* __STORAGE_H */
......@@ -2,6 +2,7 @@
* Example fingerprint verification program, which verifies the right index
* 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,131 +20,216 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
#include "storage.h"
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
typedef struct _VerifyData {
GMainLoop *loop;
int ret_value;
} VerifyData;
static void
verify_data_free (VerifyData *verify_data)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
g_main_loop_unref (verify_data->loop);
g_free (verify_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
FpDevice *discover_device (GPtrArray *devices)
{
FpDevice *dev;
if (!devices->len)
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;
dev = g_ptr_array_index (devices, 0);
printf("Found device claimed by %s driver\n", fp_device_get_driver (dev));
return dev;
}
int verify(struct fp_dev *dev, struct fp_print_data *data)
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);
}
static void start_verification (FpDevice *dev, VerifyData *verify_data);
static void
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
int r;
do {
struct fp_img *img = NULL;
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);
VerifyData *verify_data = user_data;
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
char buffer[20];
gboolean match;
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;