Hi all,
I have a attached a patch for the Gustavo's new FDU 2000 driver that
implements the image resampling from 398x300 to 260x300. It also includes
some code cleanups and leak fixes (valgrind is still coughing up loads of
them).
Since I am not an experienced driver/usb developer, I would really like some
feedback.
Thanks,
Dave.
--- /home/dave/fprint-original/libfprint/libfprint/drivers/fdu2000.c 2008-01-05 11:10:04.000000000 -0300
+++ fdu2000.c 2008-01-05 10:57:16.000000000 -0300
@@ -2,6 +2,8 @@
* Secugen FDU2000 driver for libfprint
* Copyright (C) 2007 Gustavo Chain <[EMAIL PROTECTED]>
*
+ * Copyright (C) 2008 Davidlohr Bueso <[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
@@ -17,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
@@ -27,11 +30,11 @@
#include <fp_internal.h>
#ifndef HAVE_MEMMEM
-gpointer
-memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
- const gchar *begin;
+void *
+memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) {
+ const char *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)
@@ -44,19 +47,36 @@
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))
+ !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 | USB_ENDPOINT_IN )
-#define EP_REPLY ( 0x01 | USB_ENDPOINT_IN )
-#define EP_CMD ( 0x01 | USB_ENDPOINT_OUT )
-#define BULK_TIMEOUT 200
+#define EP_IMAGE ( 0x02 | USB_ENDPOINT_IN )
+#define EP_REPLY ( 0x01 | USB_ENDPOINT_IN )
+#define EP_CMD ( 0x01 | USB_ENDPOINT_OUT )
+#define BULK_TIMEOUT 200
+
+
+#define ET_INDEX 0 /* left Offset */
+#define ET_FLIP 1 /* vertical Flip Image. 0: No Flip, 1: Flip */
+#define ET_MULTIFLY 1.1 /* Contrast. > 0 */
+#define ET_FLAG_INVERT 255 /* invertion.0: Normal, 255: Inverted */
+
+#define FINAL_IMAGE_WIDTH 260
+#define FINAL_IMAGE_HEIGHT 300
+#define FINAL_IMAGE_SIZE FINAL_IMAGE_HEIGHT * FINAL_IMAGE_WIDTH
+
+#define RAW_IMAGE_WIDTH 398
+#define RAW_IMAGE_HEIGHT 301
+#define RAW_IMAGE_SIZE RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGHT
+
+#define ET_DIGIT 1000 /* precision */
+#define ET_DISTORTION 7 /* optic Distortion Magic Number. 7 */
/* fdu_req[] index */
typedef enum {
@@ -71,9 +91,9 @@
#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
+ 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 */
{
@@ -108,22 +128,24 @@
}
};
+
+
/*
* Write a command and verify reponse
*/
-static gint
+static int
bulk_write_safe(usb_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;
+
+ char reponse[ACK_LEN];
+ int r;
+ char *cmd = (gchar *)fdu_req[rIndex].cmd;
+ char *ack = (gchar *)fdu_req[rIndex].ack;
+ int ack_len = fdu_req[rIndex].ack_len;
r = usb_bulk_write(dev, EP_CMD, cmd, sizeof(cmd), BULK_TIMEOUT);
if (r < 0)
return r;
-
+
if (ack_len == 0)
return 0;
@@ -140,26 +162,67 @@
return 1; /* Error */
}
-static gint
-capture(struct fp_img_dev *dev, gboolean unconditional,
- struct fp_img **ret)
+
+/*
+ * Converts the image from 398 to 260 pixels on the X axis and stores it in dest
+ */
+void img_resample(unsigned char *source, unsigned char *dest)
{
-#define RAW_IMAGE_WIDTH 398
-#define RAW_IMAGE_HEIGTH 301
-#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
+ unsigned long pix_1, pix_2, pixel;
+ unsigned long line, j;
+ unsigned long source_depth, dest_depth;
+ unsigned long org_x, dest_x;
+ unsigned long intpl_x;
+ unsigned long calc_x;
+ unsigned long ratio;
+
+ for(line = 0; line < FINAL_IMAGE_HEIGHT; line++) {
+ org_x = ((ET_DISTORTION * ET_DIGIT) / RAW_IMAGE_HEIGHT) * line;
+ ratio = (RAW_IMAGE_WIDTH * ET_DIGIT - 2 * ((ET_DISTORTION * ET_DIGIT) / RAW_IMAGE_HEIGHT) * line) / FINAL_IMAGE_WIDTH;
+ source_depth = line * RAW_IMAGE_WIDTH;
+
+ if (ET_FLIP != 0)
+ dest_depth = (FINAL_IMAGE_HEIGHT - line) * FINAL_IMAGE_WIDTH;
+
+ else
+ dest_depth = line * FINAL_IMAGE_WIDTH;
+
+ for(j = 0; j < FINAL_IMAGE_WIDTH; j++) {
+ dest_x = j * ratio + org_x;
+ intpl_x = (dest_x / ET_DIGIT) * ET_DIGIT;
+ calc_x = dest_x - intpl_x;
+ pix_1 = source[ET_INDEX + intpl_x / ET_DIGIT + source_depth];
+ pix_2 = source[ET_INDEX + intpl_x / ET_DIGIT + 1 + source_depth];
+ pixel = (unsigned int)((((pix_1 * (ET_DIGIT - calc_x) ) / ET_DIGIT + (pix_2 * calc_x) / ET_DIGIT ) ^ ET_FLAG_INVERT) * ET_MULTIFLY);
+ dest[(FINAL_IMAGE_WIDTH - 1) - j + dest_depth] = (pixel > 255 ? 255 : (unsigned char)pixel);
+ }
+ }
+}
- struct fp_img *img = NULL;
- guint 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;
- gchar *image;
- gchar *p;
- guint offset;
- buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
- image = g_malloc0(RAW_IMAGE_SIZE);
+static int
+capture(struct fp_img_dev *dev, int unconditional, struct fp_img **ret)
+{
+
+ struct fp_img *img = NULL;
+ unsigned int bytes, r;
+ const char SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
+ // Start of line + { L L } (L: Line num) (8 nibbles)
+ const char SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 };
+ char *buffer;
+ char *image;
+ char *p;
+ unsigned int offset;
+ unsigned char *dest = malloc(FINAL_IMAGE_SIZE * 2);
+ memset(dest, 0, sizeof(dest));
+
+ buffer = malloc(RAW_IMAGE_SIZE * 6);
+ memset(buffer, 0, RAW_IMAGE_SIZE * 6); // clean the memory
+
+ image = malloc(RAW_IMAGE_SIZE);
+ memset(image, 0, sizeof(image));
+
if ((r = bulk_write_safe(dev->udev, LED_ON))) {
fp_err("Command: LED_ON");
goto out;
@@ -170,59 +233,61 @@
goto out;
}
-read:
+ read:
if ((r = bulk_write_safe(dev->udev, CAPTURE_READ))) {
fp_err("Command: CAPTURE_READ");
goto out;
}
/* Now we are ready to read from dev */
-
+
bytes = usb_bulk_read(dev->udev,
- EP_IMAGE,
- buffer, RAW_IMAGE_SIZE * 6,
- BULK_TIMEOUT * 10);
-
+ EP_IMAGE,
+ buffer, RAW_IMAGE_SIZE * 6,
+ BULK_TIMEOUT * 10);
+
if (bytes < 1)
goto read;
-
+
/*
* Find SOF (start of line)
*/
- p = memmem(buffer, RAW_IMAGE_SIZE * 6,
- (const gpointer)SOF, sizeof SOF);
+
+ p = memmem(buffer, RAW_IMAGE_SIZE * 6, (const void *)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 )
+ if ( i >= RAW_IMAGE_HEIGHT )
break;
-
+
offset = p - buffer;
p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
- (const gpointer)SOL, sizeof SOL);
+ (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;
+ bytes += RAW_IMAGE_WIDTH;
i++;
}
}
-
+
if ((r = bulk_write_safe(dev->udev, CAPTURE_END))) {
fp_err("Command: CAPTURE_END");
goto out;
@@ -234,50 +299,69 @@
}
img = fpi_img_new_for_imgdev(dev);
- memcpy(img->data, image, RAW_IMAGE_SIZE);
+
+ /* once the image is caputed, we have to resample it */
+ img_resample(image, dest);
+
+ memcpy(img->data, dest, FINAL_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);
+ free(dest);
+ free(buffer);
+ free(image);
+
+ return r;
+}
+
+/*
+ * Call when an error occurs, if claimed is non negative, then the device is released first
+ */
+static int err_quit(struct fp_img_dev *dev, const char *msg, int claimed, int r)
+{
+ if(claimed >= 0)
+ usb_release_interface(dev->udev, 0);
+
+
+ if(msg != NULL)
+ fp_err(msg);
+ fp_err(usb_strerror());
return r;
}
+
static
-gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
+int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
- gint r;
+ int r;
if ( (r = usb_set_configuration(dev->udev, 1)) < 0 )
- goto out;
-
+ err_quit(dev, "could not init dev", -1, r);
+
+
if ( (r = usb_claim_interface(dev->udev, 0)) < 0 )
- goto out;
-
+ err_quit(dev, "could not init dev", -1, r);
+
+
if ( (r = usb_set_altinterface(dev->udev, 1)) < 0 )
- goto out;
+ err_quit(dev, "could not init dev", 1, r);
+
if ( (r = usb_clear_halt(dev->udev, EP_CMD)) < 0 )
- goto out;
-
+ err_quit(dev, "could not init dev", 1, r);
+
+
/* Make sure sensor mode is not capture_{ready|read} */
- if ((r = bulk_write_safe(dev->udev, CAPTURE_END))) {
- fp_err("Command: CAPTURE_END");
- goto out;
- }
-
- if ((r = bulk_write_safe(dev->udev, LED_OFF))) {
- fp_err("Command: LED_OFF");
- goto out;
- }
+ if ((r = bulk_write_safe(dev->udev, CAPTURE_END)))
+ err_quit(dev, "could not init dev [Command: CAPTURE_END]", 1, r);
+
+ if ((r = bulk_write_safe(dev->udev, LED_OFF)))
+ err_quit(dev, "could not init dev [Command: LED_OFF]", 1, r);
+
return 0;
-out:
- fp_err("could not init dev");
- fp_err(usb_strerror());
- return r;
}
static
@@ -301,10 +385,10 @@
.full_name = "Secugen FDU 2000",
.id_table = id_table,
},
- .img_height = RAW_IMAGE_HEIGTH,
- .img_width = RAW_IMAGE_WIDTH,
- .bz3_threshold = 23,
-
+ .img_height = FINAL_IMAGE_HEIGHT,
+ .img_width = FINAL_IMAGE_WIDTH,
+ .bz3_threshold = 18,
+
.init = dev_init,
.exit = dev_exit,
.capture = capture,
_______________________________________________
fprint mailing list
[email protected]
http://lists.reactivated.net/mailman/listinfo/fprint