• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*.............................................................................
2  * Project : SANE library for Plustek flatbed scanners.
3  *.............................................................................
4  */
5 
6 /** @file plustek-usbcalfile.c
7  *  @brief Functions for saving/restoring calibration settings
8  *
9  * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de>
10  *
11  * History:
12  * - 0.46 - first version
13  * - 0.47 - no changes
14  * - 0.48 - no changes
15  * - 0.49 - a_bRegs is now part of the device structure
16  * - 0.50 - cleanup
17  * - 0.51 - added functions for saving, reading and restoring
18  *          fine calibration data
19  * - 0.52 - no changes
20  * .
21  * <hr>
22  * This file is part of the SANE package.
23  *
24  * This program is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU General Public License as
26  * published by the Free Software Foundation; either version 2 of the
27  * License, or (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful, but
30  * WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
32  * General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
36  *
37  * As a special exception, the authors of SANE give permission for
38  * additional uses of the libraries contained in this release of SANE.
39  *
40  * The exception is that, if you link a SANE library with other files
41  * to produce an executable, this does not by itself cause the
42  * resulting executable to be covered by the GNU General Public
43  * License.  Your use of that executable is in no way restricted on
44  * account of linking the SANE library code into it.
45  *
46  * This exception does not, however, invalidate any other reasons why
47  * the executable file might be covered by the GNU General Public
48  * License.
49  *
50  * If you submit changes to SANE to the maintainers to be included in
51  * a subsequent release, you agree by submitting the changes that
52  * those changes may be distributed with this exception intact.
53  *
54  * If you write modifications of your own for SANE, it is your choice
55  * whether to permit this exception to apply to your modifications.
56  * If you do not wish that, delete this exception notice.
57  * <hr>
58  */
59 
60 typedef struct {
61 	u_long red_light_on;
62 	u_long red_light_off;
63 	u_long green_light_on;
64 	u_long green_light_off;
65 	u_long blue_light_on;
66 	u_long blue_light_off;
67 	u_long green_pwm_duty;
68 
69 } LightCtrl;
70 
71 typedef struct {
72 	u_short   version;
73 
74 	u_short   red_gain;
75 	u_short   green_gain;
76 	u_short   blue_gain;
77 
78 	u_short   red_offs;
79 	u_short   green_offs;
80 	u_short   blue_offs;
81 
82 	LightCtrl light;
83 
84 } CalData;
85 
86 /* our shading buffers */
87 static u_short a_wWhiteShading[_SHADING_BUF] = {0};
88 static u_short a_wDarkShading[_SHADING_BUF]  = {0};
89 
90 /* the version the calibration files */
91 #define _PT_CF_VERSION 0x0002
92 
93 /** function to read a text file and returns the string which starts which
94  *  'id' string.
95  *  no duplicate entries where detected, always the first occurrence will be
96  *  red.
97  * @param fp  - file pointer of file to read
98  * @param id  - what to search for
99  * @param res - where to store the result upon success
100  * @return SANE_TRUE on success, SANE_FALSE on any error
101  */
102 static SANE_Bool
usb_ReadSpecLine(FILE * fp,char * id,char * res)103 usb_ReadSpecLine( FILE *fp, char *id, char* res )
104 {
105 	char  tmp[1024];
106 	char *ptr;
107 
108 	/* rewind file pointer */
109 	if( 0 != fseek( fp, 0L, SEEK_SET)) {
110 		DBG( _DBG_ERROR, "fseek: %s\n", strerror(errno));
111 		return SANE_FALSE;
112 	}
113 
114 	/* roam through the file and examine each line... */
115 	while( !feof( fp )) {
116 
117 		memset( tmp, 0, sizeof(tmp));
118 		if( NULL != fgets( tmp, 1024, fp )) {
119 
120 			if( 0 == strncmp( tmp, id, strlen(id))) {
121 
122 				ptr = &tmp[strlen(id)];
123         			if( '\0' == *ptr )
124 					break;
125 
126 				strcpy( res, ptr );
127 				res[strlen(res)-1] = '\0';
128 				return SANE_TRUE;
129 			}
130 		}
131 	}
132 	return SANE_FALSE;
133 }
134 
135 /** function to read data from a file and excluding certain stuff like
136  *  the version lines
137  * @param fp      - file pointer of file to read
138  * @param except  - what to exclude
139  * @return Pointer to the allocated memory for the data, NULL on any error.
140  */
141 static char*
usb_ReadOtherLines(FILE * fp,char * except)142 usb_ReadOtherLines( FILE *fp, char *except )
143 {
144 	char  tmp[1024];
145 	char *ptr, *ptr_base;
146 	int   ignore;
147 	int   len;
148 
149 	if( 0 != fseek( fp, 0L, SEEK_END))
150 		return NULL;
151 
152 	len = ftell(fp);
153 
154 	/* rewind file pointer */
155 	if( 0 != fseek( fp, 0L, SEEK_SET))
156 		return NULL;
157 
158 	if( len == 0 )
159 		return NULL;
160 
161 	ptr = (char*)malloc(len);
162 	if( NULL == ptr )
163 		return NULL;
164 
165 	ptr_base = ptr;
166 	*ptr     = '\0';
167 	ignore   = 0;
168 
169 	/* roam through the file and examine each line... */
170 	while( !feof( fp )) {
171 
172 		if( NULL != fgets( tmp, 1024, fp )) {
173 
174 			/* we ignore the version line... */
175 			if( 0 == strncmp( tmp, "version=", 8 ))
176 				continue;
177 
178 			if( !ignore ) {
179 				if(0 != strncmp(tmp, except, strlen(except))) {
180 
181 					if( strlen( tmp ) > 0 ) {
182 						strcpy( ptr, tmp );
183 						ptr += strlen(tmp);
184 						*ptr = '\0';
185 					}
186 				} else {
187 					ignore = 1;
188 				}
189 			}
190 
191 			/* newline in tmp string resets ignore flag */
192 			if( strrchr(tmp, '\n')) {
193 				ignore = 0;
194 			}
195 		}
196 	}
197 	return ptr_base;
198 }
199 
200 /**
201  */
202 static SANE_Bool
usb_ReadSamples(FILE * fp,char * which,u_long * dim,u_short * buffer)203 usb_ReadSamples( FILE *fp, char *which, u_long *dim, u_short *buffer )
204 {
205 	char  *p, *next, *rb;
206 	char   tmp[1024+30];
207 	int    ignore, diml, c;
208 	u_long val;
209 
210 	/* rewind file pointer */
211 	if( 0 != fseek( fp, 0L, SEEK_SET))
212 		return SANE_FALSE;
213 
214 	ignore = 0;
215 	diml   = 0;
216 	c      = 0;
217 	rb     = tmp;
218 	*dim   = 0;
219 
220 	/* roam through the file and examine each line... */
221 	while( !feof( fp )) {
222 
223 		if( NULL != fgets( rb, 1024, fp )) {
224 
225 			/* we ignore the version line... */
226 			if( 0 == strncmp( tmp, "version=", 8 ))
227 				continue;
228 
229 			p = tmp;
230 			if( !ignore && diml == 0) {
231 				if(0 == strncmp(tmp, which, strlen(which))) {
232 
233 					/* get dimension */
234 					diml = strtol(&tmp[strlen(which)], NULL, 10);
235 					p = strchr( &tmp[strlen(which)], ':' );
236 					p++;
237 				} else {
238 					ignore = 1;
239 				}
240 			}
241 
242 			/* parse the values... */
243 			if( !ignore ) {
244 
245 				rb = tmp;
246 				while( *p ) {
247 					val = strtoul( p, &next, 10 );
248 
249 					/* check for error condition */
250 					if( val == 0 ) {
251 						if( p == next ) {
252 							if( c+1 == diml ) {
253 								*dim = diml;
254 								return SANE_TRUE;
255 							}
256 							break;
257 						}
258 					}
259 
260 					buffer[c] = (u_short)val;
261 
262 					/* more values? */
263 					if( *next == ',') {
264 						p = next+1;
265 						c++;
266 					} else {
267 						p = next;
268 					}
269 					/* reached the end? */
270 					if( *next == '\0' ) {
271 
272 						/* we probably have only parsed a part of a value
273 						 * so we copy that back to the input buffer and
274 						 * parse it the next time...
275 						 */
276 						if( c < diml ) {
277 							sprintf( tmp, "%u", buffer[c] );
278 							rb = &tmp[strlen(tmp)];
279 						}
280 					}
281 				}
282 			}
283 
284 			/* newline in tmp string resets ignore flag */
285 			if( strrchr(tmp, '\n')) {
286 				ignore = 0;
287 			}
288 		}
289 	}
290 	return SANE_FALSE;
291 }
292 
293 /**
294  */
295 static void
usb_RestoreCalData(Plustek_Device * dev,CalData * cal)296 usb_RestoreCalData( Plustek_Device *dev, CalData *cal )
297 {
298 	HWDef  *hw   = &dev->usbDev.HwSetting;
299 	u_char *regs = dev->usbDev.a_bRegs;
300 
301 	regs[0x3b] = (u_char)cal->red_gain;
302 	regs[0x3c] = (u_char)cal->green_gain;
303 	regs[0x3d] = (u_char)cal->blue_gain;
304 	regs[0x38] = (u_char)cal->red_offs;
305 	regs[0x39] = (u_char)cal->green_offs;
306 	regs[0x3a] = (u_char)cal->blue_offs;
307 
308 	regs[0x2a] = _HIBYTE((u_short)cal->light.green_pwm_duty);
309 	regs[0x2b] = _LOBYTE((u_short)cal->light.green_pwm_duty);
310 
311 	regs[0x2c] = _HIBYTE((u_short)cal->light.red_light_on);
312 	regs[0x2d] = _LOBYTE((u_short)cal->light.red_light_on);
313 	regs[0x2e] = _HIBYTE((u_short)cal->light.red_light_off);
314 	regs[0x2f] = _LOBYTE((u_short)cal->light.red_light_off);
315 
316 	regs[0x30] = _HIBYTE((u_short)cal->light.green_light_on);
317 	regs[0x31] = _LOBYTE((u_short)cal->light.green_light_on);
318 	regs[0x32] = _HIBYTE((u_short)cal->light.green_light_off);
319 	regs[0x33] = _LOBYTE((u_short)cal->light.green_light_off);
320 
321 	regs[0x34] = _HIBYTE((u_short)cal->light.blue_light_on);
322 	regs[0x35] = _LOBYTE((u_short)cal->light.blue_light_on);
323 	regs[0x36] = _HIBYTE((u_short)cal->light.blue_light_off);
324 	regs[0x37] = _LOBYTE((u_short)cal->light.blue_light_off);
325 
326 	hw->red_lamp_on    = (u_short)cal->light.red_light_on;
327 	hw->red_lamp_off   = (u_short)cal->light.red_light_off;
328 	hw->green_lamp_on  = (u_short)cal->light.green_light_on;
329 	hw->green_lamp_off = (u_short)cal->light.green_light_off;
330 	hw->blue_lamp_on   = (u_short)cal->light.blue_light_on;
331 	hw->blue_lamp_off  = (u_short)cal->light.blue_light_off;
332 }
333 
334 /**
335  */
336 static void
usb_CreatePrefix(Plustek_Device * dev,char * pfx,SANE_Bool add_bitdepth)337 usb_CreatePrefix( Plustek_Device *dev, char *pfx, SANE_Bool add_bitdepth )
338 {
339 	char       bd[5];
340 	ScanDef   *scanning = &dev->scanning;
341 	ScanParam *param    = &scanning->sParam;
342 
343 	switch( scanning->sParam.bSource ) {
344 
345 		case SOURCE_Transparency: strcpy( pfx, "tpa-" ); break;
346 		case SOURCE_Negative:     strcpy( pfx, "neg-" ); break;
347 		case SOURCE_ADF:          strcpy( pfx, "adf-" ); break;
348 	    default:                  pfx[0] = '\0'; break;
349 	}
350 
351 	sprintf( bd, "%u=", param->bBitDepth );
352 	if( param->bDataType == SCANDATATYPE_Color )
353 		strcat( pfx, "color" );
354 	else
355 		strcat( pfx, "gray" );
356 
357 	if( add_bitdepth )
358 		strcat( pfx, bd );
359 }
360 
361 /** function to read and set the calibration data from external file
362  */
363 static SANE_Bool
usb_ReadAndSetCalData(Plustek_Device * dev)364 usb_ReadAndSetCalData( Plustek_Device *dev )
365 {
366 	char       pfx[20];
367 	char       tmp[1024];
368 	u_short    version;
369 	int        res;
370 	FILE      *fp;
371 	CalData    cal;
372 	SANE_Bool  ret;
373 
374 	DBG( _DBG_INFO, "usb_ReadAndSetCalData()\n" );
375 
376 	if( usb_InCalibrationMode(dev)) {
377 		DBG( _DBG_INFO, "- we are in calibration mode!\n" );
378 		return SANE_FALSE;
379 	}
380 
381 	if( NULL == dev->calFile ) {
382 		DBG( _DBG_ERROR, "- No calibration filename set!\n" );
383 		return SANE_FALSE;
384 	}
385 
386 	sprintf( tmp, "%s-coarse.cal", dev->calFile );
387 	DBG( _DBG_INFO, "- Reading coarse calibration data from file\n");
388 	DBG( _DBG_INFO, "  %s\n", tmp );
389 
390 	fp = fopen( tmp, "r" );
391 	if( NULL == fp ) {
392 		DBG( _DBG_ERROR, "File %s not found\n", tmp );
393 		return SANE_FALSE;
394 	}
395 
396 	/* check version */
397 	if( !usb_ReadSpecLine( fp, "version=", tmp )) {
398 		DBG( _DBG_ERROR, "Could not find version info!\n" );
399 		fclose( fp );
400 		return SANE_FALSE;
401 	}
402 
403 	DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp );
404 	if( 1 != sscanf( tmp, "0x%04hx", &version )) {
405 		DBG( _DBG_ERROR, "Could not decode version info!\n" );
406 		fclose( fp );
407 		return SANE_FALSE;
408 	}
409 
410 	if( version != _PT_CF_VERSION ) {
411 		DBG( _DBG_ERROR, "Versions do not match!\n" );
412 		fclose( fp );
413 		return SANE_FALSE;
414 	}
415 
416 	usb_CreatePrefix( dev, pfx, SANE_TRUE );
417 
418 	ret = SANE_FALSE;
419 	if( usb_ReadSpecLine( fp, pfx, tmp )) {
420 		DBG( _DBG_INFO, "- Calibration data: %s\n", tmp );
421 
422 		res = sscanf( tmp, "%hu,%hu,%hu,%hu,%hu,%hu,"
423 						   "%lu,%lu,%lu,%lu,%lu,%lu,%lu\n",
424 						&cal.red_gain,   &cal.red_offs,
425 						&cal.green_gain, &cal.green_offs,
426 						&cal.blue_gain,  &cal.blue_offs,
427 						&cal.light.red_light_on,   &cal.light.red_light_off,
428 						&cal.light.green_light_on, &cal.light.green_light_off,
429 						&cal.light.blue_light_on,  &cal.light.blue_light_off,
430 						&cal.light.green_pwm_duty );
431 
432 		if( 13 == res ) {
433 			usb_RestoreCalData( dev, &cal );
434 			ret = SANE_TRUE;
435 		} else {
436 			DBG( _DBG_ERROR, "Error reading coarse-calibration data, only "
437 			                 "%d elements available!\n", res );
438 		}
439 	} else {
440 		DBG( _DBG_ERROR, "Error reading coarse-calibration data for "
441 		                 "PFX: >%s<!\n", pfx );
442 	}
443 
444 	fclose( fp );
445 	DBG( _DBG_INFO, "usb_ReadAndSetCalData() done -> %u\n", ret );
446 
447 	return ret;
448 }
449 
450 /**
451  */
452 static void
usb_PrepCalData(Plustek_Device * dev,CalData * cal)453 usb_PrepCalData( Plustek_Device *dev, CalData *cal )
454 {
455 	u_char *regs = dev->usbDev.a_bRegs;
456 
457 	memset( cal, 0, sizeof(CalData));
458 	cal->version = _PT_CF_VERSION;
459 
460 	cal->red_gain   = (u_short)regs[0x3b];
461 	cal->green_gain = (u_short)regs[0x3c];
462 	cal->blue_gain  = (u_short)regs[0x3d];
463 	cal->red_offs   = (u_short)regs[0x38];
464 	cal->green_offs = (u_short)regs[0x39];
465 	cal->blue_offs  = (u_short)regs[0x3a];
466 
467 	cal->light.green_pwm_duty  = regs[0x2a] * 256 + regs[0x2b];
468 
469 	cal->light.red_light_on    = regs[0x2c] * 256 + regs[0x2d];
470 	cal->light.red_light_off   = regs[0x2e] * 256 + regs[0x2f];
471 	cal->light.green_light_on  = regs[0x30] * 256 + regs[0x31];
472 	cal->light.green_light_off = regs[0x32] * 256 + regs[0x33];
473 	cal->light.blue_light_on   = regs[0x34] * 256 + regs[0x35];
474 	cal->light.blue_light_off  = regs[0x36] * 256 + regs[0x37];
475 }
476 
477 /** function to save/update the calibration data
478  */
479 static void
usb_SaveCalData(Plustek_Device * dev)480 usb_SaveCalData( Plustek_Device *dev )
481 {
482 	char       pfx[20];
483 	char       fn[1024];
484 	char       tmp[1024];
485 	char       set_tmp[1024];
486 	char      *other_tmp;
487 	u_short    version;
488 	FILE      *fp;
489 	CalData    cal;
490 	ScanDef   *scanning = &dev->scanning;
491 
492 	DBG( _DBG_INFO, "usb_SaveCalData()\n" );
493 
494 	/* no new data, so skip this step too */
495 	if( SANE_TRUE == scanning->skipCoarseCalib ) {
496 		DBG( _DBG_INFO, "- No calibration data to save!\n" );
497 		return;
498 	}
499 
500 	if( NULL == dev->calFile ) {
501 		DBG( _DBG_ERROR, "- No calibration filename set!\n" );
502 		return;
503 	}
504 
505 	sprintf( fn, "%s-coarse.cal", dev->calFile );
506 	DBG( _DBG_INFO, "- Saving coarse calibration data to file\n" );
507 	DBG( _DBG_INFO, "  %s\n", fn );
508 
509 	usb_PrepCalData ( dev, &cal );
510 	usb_CreatePrefix( dev, pfx, SANE_TRUE );
511 	DBG( _DBG_INFO2, "- PFX: >%s<\n", pfx );
512 
513 	sprintf( set_tmp, "%s%u,%u,%u,%u,%u,%u,"
514 	                  "%lu,%lu,%lu,%lu,%lu,%lu,%lu\n", pfx,
515 	                  cal.red_gain,   cal.red_offs,
516 	                  cal.green_gain, cal.green_offs,
517 	                  cal.blue_gain,  cal.blue_offs,
518 	                  cal.light.red_light_on,   cal.light.red_light_off,
519 	                  cal.light.green_light_on, cal.light.green_light_off,
520 	                  cal.light.blue_light_on,  cal.light.blue_light_off,
521 	                  cal.light.green_pwm_duty );
522 
523 	/* read complete old file if compatible... */
524 	other_tmp = NULL;
525 	fp = fopen( fn, "r+" );
526 	if( NULL != fp ) {
527 
528 		if( usb_ReadSpecLine( fp, "version=", tmp )) {
529 			DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp );
530 
531 			if( 1 == sscanf( tmp, "0x%04hx", &version )) {
532 
533 				if( version == cal.version ) {
534 
535 					DBG( _DBG_INFO, "- Versions do match\n" );
536 
537 					/* read the rest... */
538 					other_tmp = usb_ReadOtherLines( fp, pfx );
539 				} else {
540 					DBG( _DBG_INFO2, "- Versions do not match (0x%04x)\n", version );
541 				}
542 			} else {
543 				DBG( _DBG_INFO2, "- cannot decode version\n" );
544 			}
545 		} else {
546 			DBG( _DBG_INFO2, "- Version not found\n" );
547 		}
548 		fclose( fp );
549 	}
550 	fp = fopen( fn, "w+" );
551 	if( NULL == fp ) {
552 		DBG( _DBG_ERROR, "- Cannot create file %s\n", fn );
553 		DBG( _DBG_ERROR, "- -> %s\n", strerror(errno));
554 		if( other_tmp )
555 			free( other_tmp );
556 		return;
557 	}
558 
559 	/* rewrite the file again... */
560 	fprintf( fp, "version=0x%04X\n", cal.version );
561 	if( strlen( set_tmp ))
562 		fprintf( fp, "%s", set_tmp );
563 
564 	if( other_tmp ) {
565 		fprintf( fp, "%s", other_tmp );
566 		free( other_tmp );
567 	}
568 	fclose( fp );
569 	DBG( _DBG_INFO, "usb_SaveCalData() done.\n" );
570 }
571 
572 /**
573  */
574 static void
usb_SaveFineCalData(Plustek_Device * dev,int dpi,u_short * dark,u_short * white,u_long vals)575 usb_SaveFineCalData( Plustek_Device *dev, int dpi,
576                      u_short *dark, u_short *white, u_long vals )
577 {
578 	char     pfx[30];
579 	char     fn[1024];
580 	char     tmp[1024];
581 	char    *other_tmp;
582 	u_short  version;
583 	u_long   i;
584 	FILE    *fp;
585 
586 	if( NULL == dev->calFile ) {
587 		DBG( _DBG_ERROR, "- No calibration filename set!\n" );
588 		return;
589 	}
590 
591 	sprintf( fn, "%s-fine.cal", dev->calFile );
592 	DBG( _DBG_INFO, "- Saving fine calibration data to file\n" );
593 	DBG( _DBG_INFO, "  %s\n", fn );
594 
595 	usb_CreatePrefix( dev, pfx, SANE_FALSE );
596 	sprintf( tmp, "%s:%u", pfx, dpi );
597 	strcpy( pfx, tmp );
598 	DBG( _DBG_INFO2, "- PFX: >%s<\n", pfx );
599 
600 	/* read complete old file if compatible... */
601 	other_tmp = NULL;
602 	fp = fopen( fn, "r+" );
603 	if( NULL != fp ) {
604 
605 		if( usb_ReadSpecLine( fp, "version=", tmp )) {
606 			DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp );
607 
608 			if( 1 == sscanf( tmp, "0x%04hx", &version )) {
609 
610 				if( version == _PT_CF_VERSION ) {
611 					DBG( _DBG_INFO, "- Versions do match\n" );
612 
613 					/* read the rest... */
614 					other_tmp = usb_ReadOtherLines( fp, pfx );
615 				} else {
616 					DBG( _DBG_INFO2, "- Versions do not match (0x%04x)\n", version );
617 				}
618 			} else {
619 				DBG( _DBG_INFO2, "- cannot decode version\n" );
620 			}
621 		} else {
622 			DBG( _DBG_INFO2, "- Version not found\n" );
623 		}
624 		fclose( fp );
625 	}
626 
627 	fp = fopen( fn, "w+" );
628 	if( NULL == fp ) {
629 		DBG( _DBG_ERROR, "- Cannot create file %s\n", fn );
630 		return;
631 	}
632 
633 	/* rewrite the file again... */
634 	fprintf( fp, "version=0x%04X\n", _PT_CF_VERSION );
635 
636 	if( other_tmp ) {
637 		fprintf( fp, "%s", other_tmp );
638 		free( other_tmp );
639 	}
640 
641 	fprintf( fp, "%s:dark:dim=%lu:", pfx, vals );
642 	for( i=0; i<vals-1; i++ )
643 		fprintf( fp, "%u,", dark[i]);
644 	fprintf( fp, "%u\n", dark[vals-1]);
645 
646 	fprintf( fp, "%s:white:dim=%lu:", pfx, vals );
647 	for( i=0; i<vals-1; i++ )
648 		fprintf( fp, "%u,", white[i]);
649 	fprintf( fp, "%u\n", white[vals-1]);
650 
651 	fclose( fp );
652 }
653 
654 /** function to read and set the calibration data from external file
655  */
656 static SANE_Bool
usb_ReadFineCalData(Plustek_Device * dev,int dpi,u_long * dim_d,u_short * dark,u_long * dim_w,u_short * white)657 usb_ReadFineCalData( Plustek_Device *dev, int dpi,
658                      u_long *dim_d, u_short *dark,
659                      u_long *dim_w, u_short *white )
660 {
661 	char       pfx[30];
662 	char       tmp[1024];
663 	u_short    version;
664 	FILE      *fp;
665 
666 	DBG( _DBG_INFO, "usb_ReadFineCalData()\n" );
667 	if( usb_InCalibrationMode(dev)) {
668 		DBG( _DBG_INFO, "- we are in calibration mode!\n" );
669 		return SANE_FALSE;
670 	}
671 
672 	if( NULL == dev->calFile ) {
673 		DBG( _DBG_ERROR, "- No calibration filename set!\n" );
674 		return SANE_FALSE;
675 	}
676 
677 	sprintf( tmp, "%s-fine.cal", dev->calFile );
678 	DBG( _DBG_INFO, "- Reading fine calibration data from file\n");
679 	DBG( _DBG_INFO, "  %s\n", tmp );
680 
681 	*dim_d = *dim_w = 0;
682 
683 	fp = fopen( tmp, "r" );
684 	if( NULL == fp ) {
685 		DBG( _DBG_ERROR, "File %s not found\n", tmp );
686 		return SANE_FALSE;
687 	}
688 
689 	/* check version */
690 	if( !usb_ReadSpecLine( fp, "version=", tmp )) {
691 		DBG( _DBG_ERROR, "Could not find version info!\n" );
692 		fclose( fp );
693 		return SANE_FALSE;
694 	}
695 
696 	DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp );
697 	if( 1 != sscanf( tmp, "0x%04hx", &version )) {
698 		DBG( _DBG_ERROR, "Could not decode version info!\n" );
699 		fclose( fp );
700 		return SANE_FALSE;
701 	}
702 
703 	if( version != _PT_CF_VERSION ) {
704 		DBG( _DBG_ERROR, "Versions do not match!\n" );
705 		fclose( fp );
706 		return SANE_FALSE;
707 	}
708 
709 	usb_CreatePrefix( dev, pfx, SANE_FALSE );
710 
711 	sprintf( tmp, "%s:%u:%s:dim=", pfx, dpi, "dark" );
712 	if( !usb_ReadSamples( fp, tmp, dim_d, dark )) {
713 		DBG( _DBG_ERROR, "Error reading dark-calibration data!\n" );
714 		fclose( fp );
715 		return SANE_FALSE;
716 	}
717 
718 	sprintf( tmp, "%s:%u:%s:dim=", pfx, dpi, "white" );
719 	if( !usb_ReadSamples( fp, tmp, dim_w, white )) {
720 		DBG( _DBG_ERROR, "Error reading white-calibration data!\n" );
721 		fclose( fp );
722 		return SANE_FALSE;
723 	}
724 
725 	fclose( fp );
726 	return SANE_TRUE;
727 }
728 
729 /**
730  */
731 static void
usb_get_shading_part(u_short * buf,u_long offs,u_long src_len,int dst_len)732 usb_get_shading_part(u_short *buf, u_long offs, u_long src_len, int dst_len)
733 {
734 	u_short *p_src, *p_dst;
735 	int      i, j;
736 
737 	if (src_len == 0 || dst_len == 0)
738 		return;
739 
740 	p_dst = buf;
741 	for (i=0; i<3; i++) {
742 
743 		p_src = buf + src_len * i + offs;
744 
745 		for (j=0; j<dst_len; j++) {
746 
747 			*(p_dst++) = *(p_src++);
748 		}
749 	}
750 }
751 
752 /** function to read the fine calibration results from file
753  * and to set the correct part of the calibration buffers for
754  * storing in the device
755  * @param dev - the almigthy device structure
756  * @returns SANE_FALSE when the reading fails or SANE_TRUE on success
757  */
758 static SANE_Bool
usb_FineShadingFromFile(Plustek_Device * dev)759 usb_FineShadingFromFile( Plustek_Device *dev )
760 {
761 	ScanDef   *scan = &dev->scanning;
762 	ScanParam *sp   = &scan->sParam;
763 	u_short    xdpi;
764 	u_long     dim_w, dim_d, offs;
765 
766 	xdpi = usb_SetAsicDpiX( dev, sp->UserDpi.x );
767 
768 	if( !usb_ReadFineCalData( dev, xdpi, &dim_d, a_wDarkShading,
769 	                                     &dim_w, a_wWhiteShading)) {
770 		return SANE_FALSE;
771 	}
772 
773 	/* now we need to get the correct part of the line... */
774 	dim_d /= 3;
775 	dim_w /= 3;
776 
777 	offs = ((u_long)sp->Origin.x * xdpi) / 300;
778 
779 	usb_GetPhyPixels( dev, sp );
780 
781 	DBG( _DBG_INFO2, "FINE Calibration from file:\n" );
782 	DBG( _DBG_INFO2, "XDPI      = %u\n",  xdpi   );
783 	DBG( _DBG_INFO2, "Dim       = %lu\n", dim_d  );
784 	DBG( _DBG_INFO2, "Pixels    = %lu\n", sp->Size.dwPixels );
785 	DBG( _DBG_INFO2, "PhyPixels = %lu\n", sp->Size.dwPhyPixels );
786 	DBG( _DBG_INFO2, "Origin.X  = %u\n",  sp->Origin.x );
787 	DBG( _DBG_INFO2, "Offset    = %lu\n", offs );
788 
789 	usb_get_shading_part(a_wDarkShading,  offs, dim_d, sp->Size.dwPhyPixels);
790 	usb_get_shading_part(a_wWhiteShading, offs, dim_w, sp->Size.dwPhyPixels);
791 
792 	return SANE_TRUE;
793 }
794 
795 /** function to save the fine calibration results and to set the correct part
796  * of the calibration buffers for storing in the device
797  * @param dev    - the almigthy device structure
798  * @param tmp_sp - intermediate scan parameter
799  */
800 static void
usb_SaveCalSetShading(Plustek_Device * dev,ScanParam * tmp_sp)801 usb_SaveCalSetShading( Plustek_Device *dev, ScanParam *tmp_sp )
802 {
803 	ScanParam *sp = &dev->scanning.sParam;
804 	u_short    xdpi;
805 	u_long     offs;
806 
807 	if( !dev->adj.cacheCalData )
808 		return;
809 
810 	/* save the values */
811 	xdpi = usb_SetAsicDpiX( dev, tmp_sp->UserDpi.x );
812 
813 	usb_SaveFineCalData( dev, xdpi, a_wDarkShading,
814 	                     a_wWhiteShading, tmp_sp->Size.dwPixels*3 );
815 
816 	/* now we need to get the correct part of the line... */
817 	xdpi = usb_SetAsicDpiX( dev, sp->UserDpi.x );
818 	offs = ((u_long)sp->Origin.x * xdpi) / 300;
819 	usb_GetPhyPixels( dev, sp );
820 
821 	DBG( _DBG_INFO2, "FINE Calibration area after saving:\n" );
822 	DBG( _DBG_INFO2, "XDPI      = %u\n",  xdpi );
823 	DBG( _DBG_INFO2, "Dim       = %lu\n", tmp_sp->Size.dwPixels );
824 	DBG( _DBG_INFO2, "Pixels    = %lu\n", sp->Size.dwPixels );
825 	DBG( _DBG_INFO2, "PhyPixels = %lu\n", sp->Size.dwPhyPixels );
826 	DBG( _DBG_INFO2, "Origin.X  = %u\n",  sp->Origin.x );
827 	DBG( _DBG_INFO2, "Offset    = %lu\n", offs );
828 
829 	if (!usb_InCalibrationMode(dev)) {
830 
831 		usb_get_shading_part( a_wDarkShading, offs,
832 		                      tmp_sp->Size.dwPixels, sp->Size.dwPhyPixels );
833 		usb_get_shading_part( a_wWhiteShading, offs,
834 	    	                  tmp_sp->Size.dwPixels, sp->Size.dwPhyPixels );
835 
836 		memcpy( tmp_sp, sp, sizeof(ScanParam));
837 		tmp_sp->bBitDepth = 16;
838 
839 		usb_GetPhyPixels( dev, tmp_sp );
840 	}
841 }
842 
843 /* END PLUSTEK-USBCALFILE.C .................................................*/
844