GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/egis0570.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 170 177 96.0%
Functions: 17 17 100.0%
Branches: 51 60 85.0%

Line Branch Exec Source
1 /*
2 * Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
3 * Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
4 * Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "egis0570"
22
23 #include "egis0570.h"
24 #include "drivers_api.h"
25
26 /* Packet types */
27 #define PKT_TYPE_INIT 0
28 #define PKT_TYPE_REPEAT 1
29
30 /* Struct */
31 struct _FpDeviceEgis0570
32 {
33 FpImageDevice parent;
34
35 gboolean running;
36 gboolean stop;
37
38 GSList *strips;
39 guint8 *background;
40 gsize strips_len;
41
42 int pkt_num;
43 int pkt_type;
44 };
45 G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
46
4/5
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 117 times.
✗ Branch 4 not taken.
750 G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
47
48 static unsigned char
49 74881080 egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
50 {
51 74881080 return frame->data[x + y * ctx->frame_width];
52 }
53
54 static struct fpi_frame_asmbl_ctx assembling_ctx = {
55 .frame_width = EGIS0570_IMGWIDTH,
56 .frame_height = EGIS0570_RFMGHEIGHT,
57 .image_width = EGIS0570_IMGWIDTH * 4 / 3,
58 .get_pixel = egis_get_pixel,
59 };
60
61 /*
62 * Service
63 */
64
65 static gboolean
66 227 is_last_pkt (FpDevice *dev)
67 {
68 227 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
69
70 227 int type = self->pkt_type;
71 227 int num = self->pkt_num;
72
73 227 gboolean r;
74
75 227 r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
76 227 r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
77
78 227 return r;
79 }
80
81 /*
82 * Returns a bit for each frame on whether or not a finger has been detected.
83 * e.g. 00110 means that there is a finger in frame two and three.
84 */
85 static char
86 52 postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
87 {
88 52 size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
89
90
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 51 times.
52 if (!self->background)
91 {
92 1 self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
93 1 memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
94
95
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
96 {
97 5 guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
98
99
2/2
✓ Branch 0 taken 9690 times.
✓ Branch 1 taken 5 times.
9695 for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
100 9690 self->background[i] = MIN (self->background[i], frame[i]);
101 }
102
103 return 0;
104 }
105
106
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 51 times.
306 for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
107 {
108 255 guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
109
110
2/2
✓ Branch 0 taken 494190 times.
✓ Branch 1 taken 255 times.
494445 for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
111 {
112
2/2
✓ Branch 0 taken 178344 times.
✓ Branch 1 taken 315846 times.
494190 if (frame[i] - EGIS0570_MARGIN > self->background[i])
113 178344 frame[i] -= self->background[i];
114 else
115 315846 frame[i] = 0;
116
117 494190 mean[k] += frame[i];
118 }
119
120 255 mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
121 }
122
123 char result = 0;
124
125
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 51 times.
306 for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
126 {
127 255 fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
128
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 192 times.
255 if (mean[k] > EGIS0570_MIN_MEAN)
129 63 result |= 1 << k;
130 }
131
132 return result;
133 }
134
135 /*
136 * Device communication
137 */
138
139 static void
140 52 data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
141 {
142 52 unsigned char *stripdata;
143 52 gboolean end = FALSE;
144 52 FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
145 52 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
146
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (error)
148 {
149 fpi_ssm_mark_failed (transfer->ssm, error);
150 return;
151 }
152
153 52 int where_finger_is = postprocess_frames (self, transfer->buffer);
154
155
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 39 times.
52 if (where_finger_is > 0)
156 {
157 13 FpiImageDeviceState state;
158
159 13 fpi_image_device_report_finger_status (img_self, TRUE);
160
161 13 g_object_get (dev, "fpi-image-device-state", &state, NULL);
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
163 {
164
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 12 times.
73 for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
165 {
166
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 1 times.
61 if (where_finger_is & (1 << k))
167 {
168 60 struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
169 60 stripe->delta_x = 0;
170 60 stripe->delta_y = 0;
171 60 stripdata = stripe->data;
172 60 memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
173 60 self->strips = g_slist_prepend (self->strips, stripe);
174 60 self->strips_len += 1;
175 }
176 else
177 {
178 end = TRUE;
179 break;
180 }
181 }
182 }
183 }
184 else
185 {
186 end = TRUE;
187 }
188
189
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
13 if (end)
190 {
191
3/4
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 39 times.
40 if (!self->stop && (self->strips_len > 0))
192 {
193 1 g_autoptr(FpImage) img = NULL;
194 1 self->strips = g_slist_reverse (self->strips);
195 1 fpi_do_movement_estimation (&assembling_ctx, self->strips);
196 1 img = fpi_assemble_frames (&assembling_ctx, self->strips);
197 1 img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
198 1 g_slist_free_full (self->strips, g_free);
199 1 self->strips = NULL;
200 1 self->strips_len = 0;
201 1 FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
202 1 fpi_image_device_image_captured (img_self, g_steal_pointer (&resizeImage));
203 }
204
205 40 fpi_image_device_report_finger_status (img_self, FALSE);
206 }
207
208 52 fpi_ssm_next_state (transfer->ssm);
209 }
210
211 static void
212 52 recv_data_resp (FpiSsm *ssm, FpDevice *dev)
213 {
214 52 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
215
216 52 fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
217
218 52 transfer->ssm = ssm;
219 52 transfer->short_is_error = TRUE;
220
221 52 fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
222 52 }
223
224 static void
225 175 cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
226 {
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 175 times.
175 if (error)
228 fpi_ssm_mark_failed (transfer->ssm, error);
229 175 }
230
231 static void
232 175 recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
233 {
234 175 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
235
236 175 fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
237
238 175 transfer->ssm = ssm;
239
240 175 fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
241 175 }
242
243 static void
244 227 send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
245 {
246 227 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
247
248 227 fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
249
250 227 transfer->ssm = ssm;
251 227 transfer->short_is_error = TRUE;
252
253 227 fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
254 227 }
255
256 /*
257 * SSM States
258 */
259
260 enum sm_states {
261 SM_INIT,
262 SM_START,
263 SM_REQ,
264 SM_RESP,
265 SM_REC_DATA,
266 SM_DONE,
267 SM_STATES_NUM
268 };
269
270 static void
271 612 ssm_run_state (FpiSsm *ssm, FpDevice *dev)
272 {
273 612 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
274 612 FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
275
276
6/7
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 227 times.
✓ Branch 4 taken 227 times.
✓ Branch 5 taken 52 times.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
612 switch (fpi_ssm_get_cur_state (ssm))
277 {
278 1 case SM_INIT:
279 1 self->pkt_type = PKT_TYPE_INIT;
280 1 fpi_ssm_next_state (ssm);
281 1 break;
282
283 53 case SM_START:
284
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 52 times.
53 if (self->stop)
285 {
286 1 fp_dbg ("deactivating, marking completed");
287 1 fpi_ssm_mark_completed (ssm);
288 1 fpi_image_device_deactivate_complete (img_dev, NULL);
289 }
290 else
291 {
292 52 self->pkt_num = 0;
293 52 fpi_ssm_next_state (ssm);
294 }
295 break;
296
297 227 case SM_REQ:
298
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 204 times.
227 if (self->pkt_type == PKT_TYPE_INIT)
299 23 send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
300 else
301 204 send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
302 break;
303
304 case SM_RESP:
305
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 52 times.
227 if (is_last_pkt (dev) == FALSE)
306 {
307 175 recv_cmd_resp (ssm, dev);
308 175 self->pkt_num += 1;
309 175 fpi_ssm_jump_to_state (ssm, SM_REQ);
310 }
311 else
312 {
313
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 51 times.
52 if (self->pkt_type == PKT_TYPE_INIT)
314 1 self->pkt_type = PKT_TYPE_REPEAT;
315
316 52 fpi_ssm_next_state (ssm);
317 }
318 break;
319
320 52 case SM_REC_DATA:
321 52 recv_data_resp (ssm, dev);
322 52 break;
323
324 52 case SM_DONE:
325 52 fpi_ssm_jump_to_state (ssm, SM_START);
326 52 break;
327
328 default:
329 g_assert_not_reached ();
330 }
331 612 }
332
333 /*
334 * Activation
335 */
336
337 static void
338 1 loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
339 {
340 1 FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
341 1 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
342
343 1 self->running = FALSE;
344
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&self->background, g_free);
345
346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
347 fpi_image_device_session_error (img_dev, error);
348 1 }
349
350 static void
351 1 dev_activate (FpImageDevice *dev)
352 {
353 1 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
354 1 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
355
356 1 self->stop = FALSE;
357
358 1 fpi_ssm_start (ssm, loop_complete);
359
360 1 self->running = TRUE;
361
362 1 fpi_image_device_activate_complete (dev, NULL);
363 1 }
364
365 /*
366 * Opening
367 */
368
369 static void
370 1 dev_init (FpImageDevice *dev)
371 {
372 1 GError *error = NULL;
373
374 1 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
375
376 1 fpi_image_device_open_complete (dev, error);
377 1 }
378
379 /*
380 * Closing
381 */
382
383 static void
384 1 dev_deinit (FpImageDevice *dev)
385 {
386 1 GError *error = NULL;
387
388 1 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
389
390 1 fpi_image_device_close_complete (dev, error);
391 1 }
392
393 /*
394 * Deactivation
395 */
396
397 static void
398 1 dev_deactivate (FpImageDevice *dev)
399 {
400 1 FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
401
402
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->running)
403 1 self->stop = TRUE;
404 else
405 fpi_image_device_deactivate_complete (dev, NULL);
406 1 }
407
408 /*
409 * Driver data
410 */
411
412 static const FpIdEntry id_table[] = {
413 { .vid = 0x1c7a, .pid = 0x0570, },
414 { .vid = 0x1c7a, .pid = 0x0571, },
415 { .vid = 0, .pid = 0, },
416 };
417
418 static void
419 1 fpi_device_egis0570_init (FpDeviceEgis0570 *self)
420 {
421 1 }
422
423 static void
424 117 fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
425 {
426 117 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
427 117 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
428
429 117 dev_class->id = "egis0570";
430 117 dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
431 117 dev_class->type = FP_DEVICE_TYPE_USB;
432 117 dev_class->id_table = id_table;
433 117 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
434
435 117 img_class->img_open = dev_init;
436 117 img_class->img_close = dev_deinit;
437 117 img_class->activate = dev_activate;
438 117 img_class->deactivate = dev_deactivate;
439
440 117 img_class->img_width = EGIS0570_IMGWIDTH;
441 117 img_class->img_height = -1;
442
443 117 img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
444 }
445