GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/vcom5s.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 15 137 10.9%
Functions: 3 16 18.8%
Branches: 4 29 13.8%

Line Branch Exec Source
1 /*
2 * Veridicom 5thSense driver for libfprint
3 * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #define FP_COMPONENT "vcom5s"
21
22 #include "drivers_api.h"
23
24 /* TODO:
25 * calibration?
26 * image size: windows gets 300x300 through vpas enrollment util?
27 * (probably just increase bulk read size?)
28 * powerdown? does windows do anything special on exit?
29 */
30
31 #define CTRL_TIMEOUT 1000
32 #define EP_IN (1 | FPI_USB_ENDPOINT_IN)
33
34 #define IMG_WIDTH 300
35 #define IMG_HEIGHT 288
36 #define ROWS_PER_RQ 12
37 #define NR_REQS (IMG_HEIGHT / ROWS_PER_RQ)
38 #define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
39 #define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
40
41 struct _FpDeviceVcom5s
42 {
43 FpImageDevice parent;
44
45 int capture_iteration;
46 FpImage *capture_img;
47 gboolean loop_running;
48 gboolean deactivating;
49 };
50 G_DECLARE_FINAL_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S,
51 FpImageDevice);
52
4/5
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
768 G_DEFINE_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE);
53
54 enum v5s_regs {
55 /* when using gain 0x29:
56 * a value of 0x00 produces mostly-black image
57 * 0x09 destroys ridges (too white)
58 * 0x01 or 0x02 seem good values */
59 REG_CONTRAST = 0x02,
60
61 /* when using contrast 0x01:
62 * a value of 0x00 will produce an all-black image.
63 * 0x29 produces a good contrast image: ridges quite dark, but some
64 * light grey noise as background
65 * 0x46 produces all-white image with grey ridges (not very dark) */
66 REG_GAIN = 0x03,
67 };
68
69 enum v5s_cmd {
70 /* scan one row. has parameter, at a guess this is which row to scan? */
71 CMD_SCAN_ONE_ROW = 0xc0,
72
73 /* scan whole image */
74 CMD_SCAN = 0xc1,
75 };
76
77 /***** REGISTER I/O *****/
78
79 static void
80 sm_write_reg (FpiSsm *ssm,
81 FpDevice *dev,
82 unsigned char reg,
83 unsigned char value)
84 {
85 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
86
87 fp_dbg ("set %02x=%02x", reg, value);
88 fpi_usb_transfer_fill_control (transfer,
89 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
90 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
91 G_USB_DEVICE_RECIPIENT_DEVICE,
92 reg, value, 0, 0);
93 transfer->ssm = ssm;
94 fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
95 fpi_ssm_usb_transfer_cb, NULL);
96 }
97
98 static void
99 sm_exec_cmd (FpiSsm *ssm,
100 FpDevice *dev,
101 unsigned char cmd,
102 unsigned char param)
103 {
104 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
105
106 fp_dbg ("cmd %02x param %02x", cmd, param);
107 fpi_usb_transfer_fill_control (transfer,
108 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
109 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
110 G_USB_DEVICE_RECIPIENT_DEVICE,
111 cmd, param, 0, 0);
112 transfer->ssm = ssm;
113 fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
114 fpi_ssm_usb_transfer_cb, NULL);
115 }
116
117 /***** FINGER DETECTION *****/
118
119 /* We take 64x64 pixels at the center of the image, determine the average
120 * pixel intensity, and threshold it. */
121 #define DETBOX_ROW_START 111
122 #define DETBOX_COL_START 117
123 #define DETBOX_ROWS 64
124 #define DETBOX_COLS 64
125 #define DETBOX_ROW_END (DETBOX_ROW_START + DETBOX_ROWS)
126 #define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
127 #define FINGER_PRESENCE_THRESHOLD 100
128
129 static gboolean
130 finger_is_present (unsigned char *data)
131 {
132 int row;
133 guint16 imgavg = 0;
134
135 for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++)
136 {
137 unsigned char *rowdata = data + (row * IMG_WIDTH);
138 guint16 rowavg = 0;
139 int col;
140
141 for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
142 rowavg += rowdata[col];
143 rowavg /= DETBOX_COLS;
144 imgavg += rowavg;
145 }
146 imgavg /= DETBOX_ROWS;
147 fp_dbg ("img avg %d", imgavg);
148
149 return imgavg <= FINGER_PRESENCE_THRESHOLD;
150 }
151
152
153
154 /***** IMAGE ACQUISITION *****/
155
156 static void capture_iterate (FpiSsm *ssm,
157 FpDevice *dev);
158
159 static void
160 capture_cb (FpiUsbTransfer *transfer, FpDevice *device,
161 gpointer user_data, GError *error)
162 {
163 FpImageDevice *imgdev = FP_IMAGE_DEVICE (device);
164 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (device);
165
166 if (error)
167 {
168 fpi_ssm_mark_failed (transfer->ssm, error);
169 return;
170 }
171
172 if (++self->capture_iteration == NR_REQS)
173 {
174 FpImage *img = self->capture_img;
175 /* must clear this early, otherwise the call chain takes us into
176 * loopsm_complete where we would free it, when in fact we are
177 * supposed to be handing off this image */
178 self->capture_img = NULL;
179
180 fpi_image_device_report_finger_status (imgdev,
181 finger_is_present (img->data));
182 fpi_image_device_image_captured (imgdev, img);
183 fpi_ssm_next_state (transfer->ssm);
184 }
185 else
186 {
187 capture_iterate (transfer->ssm, device);
188 }
189 }
190
191 static void
192 capture_iterate (FpiSsm *ssm,
193 FpDevice *dev)
194 {
195 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
196 int iteration = self->capture_iteration;
197 FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
198
199 transfer->ssm = ssm;
200 transfer->short_is_error = TRUE;
201 fpi_usb_transfer_fill_bulk_full (transfer,
202 EP_IN,
203 self->capture_img->data + (RQ_SIZE * iteration),
204 RQ_SIZE,
205 NULL);
206
207 fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL);
208 }
209
210
211 static void
212 sm_do_capture (FpiSsm *ssm,
213 FpDevice *dev)
214 {
215 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
216 FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev);
217
218 G_DEBUG_HERE ();
219 self->capture_img = fp_image_new (cls->img_width, cls->img_height);
220 self->capture_iteration = 0;
221 capture_iterate (ssm, dev);
222 }
223
224 /***** CAPTURE LOOP *****/
225
226 enum loop_states {
227 LOOP_SET_CONTRAST,
228 LOOP_SET_GAIN,
229 LOOP_CMD_SCAN,
230 LOOP_CAPTURE,
231 LOOP_CAPTURE_DONE,
232 LOOP_NUM_STATES,
233 };
234
235 static void
236 loop_run_state (FpiSsm *ssm, FpDevice *dev)
237 {
238 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
239
240 switch (fpi_ssm_get_cur_state (ssm))
241 {
242 case LOOP_SET_CONTRAST:
243 sm_write_reg (ssm, dev, REG_CONTRAST, 0x01);
244 break;
245
246 case LOOP_SET_GAIN:
247 sm_write_reg (ssm, dev, REG_GAIN, 0x29);
248 break;
249
250 case LOOP_CMD_SCAN:
251 if (self->deactivating)
252 {
253 fp_dbg ("deactivating, marking completed");
254 fpi_ssm_mark_completed (ssm);
255 }
256 else
257 {
258 sm_exec_cmd (ssm, dev, CMD_SCAN, 0x00);
259 }
260 break;
261
262 case LOOP_CAPTURE:
263 sm_do_capture (ssm, dev);
264 break;
265
266 case LOOP_CAPTURE_DONE:
267 fpi_ssm_jump_to_state (ssm, LOOP_CMD_SCAN);
268 break;
269
270 default:
271 g_assert_not_reached ();
272 }
273 }
274
275 static void
276 loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
277 {
278 FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev);
279 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
280
281 g_object_unref (self->capture_img);
282 self->capture_img = NULL;
283 self->loop_running = FALSE;
284
285 if (error && !self->deactivating)
286 fpi_image_device_session_error (imgdev, error);
287 else if (error)
288 g_error_free (error);
289
290 if (self->deactivating)
291 fpi_image_device_deactivate_complete (imgdev, NULL);
292 }
293
294 static void
295 dev_activate (FpImageDevice *dev)
296 {
297 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
298 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, LOOP_NUM_STATES);
299
300 self->deactivating = FALSE;
301 fpi_ssm_start (ssm, loopsm_complete);
302 self->loop_running = TRUE;
303 fpi_image_device_activate_complete (dev, NULL);
304 }
305
306 static void
307 dev_deactivate (FpImageDevice *dev)
308 {
309 FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
310
311 if (self->loop_running)
312 self->deactivating = TRUE;
313 else
314 fpi_image_device_deactivate_complete (dev, NULL);
315 }
316
317 static void
318 dev_init (FpImageDevice *dev)
319 {
320 GError *error = NULL;
321
322 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
323
324 fpi_image_device_open_complete (dev, error);
325 }
326
327 static void
328 dev_deinit (FpImageDevice *dev)
329 {
330 GError *error = NULL;
331
332 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
333 0, 0, &error);
334
335 fpi_image_device_close_complete (dev, error);
336 }
337
338 static const FpIdEntry id_table[] = {
339 { .vid = 0x061a, .pid = 0x0110, },
340 { .vid = 0, .pid = 0, .driver_data = 0 },
341 };
342
343 static void
344 fpi_device_vcom5s_init (FpDeviceVcom5s *self)
345 {
346 }
347
348 static void
349 120 fpi_device_vcom5s_class_init (FpDeviceVcom5sClass *klass)
350 {
351 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
352 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
353
354 120 dev_class->id = "vcom5s";
355 120 dev_class->full_name = "Veridicom 5thSense";
356 120 dev_class->type = FP_DEVICE_TYPE_USB;
357 120 dev_class->id_table = id_table;
358 120 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
359
360 120 img_class->img_open = dev_init;
361 120 img_class->img_close = dev_deinit;
362 120 img_class->activate = dev_activate;
363 120 img_class->deactivate = dev_deactivate;
364
365 120 img_class->img_width = IMG_WIDTH;
366 120 img_class->img_height = IMG_HEIGHT;
367 }
368