This repository is for debugging and development purpose of the EgisTec (aka Lightuning) ES603 fingerprint device driver. All dated from 2012 and it is just a reincarnation of the google repository with some adjustments.
The asynchronous ES603 driver has been integrated into the mainline of libfprint. Please use latest libfprint library and report bugs in libfprint bugzilla.
etes603.c
: Synchronous driverfake_fp.c
: Fake functions of libfprint for debug purposecontact.c
: Program to test the contact detection of the devicedumpregs.c
: Program to dump all registers of the devicegui.c
: GUI program to debug calibration parametersMODE_FRAME
MODE_IMAGE
MODE_IMAGE_FULL
MODE_LOGGING
assemble.c
: Program to merge frames to compose a fingerprint imageleds.c
: Program to test LEDs of the device
All started in 2012 when I bought a laptop to replace my desktop computer. My choice was the Lenovo Essential B570. It comes with Windows 7 Home edition so the first thing I did was to change the HDD to the SSD from my old desktop PC and to install Ubuntu. After fixing the different issues (GPT partition, 3Gb SATA link, wifi, ...), I focused on the embedded fingerprint device.
lsusb
command gives this:
Bus 002 Device 003: ID 1c7a:0603 LighTuning Technology Inc.
LighTuning was bought by EgisTec few years ago but both does not provide linux support of the device. On linux, libfprint seems the most advanced framework for fingerprint. My search about EgisTec ended to the driver from Alexey for the SS801U device. However, the device embedded in my laptop is a ES603 and after testing, I concluded my device was not compatible.
I could wait someone to implement the driver but since I had no experience about this, I decided to put hands under the hood. Here the plan:
- Use the Windows support to monitor USB traffic between the fingerprint device and the host
- Create a simple linux application to communicate with a USB device
- Understand part of the traces and protocol to implement it into the testing application
- Iterate previous step until the protocol is reversed to capture a fingerprint
- Add support to libfprint
Once booted on Windows, let's try to gather informations! A quick search on EgisTec website to find the ES603 characteristics (it could help to understand the protocol):
- ES603 (AF or WB?)
- 192 x 4 pixels @ 508 dpi
- auto-calibration technology
- finger detection: based on E-Field (AC-Capacitance)
- Imaging/navigating mode: Typical 15 mA
- Finger detection mode: Typical <500uA
- Fly-Estimation® technology delivers complete fingerprint without image reconstruction.
Two files compose the Windows driver:
fpsensor.sys
: Low level drivernbmats1sdk.dll
: High level driver
Egistec BioExcess software permits to exploit this driver on Windows.
In order to understand the protocol, we need to capture the USB communication on Windows 7. I used different softwares but two are quite good. USBlyzer has a trial version for 33 days however data frame size is also limited. USBSnoop is free but it is not easy to install and to make it work properly. All the captured traces will be used to reverse engineer how to communicate with the device. To understand properly the protocol, we need a lot of traces from device activation and deactivation, from no finger, from one finger, from many fingers, ...
The first thing you figure out is the fixed header of usb frames (see Analysis section). The rest is much more difficult to understand and even with extensive testing I did not figure out all the purpose of all registers (EgisTec, please release the specifications). Since I have no experience about fingerprint device, I read briefly sources of other drivers in the libfprint package.
I developped a small C application with GUI and synchronous usb communcation to figure out how the sensor works. The second step was to implement the protocol for libfprint (asynchronous usb communication) and to test it with fprint_demo. The code was available at code.google.com/p/etes603/ (Now dead) but it now integrated into libfprint library.
I sold my Lenovo computer in 2014 and so I do not have access to the device anymore. However, if you want to experience the driver, the USB dongle is really cheap and can be found at DealExtreme: SKU 109073 Mini USB 2.0 Biometric Fingerprint Reader Password Security Lock for PC about USD 14.
The device uses endpoint 0x02 to send a request (from host to device) and endpoint 0x81 to receive (from device to host).
The fixed header of usb frames (5 bytes):
- Host to device:
'E' 'G' 'I' 'S' 0x09
- Device to host:
'S' 'I' 'G' 'E' 0x0A
In this following tables, this is all registers used in the driver. However I was not able to determine purposes of all registers.
Register number | Register purpose | Register values |
---|---|---|
0x02 | Mode control | Sleep:0x30 Contact:0x31 Sensor:0x33 FlyEstimation:0x34 |
0x03 | Contact register/capacitance? | (value >> 4) & 0x1 = 1 if finger contact otherwise 0 |
0x04 | ? | |
0x10 | MVS FRMBUF control | |
0x1A | ? | |
0x20 | ? | def: 0x00 |
0x21 | Small gain | def: 0x23 |
0x22 | Normal gain | def: 0x21 |
0x23 | Large gain | def: 0x20 |
0x24 | ? | def: 0x14 |
0x25 | ? | def: 0x6A |
0x26 | VRB again? | def: 0x00 |
0x27 | VRT again? | def: 0x00 |
0x28 | ? | def: 0x00 |
0x29 | ? | def: 0xC0 |
0x2A | ? | def: 0x50 |
0x2B | ? | def: 0x50 |
0x2C | ? | def: 0x4D |
0x2D | ? | def: 0x03 |
0x2E | ? | def: 0x06 |
0x2F | ? | def: 0x06 |
0x30 | ? | def: 0x10 |
0x31 | ? | def: 0x02 |
0x32 | ? | def: 0x14 |
0x33 | ? | def: 0x34 |
0x34 | ? | def: 0x01 |
0x35 | ? | def: 0x08 |
0x36 | ? | def: 0x03 |
0x37 | ? | def: 0x21 |
0x41 | Encryption byte1 | def: 0x12 |
0x42 | Encryption byte2 | def: 0x34 |
0x43 | Encryption byte3 | def: 0x56 |
0x44 | Encryption byte4 | def: 0x78 |
0x45 | Encryption byte5 | def: 0x90 |
0x46 | Encryption byte6 | def: 0xAB |
0x47 | Encryption byte7 | def: 0xCD |
0x48 | Encryption byte8 | def: 0xEF |
0x50 | required for contact detection? | init: 0x0F valid: value | 0x80 / 0x8F |
0x51 | ? | valid: value & 0xF7 / 0x30 |
0x59 | ? | valid: 0x18 |
0x5A | ? | valid: 0x08 |
0x5B | ? | valid: 0x00/0x10 |
0x70 | Sensor model byte0 (version?, firmware?) | def: 0x4A |
0x71 | Sensor model byte1 | def: 0x44 |
0x72 | Sensor model byte2 | def: 0x49 |
0x73 | Sensor model byte3 | def: 0x31 |
0x93 | ? | |
0x94 | ? | |
0xE0 | Sensor Gain | init: 0x04, GAIN_SMALL_INIT: 0x23 (default gain) |
0xE1 | For brightness and contrast | Maximum value for VRT: 0x3F |
0xE2 | For brightness and contrast | Maximum value for VRB: 0x3A |
0xE3 | Used for contact detection | Maximum value for DTVRT: 0x3A |
0xE5 | VCO Control | 0x13 (IDLE?), 0x14 (REALTIME) |
0xE6 | DC Offset | Minimum value for DCoffset: 0x00 Maximum value for DCoffset: 0x35 |
0xF0 | ? | init:0x00 close:0x01 |
0xF2 | ? | init:0x00 close:0x4E |
Request:
CMD_READ_REG NN XX ...
CMD_READ_REG
is 0x01.
NN is the number of registers to read.
XX are the registers number.
Answer:
CMD_OK XX ...
CMD_OK
is 0x01.
XX are register values.
Request:
CMD_WRITE_REG NN XX YY ...
CMD_WRITE_REG
is 0x02.
NN is the number of registers to write.
XX are the registers number.
YY are the new registers values.
Answer:
CMD_OK
Request:
WIDTH, 0x01, GAIN, VRT, VRB
WIDTH, 0x00, 0x00, 0x00, 0x00
it seems that the only working WIDTH is 0xC0 (192) and it the only value used in the windows driver. If the second byte is 0, registers for GAIN/VRT/VRB will be used.
Answer:
RAWDATA
Frame is 384 bytes long (depending on WIDTH). The image encoding is 4 bits per pixel raw image. So the resulting image is 192 * 4 pixels.
Image capture (aka Fly-Estimation%reg; technology) completes fingerprint without software reconstruction.
Request:
HEIGHT0, HEIGHT1, UNK1, UNK2, UNK3
0xF4, 0x02, 0x01, 0x64, 0x00
In the windows driver, values are fixed to the above values.
1st 2nd bytes is unsigned short for height, but only on value range:
0x01 0xF4 (500), 0x02 0x00 (512), 0x02 0xF4 (756) are ok.
3rd byte : ?? but changes frame size.
4th byte : ??.
5th byte : motion sensibility?.
Answer:
RAWDATA
The sensor buffered 64000 bytes of data. The encoding used is a 4 bits raw.
So the resulting image is 256*500
pixels.
The command is synchronous (blocking).
Some models have 2 LEDs (red and blue) that can be controlled with CMD 0x60.
Request CMD 0x60: ask status of LEDs:
0x60 0x01
Answer CMD 0x60: returns OK and status of LEDs
CMD_OK 0xXX
Request CMD 0x60 write: set status of LEDs
0x60 0x02 0xXX
None: 0x00 Red: 0x10 Blue: 0x20 Red+Blue: 0x10|0x20 = 0x30 (Unknown behaviour with value 0x11, 0x21, 0x31)
Answer CMD 0x60 write:
CMD_OK 0xXX
I was not able to determine the exact purpose of those commands.
Request CMD 0x20:
0x20
Answer CMD 0x20:
0x05 0x00 0x00
Request CMD 0x25:
0x25
Answer CMD 0x25:
CMD_OK 0x00
- Set initial values:
gain=0x23 min_dcoffset=0x00 max_dcoffset=0x35
- Get a frame with the current gain and use fixed
vrt=0x15 vrb=0x10
- Use dichotomy to find at what dcoffset value the frame start to be completely black
- Reduce gain if cannot get a completely black frame
DTVRT tuning permit to detect finger contact with the sensor.
- Read registers
0x50, 0x51, 0x59, 0x5A, 0x5B
to reset the initial values at the end of tuning - Change to sleep mode
- Set
VCO_CONTROL
toVCO_IDLE
- Set register
0x50
tovalue | 0x80
- Set register
0x51
tovalue & 0xF7
- Set registers
0x59
to0x18, 0x5A
to0x08
and0x5B
to0x00
- Change to contact mode
- Set
DTVRT
to MAX - Read register
0x03
to value - If
(value >> 4) & 1 == 1
, then we found the tunedDTVRT
value (current + 5) - Else Set
DTVRT
register to current - 5 and read register0x03
until contact is found - If
DTVRT
reaches 0, reduce DCoffset of 1 and restart tuning
- Initial values are
VRT = 0x0A
,VRB = 0x10
- Reduce DCoffset of 1 (reset it at the end of this tuning)
- Get a frame with this specific vrt/vrb and gain found in tune DCoffset
- Calculate the histogram of the image
- The image should not have more than 95% of black or white pixel (otherwise need to decrease/increase DCoffset)
- increase VRT/VRB until you found a balanced image
The detection of a finger can be done in different ways. The first way is to capture contiguously frames and that if the frame is black or not. But the sensor has a specific way to detect the finger contact with the E-Field (as advertised on the website). Following how to use the E-Field:
- Change to mode contact
- Set registers
0x59
to0x18
,0x5A
to0x08
,0x5B
to0x10
- Read register
0x50
and set it to(value & 0x7F) | 0x80
- Read register
0x03
until value is(value >> 4) & 0x1 == 1
which indicates contact - Add sleep of 5ms between each read and add a timeout
- When done, change to sleep mode
You may have to change rights to access the fingerprint device for non-root:
lsusb -d 1c7a:0603
to figure out the bus device idsudo chmod a+rw /dev/bus/usb/00X/00Y
but the better way to set rights at each reboot is to add a udev rules.
Create the file /etc/udev/rules.d/90-egis.rules
with the following content:
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="1c7a", ATTR{idProduct}=="0603", MODE="0666"
You can experience some problem with the driver when debugging, in this case the device can disconnect and reconnect but then the number on the USB bus changed. So you need to change again the permission. The device could be also in a weird state, unplug it and replug it.
Thanks to all people who helps to test the driver with special thanks to:
- Chase Montgomery (BLuFeNiX)
- Matthias Macha
- Vasily Khoruzhick