Hi Folks.
I'm developing the Secugen-FDU2000 driver for fprint.
Currently it show the finger image and make the match.
I need testers for feedback (please)
TODO:
1º Code cleanup.
2º Resample Image 398x300 -> 260x300
3º Testing.
4º Implement await_finger_on();
--
Gustavo Chaín Dumit
http://0xff.cl
/*
* Secugen FDU2000 driver for libfprint
* Copyright (C) 2007 Gustavo Chain <[EMAIL PROTECTED]>
*
* 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 <errno.h>
#include <string.h>
#include <unistd.h>
#include <usb.h>
#include <fp_internal.h>
#define FP_COMPONENT "fdu2000"
#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 char cmd[CMD_LEN]; // Command to send
const char ack[ACK_LEN]; // Expected ACK
const unsigned int 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 int
bulk_write_safe(usb_dev_handle *dev, req_index rIndex) {
char reponse[ACK_LEN];
int bytes, r;
char *cmd = (char *)fdu_req[rIndex].cmd;
char *ack = (char *)fdu_req[rIndex].ack;
int ack_len = fdu_req[rIndex].ack_len;
bytes = usb_bulk_write(dev, USB_ENDPOINT_TYPE_ISOCHRONOUS, cmd, sizeof(cmd), BULK_TIMEOUT);
if (bytes < 0) {
fp_err("%d: %s", __LINE__, usb_strerror());
}
if (ack_len == 0)
return bytes;
/* Check reply from FP */
r = usb_bulk_read (dev, USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_ISOCHRONOUS,
reponse, sizeof(reponse), BULK_TIMEOUT);
if (r < 0) {
fp_err(usb_strerror());
return r;
}
if (!strncmp(ack, reponse, ack_len))
return bytes;
fp_err("%d: ACK ERROR!", __LINE__);
return 0;
}
static int await_finger_on(struct fp_img_dev *dev)
{
return 0; /* Not Implemented */
}
static int capture(struct fp_img_dev *dev, gboolean unconditional,
struct fp_img **ret)
{
/* Pre resampled sizes */
#define RAW_IMAGE_WIDTH 404
#define RAW_IMAGE_HEIGTH 301
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
/* Resamples sizes */
#define SAMPLE_IMAGE_WIDTH 260
#define SAMPLE_IMAGE_HEIGTH 300
#define SAMPLE_IMAGE_SIZE (SAMPLE_IMAGE_WIDTH * SAMPLE_IMAGE_HEIGTH)
struct fp_img *img = NULL;
unsigned int bytes;
const char SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
const char SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 }; // Start of line + { L L } (L: Line num) (8 nibbles)
char *buffer;
char *image;
char *p;
int offset;
img = fpi_img_new_for_imgdev(dev);
buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
image = g_malloc0(RAW_IMAGE_SIZE);
bulk_write_safe(dev->udev, LED_ON);
bulk_write_safe(dev->udev, CAPTURE_READY);
bulk_write_safe(dev->udev, CAPTURE_READ);
/* Now we are ready to read from dev */
read:
bytes = usb_bulk_read(dev->udev,
USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_BULK,
buffer, RAW_IMAGE_SIZE * 6,
BULK_TIMEOUT * 10);
/*
* Find SOF (start of line)
*/
p = memmem(buffer, RAW_IMAGE_SIZE * 6,
SOF, sizeof SOF);
fp_dbg("Read %d byte/s from dev\n", bytes);
if (!p)
goto read;
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),
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 */
*(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++;
}
}
memcpy(img->data, image, RAW_IMAGE_SIZE);
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED;
*ret = img;
bulk_write_safe(dev->udev, CAPTURE_END);
bulk_write_safe(dev->udev, LED_OFF);
g_free(buffer);
g_free(image);
return 0;
}
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
int r;
r = usb_set_configuration(dev->udev, 1);
if (r < 0)
goto hell;
r = usb_claim_interface(dev->udev, USB_CLASS_PER_INTERFACE);
if (r < 0)
goto hell;
r = usb_set_altinterface(dev->udev, 1);
if (r < 0)
goto hell;
r = usb_clear_halt(dev->udev, USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_ISOCHRONOUS);
if (r < 0)
goto hell;
/* Make sure sensor mode is not capture_{ready|read} */
bulk_write_safe(dev->udev, CAPTURE_END);
return 0;
hell:
fp_err("could not init dev");
fp_err(usb_strerror());
return r;
}
static void dev_exit(struct fp_img_dev *dev)
{
int r;
bulk_write_safe(dev->udev, CAPTURE_END);
r = usb_release_interface(dev->udev, USB_CLASS_PER_INTERFACE);
if (r < 0)
fp_err("could not release interface");
}
static const struct usb_id id_table[] = {
{ .vendor = 0x1162, .product = 0x0300 },
{ 0, 0, 0, },
};
struct fp_img_driver fdu2000_driver = {
.driver = {
.id = 99,
.name = FP_COMPONENT,
.full_name = "Secugen FDU 2000",
.id_table = id_table,
},
.flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE,
.img_height = RAW_IMAGE_HEIGTH,
.img_width = RAW_IMAGE_WIDTH,
.init = dev_init,
.exit = dev_exit,
.await_finger_on = await_finger_on,
.capture = capture,
};
diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am
index 933ec69..fe6db4a 100644
--- a/libfprint/Makefile.am
+++ b/libfprint/Makefile.am
@@ -6,8 +6,9 @@ URU4000_SRC = drivers/uru4000.c
AES1610_SRC = drivers/aes1610.c
AES2501_SRC = drivers/aes2501.c drivers/aes2501.h
AES4000_SRC = drivers/aes4000.c
+FDU2000_SRC = drivers/fdu2000.c
-DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES1610_SRC) $(AES2501_SRC) $(AES4000_SRC) $(UPEKTC_SRC)
+DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES1610_SRC) $(AES2501_SRC) $(AES4000_SRC) $(UPEKTC_SRC) $(FDU2000_SRC)
NBIS_SRC = \
nbis/include/bozorth.h \
diff --git a/libfprint/core.c b/libfprint/core.c
index 1a5a146..d3cf3ff 100644
--- a/libfprint/core.c
+++ b/libfprint/core.c
@@ -334,6 +334,7 @@ static struct fp_img_driver * const img_drivers[] = {
&aes2501_driver,
&aes4000_driver,
&upektc_driver,
+ &fdu2000_driver
};
static void register_drivers(void)
diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h
index 96b82a9..da8e763 100644
--- a/libfprint/fp_internal.h
+++ b/libfprint/fp_internal.h
@@ -145,6 +145,7 @@ extern struct fp_img_driver uru4000_driver;
extern struct fp_img_driver aes1610_driver;
extern struct fp_img_driver aes2501_driver;
extern struct fp_img_driver aes4000_driver;
+extern struct fp_img_driver fdu2000_driver;
void fpi_img_driver_setup(struct fp_img_driver *idriver);
_______________________________________________
fprint mailing list
[email protected]
http://lists.reactivated.net/mailman/listinfo/fprint