Daniel Drake wrote:
I just spent some time sniffing what UPEK's new libbsapi is doing, and
produced a libusb-1.0 app to do the same. It works - it captures image
data. I'm not totally clear on the format, but the output file looks
quite nice when plotted as 8 bit greyscale with a width of 2306 pixels
(although the fingerprint is repeated).
Updated version attached which works from cold boot. Also it now uses
the hardware's finger detection capability and deinitializes the device
after the scan.
Another version which includes finger-removal detection and outputs
coherent images in pgm format. yay.
That was less effort than expected. I've mostly finished converting this
to a libfprint driver as well, expect that in the next few days.
Daniel
/*
* UPEK TouchStrip Sensor-Only mockup code
* Copyright (C) 2008 Daniel Drake <[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 <libusb.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define IMG_WIDTH 288
#define NUM_ROWS 500
static int last_seqnum = 16383;
static unsigned char imgbuf[IMG_WIDTH * NUM_ROWS];
static size_t imgbuf_row_offset = 0;
static unsigned char rowbuf[IMG_WIDTH];
static int rowbuf_offset = -1;
int wraparounds = -1;
static int num_blank = 0;
static int finger_removed = 0;
#define CAPTURING (imgbuf_row_offset < NUM_ROWS && !finger_removed)
static libusb_device_handle *handle;
static FILE *fd;
static const int wait_for_finger = 1;
static int read_reg(uint16_t index)
{
unsigned char buf[8];
int r;
r = libusb_control_transfer(handle, 0xc0, 0x0c, 0, index, buf, 8, 5000);
printf("read8 %x = %d: %02x %02x %02x %02x %02x %02x %02x %02x\n",
index, r,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
if (r < 0)
return r;
return buf[0];
}
static int write_reg(uint16_t reg, uint8_t val)
{
int r;
r = libusb_control_transfer(handle, 0x40, 0x0c, 0, reg, &val, 1, 5000);
printf("write reg %x = %d\n", reg, r);
return r;
}
static void bulkin(int len)
{
int actual;
unsigned char buf[len];
int r = libusb_bulk_transfer(handle, 0x81, buf, len, &actual, 5000);
printf("bulkin %d = %d,%d: %02x %02x %02x %02x %02x %02x %02x %02x
...\n",
len, actual, r,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}
static void intrin(void)
{
int actual;
unsigned char buf[4];
int r = libusb_interrupt_transfer(handle, 0x83, buf, 4, &actual, 5000);
printf("intrin %d,%d: %02x %02x %02x %02x...\n",
actual, r,
buf[0], buf[1], buf[2], buf[3]);
if (r < 0)
exit(1);
}
static int rowdiff(unsigned char *a, unsigned char *b, int *diff, int *total)
{
int i;
int r = 0;
int _total = 0;
int _diff = 0;
for (i = 0; i < IMG_WIDTH; i++) {
if (a[i] > b[i])
_diff += a[i] - b[i];
else
_diff += b[i] - a[i];
_total += b[i];
}
*diff = _diff;
*total = _total;
}
static void row_complete(void)
{
unsigned char *base = imgbuf + (imgbuf_row_offset * IMG_WIDTH);
rowbuf_offset = -1;
if (imgbuf_row_offset > 0) {
unsigned char *lastrow = base - IMG_WIDTH;
int diff;
int total;
rowdiff(lastrow, rowbuf, &diff, &total);
printf("row diff %d total %d\n", diff, total);
if (total < 52000) {
num_blank = 0;
} else {
num_blank++;
if (num_blank > 500) {
finger_removed = 1;
return;
}
}
if (diff < 3000)
return;
}
memcpy(base, rowbuf, IMG_WIDTH);
imgbuf_row_offset++;
}
/* add data to row buffer */
static void add_to_rowbuf(unsigned char *data, int size)
{
memcpy(rowbuf + rowbuf_offset, data, size);
rowbuf_offset += size;
if (rowbuf_offset >= IMG_WIDTH)
row_complete();
}
static int start_new_row(unsigned char *data, int size)
{
memcpy(rowbuf + IMG_WIDTH - 2, data, 2);
memcpy(rowbuf, data + 2, size - 2);
rowbuf_offset = size;
}
/* returns number of bytes left to be copied into rowbuf (capped to 62)
* or -1 if we aren't capturing anything */
static int rowbuf_remaining()
{
int r;
if (rowbuf_offset == -1)
return -1;
r = IMG_WIDTH - rowbuf_offset;
if (r > 62)
r = 62;
return r;
}
static void handle_packet(unsigned char *data)
{
uint16_t seqnum = data[0] << 8 | data[1];
int abs_base_addr;
int for_rowbuf;
data += 2;
//printf("handle_packet seq=%d\n", seqnum);
if (seqnum != last_seqnum + 1) {
if (seqnum != 0 && last_seqnum != 16383)
printf("LOST SOME DATA\n");
}
if (seqnum <= last_seqnum) {
printf("WRAPPED\n");
wraparounds++;
}
last_seqnum = seqnum;
seqnum += wraparounds * 16384;
abs_base_addr = seqnum * 62;
/* are we already capturing a row? if so append the data to the
* row buffer */
for_rowbuf = rowbuf_remaining();
if (for_rowbuf != -1) {
//printf("already capturing so append\n");
add_to_rowbuf(data, for_rowbuf);
return;
}
/* does the packet START on a boundary? if so we want it */
if (abs_base_addr % IMG_WIDTH == 0) {
//printf("start new row\n");
start_new_row(data, 62);
return;
}
/* does the data in the packet reside on an interesting row
boundary?
* if so capture it */
int next_row_addr = ((abs_base_addr / IMG_WIDTH) + 1) *
IMG_WIDTH;
int diff = next_row_addr - abs_base_addr;
if (diff < 62) {
//printf("start new row from offset %d\n", diff);
start_new_row(data + diff, 62 - diff);
}
}
static void bulkcb(struct libusb_transfer *transfer)
{
int i;
unsigned char *buf = transfer->buffer;
printf("cb stat=%d,%d\n", transfer->status, transfer->actual_length);
/* there are 64 packets in the transfer buffer
* each packet is 64 bytes in length
* the first 2 bytes are a sequence number
* then there are 62 bytes for image data
* we can regard a packet as offset (seq * 62) into the image
* image rows are 288 bytes wide
*/
for (i = 0; i < 4096; i += 64) {
int for_imgbuf = 0;
if (!CAPTURING)
return;
handle_packet(transfer->buffer + i);
}
if (CAPTURING) {
printf("resubmit\n");
libusb_submit_transfer(transfer);
} else {
printf("no resubmit, row offset=%d\n", imgbuf_row_offset);
}
}
static void onebulk(void)
{
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
unsigned char *buf = malloc(4096);
libusb_fill_bulk_transfer(transfer, handle, 0x81, buf, 4096, bulkcb,
NULL, 5000);
libusb_submit_transfer(transfer);
}
static void startbulk(void)
{
int i;
for (i = 0; i < 24; i++)
onebulk();
}
static int init3e(void)
{
int i;
int r;
const unsigned char data3e[] = {
0x83, 0x4f, 0x0f, 0xbf, 0x45, 0x35, 0x1c, 0xae
};
for (i = 0; i < sizeof(data3e); i++) {
r = write_reg(0x3e, data3e[i]);
if (r < 0)
return r;
}
return 0;
}
int main(void)
{
int r;
libusb_init(NULL);
handle = libusb_open_device_with_vid_pid(NULL, 0x147e, 0x2016);
if (!handle)
return 2;
/* ABSOpen */
libusb_set_configuration(handle, 1);
read_reg(0x17);
write_reg(0x49, 0x00);
init3e();
write_reg(0x44, 0x01);
write_reg(0x43, 0x06);
write_reg(0x43, 0x05);
read_reg(0x45);
write_reg(0x43, 0x04);
write_reg(0x44, 0);
write_reg(0x44, 0x9d);
write_reg(0x40, 0x1f);
write_reg(0x41, 0xb8);
write_reg(0x42, 0);
write_reg(0x43, 0x03);
read_reg(0x45);
bulkin(64);
write_reg(0x44, 0);
write_reg(0x44, 0x9d);
write_reg(0x40, 0x03);
write_reg(0x43, 0x03);
read_reg(0x45);
bulkin(64);
write_reg(0x44, 0x00);
write_reg(0x44, 0x9d);
write_reg(0x40, 0xff);
write_reg(0x41, 0xc0);
write_reg(0x43, 0x03);
read_reg(0x45);
read_reg(0x45);
bulkin(512);
write_reg(0x44, 0x00);
write_reg(0x44, 0x9d);
write_reg(0x41, 0x40);
write_reg(0x42, 0x03);
write_reg(0x43, 0x03);
read_reg(0x45);
read_reg(0x45);
bulkin(512);
write_reg(0x44, 0x00);
write_reg(0x44, 0x9d);
write_reg(0x42, 0x05);
write_reg(0x43, 0x03);
read_reg(0x45);
read_reg(0x45);
bulkin(512);
write_reg(0x44, 0);
write_reg(0x44, 0x9d);
write_reg(0x42, 0x07);
write_reg(0x43, 0x03);
read_reg(0x45);
read_reg(0x45);
bulkin(512);
write_reg(0x44, 0);
read_reg(0x17);
read_reg(0xb);
write_reg(0xb, 0);
r = read_reg(0x9);
if (r < 0)
return r;
write_reg(0x9, r & ~0x08);
r = read_reg(0x13);
if (r < 0)
return r;
write_reg(0x13, r & ~0x10);
write_reg(0x4, 0);
write_reg(0x5, 0);
/* ABSEnroll */
if (!wait_for_finger) {
printf("scan finger now\n");
sleep(1);
}
read_reg(0x17);
read_reg(0xa);
write_reg(0xa, 0);
read_reg(0xa);
write_reg(0xa, 0);
read_reg(0x9);
write_reg(0x09, 0x20);
read_reg(0x3);
write_reg(0x3, 0x3b);
read_reg(0x0);
write_reg(0x0, 0x67);
read_reg(0);
write_reg(0, 0x67);
r = read_reg(0x1);
if (r < 0)
return r;
else if (r != 0xc6)
/* cold boot */
write_reg(1, 0x46);
else
write_reg(1, 0xc6);
read_reg(1);
write_reg(1, 0xc6);
write_reg(0xc, 0x13);
write_reg(0xd, 0x0d);
write_reg(0xe, 0x0e);
write_reg(0xf, 0xd);
read_reg(0xb);
write_reg(0xb, 0);
r = read_reg(0x13);
if (r < 0)
return 1;
else if (r != 0x45)
/* cold boot */
write_reg(0x13, 0x05);
else
write_reg(0x13, 0x45);
read_reg(0x13);
write_reg(0x13, 0x45);
read_reg(0x30);
write_reg(0x30, 0xe0);
/* only happens for enroll */
if (!wait_for_finger) {
read_reg(0x13);
write_reg(0x13, 0x55);
}
read_reg(0x12);
write_reg(0x12, 0x01);
read_reg(0x20);
write_reg(0x20, 0x01);
read_reg(0x9);
write_reg(0x9, 0x20);
read_reg(0xa);
write_reg(0xa, 0);
read_reg(0x30);
write_reg(0x30, 0xe0);
read_reg(0x20);
write_reg(0x20, 0x01);
/* 90 cold, 10 warm */
r = read_reg(0x07);
if (r < 0)
return r;
if (r != 0x10 && r != 0x90)
printf("odd reg7 value %x\n", r);
write_reg(0x07, r);
read_reg(0x08);
write_reg(0x08, 0x00);
write_reg(0x10, 0x00);
read_reg(0x12);
write_reg(0x12, 0x01);
write_reg(0x11, 0xbf);
read_reg(0x12);
write_reg(0x12, 0x01);
read_reg(0x7);
write_reg(0x7, 0x10);
read_reg(0x7);
write_reg(0x7, 0x10);
write_reg(0x04, 0);
write_reg(0x5, 0);
read_reg(0x9);
read_reg(0xb);
read_reg(0x13);
read_reg(0x15);
read_reg(0x30);
read_reg(0xb);
write_reg(0xb, 0x00);
if (wait_for_finger) {
read_reg(0x15);
write_reg(0x15, 0x20),
read_reg(0x30);
write_reg(0x30, 0xe1);
read_reg(0x15);
write_reg(0x15, 0x24);
read_reg(0x15);
write_reg(0x15, 0x04);
read_reg(0x15);
write_reg(0x15, 0x84);
printf("wait for finger\n");
intrin();
write_reg(0x15, 0x20);
write_reg(0x30, 0xe0);
}
startbulk();
write_reg(0x09, 0x28);
write_reg(0x13, 0x55);
write_reg(0x0b, 0x80);
/* after some data comes in */
write_reg(0x4, 0);
write_reg(0x5, 0);
while (CAPTURING)
libusb_handle_events(NULL);
fd = fopen("data.out", "w");
fwrite(imgbuf, 1, sizeof(imgbuf), fd);
fclose(fd);
fd = fopen("data.pgm", "w");
fprintf(fd, "P5 %d %d 255 ", IMG_WIDTH, imgbuf_row_offset);
fwrite(imgbuf, 1, sizeof(imgbuf), fd);
fclose(fd);
/* deinit */
read_reg(0xb);
write_reg(0xb, 0);
read_reg(0x9);
write_reg(0x9, 0x20);
read_reg(0x13);
write_reg(0x13, 0x45);
read_reg(0x13);
write_reg(0x13, 0x45);
return 0;
}
_______________________________________________
fprint mailing list
[email protected]
http://lists.reactivated.net/mailman/listinfo/fprint