1 
2  /* Illuminant measurement utility */
3 
4 /*
5  * Argyll Color Correction System
6  * Author: Graeme W. Gill
7  * Date:   3/10/2001
8  *
9  * Derived from printread.c/chartread.c
10  * Was called printspot.
11  *
12  * Copyright 2001 - 2013 Graeme W. Gill
13  * All rights reserved.
14  *
15  * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
16  * see the License.txt file for licencing details.
17  */
18 
19 /* This program uses an instrument capable of spectral illuminant/emissive */
20 /* and reflective (non-UV filtered) measurement, to measure an illuminant */
21 /* spectrum that includes a UV estimate. */
22 
23 /* Based on spotread.c */
24 
25 /*
26 	TTBD:
27 
28 	Should add support for converting Spyder correction readings to ccmx.
29 	(see SpyderDeviceCorrections.txt)
30 
31  */
32 
33 /*
34 	Test mode files restored/saved:
35 
36 	outname_i.sp	Illuminant spectrum
37 	outname_r.sp	Illuminant off paper spectrum
38 	outname_p.sp	Instrument measured paper reflectance spectrum
39 
40 	Just saved:
41 
42 	outname_mpir.sp	Measured paper under illuminant spectrum
43 	outname_cpir.sp	Computed paper under illuminant spectrum
44  */
45 
46 #undef DEBUG			/* Debug messages */
47 #undef PLOT_FITTING	/* Plot the fitting itterations */
48 #undef SHOWDXX			/* Plot the best matched daylight as well */
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <math.h>
53 #include <sys/types.h>
54 #include <time.h>
55 #include <string.h>
56 #include "copyright.h"
57 #include "aconfig.h"
58 #include "numlib.h"
59 #include "cgats.h"
60 #include "xicc.h"
61 #include "conv.h"
62 #include "inst.h"
63 #include "icoms.h"
64 #include "instappsup.h"
65 #include "plot.h"
66 #include "ui.h"
67 #ifdef ENABLE_USB
68 # include "spyd2.h"
69 #endif
70 
71 #include <stdarg.h>
72 
73 #if defined (NT)
74 #include <conio.h>
75 #endif
76 
77 /* Deal with an instrument error. */
78 /* Return 0 to retry, 1 to abort */
ierror(inst * it,inst_code ic)79 static int ierror(inst *it, inst_code ic) {
80 	int ch;
81 	empty_con_chars();
82 	printf("Got '%s' (%s) error.\nHit Esc or Q to give up, any other key to retry:",
83 	       it->inst_interp_error(it, ic), it->interp_error(it, ic));
84 	fflush(stdout);
85 	ch = next_con_char();
86 	printf("\n");
87 	if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q')	/* Escape, ^C or Q */
88 		return 1;
89 	return 0;
90 }
91 
92 #if defined(__APPLE__) && defined(__POWERPC__)
93 
94 /* Workaround for a ppc gcc 3.3 optimiser bug... */
gcc_bug_fix(int i)95 static int gcc_bug_fix(int i) {
96 	static int nn;
97 	nn += i;
98 	return nn;
99 }
100 
101 #define GCC_BUGFIX(XX) gcc_bug_fix(XX);
102 #else	/* !APPLE */
103 #define GCC_BUGFIX(XX)
104 #endif	/* !APPLE */
105 
106 
107 /* ============================================================== */
108 /* optimizer callback */
109 
110 /* Structure to hold optimisation information */
111 typedef struct {
112 	xspect *i_sp;		/* Illuminiant measurement */
113 	xspect *r_sp;		/* Illuminant off paper measurement */
114 	xspect *p_sp;		/* Paper reflectance measurement */
115 
116 	xsp2cie *pap;		/* Estimated illuminant + UV on paper lookup inc FWA */
117 	xsp2cie *ref;		/* Measured illuminant on paper lookup */
118 
119 	xspect ill;			/* Illuminant with UV added - set by bfindfunc() */
120 	xspect cpsp;		/* FWA corrected calculated paper reflectance */
121 	xspect srop;		/* Scaled measured paper reflectance */
122 
123 	double lab0[3], lab1[3];	/* Conversion of calculated vs. measured */
124 } bfinds;
125 
126 /* Optimize the UV content that minimizes the (weighted) Delta E */
bfindfunc(void * adata,double pv[])127 static double bfindfunc(void *adata, double pv[]) {
128 	bfinds *b = (bfinds *)adata;
129 	int i;
130 	double rv = 0.0;
131 
132 	/* Add UV level to illuminant */
133 	b->ill = *b->i_sp;							/* Structure copy */
134 	xsp_setUV(&b->ill, b->i_sp, pv[0]);		/* Extends ill range into UV */
135 
136 #ifdef NEVER	/* Plot the two reflectance spectra */
137 	printf("Black = Measured illum, Red = illum + %f UV\n",pv[0]);
138 	xspect_plot(b->i_sp, &b->ill, NULL);
139 #endif
140 
141 	/* Update the conversion to use observer illuminant with UV */
142 	if (b->pap->update_fwa_custillum(b->pap, NULL, &b->ill) != 0)
143 		error ("Updating FWA compensation failed");
144 
145 	/* Apply FWA compensation to the paper reflectance */
146 	b->pap->sconvert(b->pap, &b->cpsp, b->lab0, b->p_sp);
147 
148 	/* Adjust gain factor of measured illuminant off paper */
149 	/* and divide by illuminant measurement to give reflectance */
150 	b->srop = *b->r_sp;
151 	for (i = 0; i < b->r_sp->spec_n; i++) {
152 		double ww = XSPECT_XWL(b->r_sp, i);
153 		double ival = value_xspect(b->i_sp, ww);
154 		if (ival < 0.05)		/* Stop noise sending it wild */
155 			ival = 0.05;
156 		b->srop.spec[i] *= pv[1]/ival;
157 		if (b->srop.spec[i] < 0.0)
158 			b->srop.spec[i] = 0.0;
159 	}
160 
161 	/* Compute Lab of the computed reflectance under flat spectrum */
162 	b->ref->convert(b->ref, b->lab0, &b->cpsp);
163 
164 	/* Compute Lab value of illuminant measured reflectance */
165 	b->ref->convert(b->ref, b->lab1, &b->srop);
166 
167 	/* Weighted Delta E (low weight on a* error) */
168 	rv = sqrt(      (b->lab0[0] - b->lab1[0]) * (b->lab0[0] - b->lab1[0])
169 	        + 0.1 * (b->lab0[1] - b->lab1[1]) * (b->lab0[1] - b->lab1[1])
170 	        +       (b->lab0[2] - b->lab1[2]) * (b->lab0[2] - b->lab1[2]));
171 
172 	/* Add a slight weight of the UV level, to minimize it */
173 	/* if the case is unconstrained. */
174 	rv += 0.1 * fabs(pv[0]);
175 
176 #ifdef PLOT_FITTING	/* Plot the two reflectance spectra */
177 	printf("rev = %f (%f %f %f - %f %f %f) from UV %f GA %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
178 
179 	printf("Black = Measured, Red = trial\n");
180 	xspect_plot(&b->srop, &b->cpsp, NULL);
181 #endif
182 
183 	return rv;
184 }
185 
186 /* ============================================================== */
187 #ifdef SHOWDXX			/* Plot the best matched daylight as well */
188 
189 /* optimizer callback for computing daylight match */
190 
191 /* Structure to hold optimisation information */
192 typedef struct {
193 	xspect ill;			/* Illuminant with UV added - target */
194 	xspect dxx;			/* Daylight spectrum */
195 
196 	xsp2cie *ref;		/* reference Lab conversion */
197 
198 	double lab0[3], lab1[3];	/* Conversion of target vs. Daylight */
199 } cfinds;
200 
201 /* Optimize the daylight color temperature and level to minimizes the Delta E */
cfindfunc(void * adata,double pv[])202 static double cfindfunc(void *adata, double pv[]) {
203 	cfinds *b = (cfinds *)adata;
204 	int i;
205 	double rv = 0.0;
206 
207 	/* Compute daylight with the given color temperature */
208 	standardIlluminant( &b->dxx, icxIT_Dtemp, pv[0]);
209 	b->dxx.norm = 1.0;
210 
211 	/* Adjust the level of daylight spectra */
212 	for (i = 0; i < b->dxx.spec_n; i++) {
213 		b->dxx.spec[i] *= pv[1];
214 	}
215 
216 	/* Compute Lab of target */
217 	b->ref->convert(b->ref, b->lab0, &b->ill);
218 
219 	/* Compute Lab of Dxx */
220 	b->ref->convert(b->ref, b->lab1, &b->dxx);
221 
222 	/* Weighted Delta E (low weight on a* error) */
223 	rv = icmLabDEsq(b->lab0, b->lab1);
224 
225 //printf("~1 rev = %f (%f %f %f - %f %f %f) from %f %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
226 	return rv;
227 }
228 
229 #endif /* SHOWDXX */
230 
231 /* ============================================================== */
232 void
usage(char * diag,...)233 usage(char *diag, ...) {
234 	icompaths *icmps;
235 	fprintf(stderr,"Measure an illuminant, Version %s\n",ARGYLL_VERSION_STR);
236 	fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
237 	if (diag != NULL) {
238 		va_list args;
239 		fprintf(stderr,"Diagnostic: ");
240 		va_start(args, diag);
241 		vfprintf(stderr, diag, args);
242 		va_end(args);
243 		fprintf(stderr,"\n");
244 	}
245 	fprintf(stderr,"usage: illumread [-options] output.sp\n");
246 	fprintf(stderr," -v                   Verbose mode\n");
247 	fprintf(stderr," -S                   Plot spectrum for each reading\n");
248 	fprintf(stderr," -c listno            Choose instrument from the following list (default 1)\n");
249 	if ((icmps = new_icompaths(g_log)) != NULL) {
250 		icompath **paths;
251 		if ((paths = icmps->paths) != NULL) {
252 			int i;
253 			for (i = 0; ; i++) {
254 				if (paths[i] == NULL)
255 					break;
256 				if ((paths[i]->itype == instSpyder1 && setup_spyd2(0) == 0)
257 				 || (paths[i]->itype == instSpyder2 && setup_spyd2(1) == 0))
258 					fprintf(stderr,"    %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
259 				else
260 					fprintf(stderr,"    %d = '%s'\n",i+1,paths[i]->name);
261 			}
262 		} else
263 			fprintf(stderr,"    ** No ports found **\n");
264 	}
265 	fprintf(stderr," -N                   Disable initial calibration of instrument if possible\n");
266 	fprintf(stderr," -H                   Use high resolution spectrum mode (if available)\n");
267 	fprintf(stderr," -Y r                 Set refresh measurement mode\n");
268 	fprintf(stderr," -Y R:rate            Override measured refresh rate with rate Hz\n");
269 	fprintf(stderr," -W n|h|x             Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
270 	fprintf(stderr," -T                   Test mode - restore & save measurements to\n");
271 	fprintf(stderr,"                       *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files\n");
272 	fprintf(stderr," -D [level]           Print debug diagnostics to stderr\n");
273 	fprintf(stderr," illuminant.sp        File to save measurement to\n");
274 
275 	if (icmps != NULL)
276 		icmps->del(icmps);
277 	exit(1);
278 }
279 
main(int argc,char * argv[])280 int main(int argc, char *argv[])
281 {
282 	int i,j;
283 	int fa, nfa, mfa;				/* current argument we're looking at */
284 	int verb = 0;
285 	int debug = 0;
286 	int nocal = 0;					/* Disable initial calibration */
287 	int pspec = 0;                  /* 2 = Plot out the spectrum for each reading */
288 	int highres = 0;				/* Use high res mode if available */
289 	int refrmode = -1;				/* -1 = default,  = non-refresh mode, 1 = non-refresh mode */
290 	double refrate = 0.0;			/* 0.0 = default, > 0.0 = override refresh rate */
291 	char outname[MAXNAMEL+1] = "\000";  /* Spectral output file name */
292 
293 	int tmode = 0;					/* Test mode */
294 	char tname[MAXNAMEL+11] = "\000", *tnp;		/* Test mode file names */
295 	int rd_i = 0, rd_r = 0, rd_p = 0;			/* Test mode flags */
296 
297 	icompaths *icmps = NULL;		/* Ports to choose from */
298 	int comno = 1;					/* Specific port suggested by user */
299 	inst *it = NULL;				/* Instrument object, NULL if none */
300 	inst_mode mode = 0;				/* Instrument reading mode */
301 	inst_opt_type trigmode = inst_opt_unknown;	/* Chosen trigger mode */
302 	instType itype = instUnknown;	/* No default target instrument */
303 	inst_mode cap = inst_mode_none;		/* Instrument mode capabilities */
304 	inst2_capability cap2 = inst2_none;	/* Instrument capabilities 2 */
305 	inst3_capability cap3 = inst3_none;	/* Instrument capabilities 3 */
306 	baud_rate br = baud_38400;		/* Target baud rate */
307 	flow_control fc = fc_nc;		/* Default flow control */
308 
309 	inst_code rv;
310 	int uswitch = 0;				/* Instrument switch is enabled */
311 	xspect i_sp;					/* Illuminant emsission spectrum */
312 	xspect r_sp;					/* Illuminant reflected from paper emission spectrum */
313 	xspect p_sp;					/* Paper reflectance spectrum */
314 	xspect insp;					/* Instrument illuminant (for FWA) */
315 	xspect ill;						/* Estimated illuminant */
316 	xspect aill;					/* Accumulated result */
317 	int    nacc = 0;				/* Number accumulated */
318 	ipatch val;						/* Value read */
319 
320 	set_exe_path(argv[0]);			/* Set global exe_path and error_program */
321 	check_if_not_interactive();
322 
323 	i_sp.spec_n = 0;
324 	r_sp.spec_n = 0;
325 	p_sp.spec_n = 0;
326 	insp.spec_n = 0;
327 	ill.spec_n = 0;
328 	aill.spec_n = 0;
329 
330 	/* Process the arguments */
331 	mfa = 0;        /* Minimum final arguments */
332 	for(fa = 1;fa < argc;fa++) {
333 		nfa = fa;					/* skip to nfa if next argument is used */
334 		if (argv[fa][0] == '-') {	/* Look for any flags */
335 			char *na = NULL;		/* next argument after flag, null if none */
336 
337 			if (argv[fa][2] != '\000')
338 				na = &argv[fa][2];		/* next is directly after flag */
339 			else {
340 				if ((fa+1+mfa) < argc) {
341 					if (argv[fa+1][0] != '-') {
342 						nfa = fa + 1;
343 						na = argv[nfa];		/* next is seperate non-flag argument */
344 					}
345 				}
346 			}
347 
348 			if (argv[fa][1] == '?') {
349 				usage(NULL);
350 
351 			} else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
352 				verb = 1;
353 				g_log->verb = verb;
354 
355 			} else if (argv[fa][1] == 'S') {
356 				pspec = 2;
357 
358 			/* COM port  */
359 			} else if (argv[fa][1] == 'c') {
360 				fa = nfa;
361 				if (na == NULL) usage(NULL);
362 				comno = atoi(na);
363 				if (comno < 1 || comno > 99) usage(NULL);
364 
365 			/* No initial calibration */
366 			} else if (argv[fa][1] == 'N') {
367 				nocal = 1;
368 
369 			/* High res mode */
370 			} else if (argv[fa][1] == 'H') {
371 				highres = 1;
372 
373 			/* Extra flags */
374 			} else if (argv[fa][1] == 'Y') {
375 				if (na == NULL)
376 					usage(NULL);
377 
378 				if (na[0] == 'R') {
379 					if (na[1] != ':')
380 						usage("-Y R:rate syntax incorrect");
381 					refrate = atof(na+2);
382 					if (refrate < 5.0 || refrate > 150.0)
383 						usage("-Y R:rate %f Hz not in valid range",refrate);
384 				} else if (na[0] == 'r')
385 					refrmode = 1;
386 				else
387 					usage(NULL);
388 				fa = nfa;
389 
390 			/* Serial port flow control */
391 			} else if (argv[fa][1] == 'W') {
392 				fa = nfa;
393 				if (na == NULL) usage(NULL);
394 
395 					if (na[0] == 'n' || na[0] == 'N')
396 						fc = fc_None;
397 					else if (na[0] == 'h' || na[0] == 'H')
398 						fc = fc_Hardware;
399 					else if (na[0] == 'x' || na[0] == 'X')
400 						fc = fc_XonXOff;
401 					else
402 						usage(NULL);
403 
404 			} else if (argv[fa][1] == 'T') {
405 				tmode = 1;
406 
407 			} else if (argv[fa][1] == 'D') {
408 				debug = 1;
409 				if (na != NULL && na[0] >= '0' && na[0] <= '9') {
410 					debug = atoi(na);
411 					fa = nfa;
412 				}
413 				g_log->debug = debug;
414 			} else
415 				usage(NULL);
416 		}
417 		else
418 			break;
419 	}
420 
421 	/* Get the output spectrum file name argument */
422 	if (fa >= argc)
423 		usage(NULL);
424 
425 	strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
426 
427 	if (tmode) {
428 		strcpy(tname, outname);
429 		if ((tnp = strrchr(tname, '.')) == NULL)
430 			tnp = tname + strlen(tname);
431 
432 		/* Special debug */
433 		strcpy(tnp, "_i.sp");
434 		if (read_xspect(&i_sp, NULL, tname) == 0) {
435 			rd_i = 1;
436 			printf("(Found '%s' file and loaded it)\n",tname);
437 		}
438 		strcpy(tnp, "_r.sp");
439 		if (read_xspect(&r_sp, NULL, tname) == 0) {
440 			rd_r = 1;
441 			printf("(Found '%s' file and loaded it)\n",tname);
442 		}
443 		strcpy(tnp, "_p.sp");
444 		if (read_xspect(&p_sp, NULL, tname) == 0) {
445 			rd_p = 1;
446 			/* Should read instrument type from debug_p.sp !! */
447 			if (inst_illuminant(&insp, instI1Pro) != 0)		/* Hack !! */
448 				error ("Instrument doesn't have an FWA illuminent");
449 			printf("(Found '%s' file and loaded it)\n",tname);
450 		}
451 	}
452 
453 	/* Until the measurements are done, or we give up */
454 	for (;;) {
455 		int c;
456 
457 		/* Print the menue of adjustments */
458 		printf("\nPress 1 .. 7\n");
459 		printf("1) Measure direct illuminant%s\n",i_sp.spec_n != 0 ? " (measured)":"");
460 		printf("2) Measure illuminant reflected from paper%s\n", r_sp.spec_n != 0 ? " (measured)":"");
461 		printf("3) Measure paper%s\n", p_sp.spec_n != 0 ? " (measured)":"");
462 		if (it == NULL) {
463 			printf("4) Select another instrument, Currently %d (", comno);
464 			if (icmps == NULL)
465 				icmps = new_icompaths(g_log);
466 			else
467 				icmps->refresh(icmps);
468 			if (icmps != NULL) {
469 				icompath **paths;
470 				if ((paths = icmps->paths) != NULL) {
471 					int i;
472 					for (i = 0; ; i++) {
473 						if (paths[i] == NULL)
474 							break;
475 						if ((i+1) == comno) {
476 							printf(" '%s'",paths[i]->name);
477 							break;
478 						}
479 					}
480 				}
481 			}
482 			printf(")\n");
483 		} else
484 			printf("4) Select another instrument, Currently %s\n", inst_name(itype));
485 		printf("5) Compute illuminant spectrum, average result with %d previous readings & save it\n",nacc);
486 		printf("6) Compute illuminant spectrum from this reading & save result\n");
487 		printf("7) Exit\n");
488 
489 		empty_con_chars();
490 		c = next_con_char();
491 		printf("'%c'\n",c);
492 
493 		/* Deal with doing a measurement */
494 		if (c == '1' || c == '2' || c == '3') {
495 			int ch;
496 
497 			if (it == NULL) {
498 				icompath *ipath;
499 				if (icmps == NULL)
500 					icmps = new_icompaths(g_log);
501 
502 				/* Open the instrument */
503 				ipath = icmps->get_path(icmps, comno);
504 				if ((it = new_inst(ipath, 0, g_log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
505 					printf("!!! Unknown, inappropriate or no instrument detected !!!\n");
506 					continue;
507 				}
508 
509 				if (verb)
510 					printf("Connecting to the instrument ..\n");
511 
512 #ifdef DEBUG
513 				printf("About to init the comms\n");
514 #endif
515 
516 				/* Establish communications */
517 				if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
518 					printf("!!! Failed to initialise communications with instrument\n"
519 					       "    or wrong instrument or bad configuration !!!\n"
520 					       "   ('%s' + '%s')\n", it->inst_interp_error(it, rv), it->interp_error(it, rv));
521 					it->del(it);
522 					it = NULL;
523 					itype = instUnknown;
524 					continue;
525 				}
526 
527 #ifdef DEBUG
528 				printf("Established comms & initing the instrument\n");
529 #endif
530 
531 				/* Initialise the instrument */
532 				if ((rv = it->init_inst(it)) != inst_ok) {
533 					printf("!!! Instrument initialisation failed with '%s' (%s) !!!\n",
534 					      it->inst_interp_error(it, rv), it->interp_error(it, rv));
535 					it->del(it);
536 					it = NULL;
537 					itype = instUnknown;
538 					continue;
539 				}
540 
541 				itype = it->get_itype(it);		/* get actual type of instrument */
542 
543 				/* Check the instrument has the necessary capabilities */
544 				it->capabilities(it, &cap, &cap2, &cap3);
545 
546 				/* Need spectral */
547 				if (!IMODETST(cap, inst_mode_spectral)) {
548 					printf("Instrument lacks spectral measurement capability");
549 				}
550 
551 				if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
552 				                  && it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
553 					if (verb) {
554 						printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
555 						refrmode = -1;
556 					}
557 				}
558 
559 				/* Disable iniial calibration of machine if selected */
560 				if (nocal != 0) {
561 					if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
562 						printf("Setting no-initial calibrate failed failed with '%s' (%s) !!!\n",
563 					       it->inst_interp_error(it, rv), it->interp_error(it, rv));
564 						printf("Disable initial-calibrate not supported\n");
565 					}
566 				}
567 			}
568 
569 			/* Check the instrument has the necessary capabilities for this measurement */
570 			it->capabilities(it, &cap, &cap2, &cap3);
571 
572 			if (c == '1') {
573 				if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
574 					mode = inst_mode_emis_ambient;
575 				} else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
576 					mode = inst_mode_emis_spot;
577 				} else {
578 					printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
579 					continue;
580 				}
581 			}
582 			if (c == '2') {
583 				if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
584 					mode = inst_mode_emis_tele;
585 				} else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
586 					mode = inst_mode_emis_spot;
587 				} else {
588 					printf("!!! Instrument doesn't have telephoto or emissive capability !!!\n");
589 					continue;
590 				}
591 			}
592 			if (c == '3') {
593 				inst_opt_filter filt;
594 
595 				if (it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
596 					mode = inst_mode_ref_spot;
597 				} else {
598 					printf("!!! Instrument lacks reflective spot measurement capability !!!\n");
599 					continue;
600 				}
601 
602 				if ((rv = it->get_set_opt(it, inst_stat_get_filter, &filt)) == inst_ok) {
603 					if (filt & inst_opt_filter_UVCut) {
604 						printf("!!! Instrument has UV filter - can't measure FWA !!!\n");
605 						continue;
606 					}
607 				}
608 			}
609 			mode |= inst_mode_spectral;
610 
611 			if (refrmode == 0)
612 				mode |= inst_mode_emis_norefresh_ovd;
613 			else if (refrmode == 1)
614 				mode |= inst_mode_emis_refresh_ovd;
615 
616 			if (highres) {
617 				if (IMODETST(cap, inst_mode_highres)) {
618 					mode |= inst_mode_highres;
619 				} else if (verb) {
620 					printf("!!! High resolution ignored - instrument doesn't support it !!!\n");
621 				}
622 			}
623 
624 			if ((rv = it->set_mode(it, mode)) != inst_ok) {
625 				printf("!!! Setting instrument mode failed with error :'%s' (%s) !!!\n",
626 			     	       it->inst_interp_error(it, rv), it->interp_error(it, rv));
627 				continue;
628 			}
629 			it->capabilities(it, &cap, &cap2, &cap3);
630 
631 			if (refrate > 0.0) {
632 				if (!(cap2 & inst2_set_refresh_rate)) {
633 					if (verb)
634 						printf("Attempted to set refresh rate and instrument doesn't support setting it (ignored)\n");
635 					refrate = 0.0;
636 				} else {
637 					if ((rv = it->set_refr_rate(it, refrate)) != inst_ok) {
638 						error("Setting instrument refresh rate to %f Hz failed with error :'%s' (%s)",
639 					     	       refrate, it->inst_interp_error(it, rv), it->interp_error(it, rv));
640 					}
641 				}
642 			}
643 
644 			/* If it batter powered, show the status of the battery */
645 			if ((cap2 & inst2_has_battery)) {
646 				double batstat = 0.0;
647 				if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) == inst_ok)
648 					printf("The battery charged level is %.0f%%\n",batstat * 100.0);
649 			}
650 
651 			/* If it's an instrument that need positioning do trigger using user via uicallback */
652 			/* in illumread, else enable switch or keyboard trigger if possible. */
653 			if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
654 				trigmode = inst_opt_trig_prog;
655 
656 			} else if (cap2 & inst2_user_switch_trig) {
657 				trigmode = inst_opt_trig_user_switch;
658 				uswitch = 1;
659 
660 			/* Or go for user via uicallback trigger */
661 			} else if (cap2 & inst2_user_trig) {
662 				trigmode = inst_opt_trig_user;
663 
664 			/* Or something is wrong with instrument capabilities */
665 			} else {
666 				printf("!!! No reasonable trigger mode avilable for this instrument !!!\n");
667 				continue;
668 			}
669 			if ((rv = it->get_set_opt(it, trigmode)) != inst_ok) {
670 				printf("!!! Setting trigger mode failed with error :'%s' (%s) !!!\n",
671 		       	       it->inst_interp_error(it, rv), it->interp_error(it, rv));
672 				continue;
673 			}
674 
675 			/* Setup the keyboard trigger to return our commands */
676 			inst_set_uih(0x0, 0xff,  DUIH_TRIG);
677 			inst_set_uih('q', 'q',   DUIH_ABORT);
678 			inst_set_uih('Q', 'Q',   DUIH_ABORT);
679 			inst_set_uih(0x03, 0x03, DUIH_ABORT);		/* ^c */
680 			inst_set_uih(0x1b, 0x1b, DUIH_ABORT);		/* Esc */
681 
682 			/* Hold table */
683 			if (cap2 & inst2_xy_holdrel) {
684 				for (;;) {		/* retry loop */
685 					if ((rv = it->xy_sheet_hold(it)) == inst_ok)
686 						break;
687 
688 					if (ierror(it, rv)) {
689 						printf("!!! Setting paper hold failed with error :'%s' (%s) !!!\n",
690 						       it->inst_interp_error(it, rv), it->interp_error(it, rv));
691 						it->xy_clear(it);
692 						continue;
693 					}
694 				}
695 			}
696 
697 			/* Do any needed calibration before the user places the instrument on a desired spot */
698 			if (it->needs_calibration(it) != inst_calt_none) {
699 				double lx, ly;
700 				inst_code ev;
701 
702 				printf("\nInstrument needs a calibration before continuing\n");
703 
704 				/* save current location */
705 				if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
706 					for (;;) {		/* retry loop */
707 						if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok)
708 							break;
709 						if (ierror(it, ev) == 0)	/* Ignore */
710 							continue;
711 						break;						/* Abort */
712 					}
713 					if (ev != inst_ok) {
714 						printf("!!! Setting calibration location failed with error :'%s' (%s) !!!\n",
715 							it->inst_interp_error(it, rv), it->interp_error(it, rv));
716 						continue;
717 					}
718 				}
719 
720 				ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0);
721 				if (ev != inst_ok) {	/* Abort or fatal error */
722 					printf("!!! Calibration failed with error :'%s' (%s) !!!\n",
723 						it->inst_interp_error(it, rv), it->interp_error(it, rv));
724 					continue;
725 				}
726 
727 				/* restore location */
728 				if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
729 					for (;;) {		/* retry loop */
730 						if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
731 							break;
732 						if (ierror(it, ev) == 0)	/* Ignore */
733 							continue;
734 						break;						/* Abort */
735 					}
736 					if (ev != inst_ok) {
737 						printf("!!! Restoring location failed with error :'%s' (%s) !!!\n",
738 							it->inst_interp_error(it, rv), it->interp_error(it, rv));
739 						continue;
740 					}
741 				}
742 			}
743 
744 			/* Now do the measurement: */
745 
746 			/* If this is an xy instrument: */
747 			if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
748 
749 				/* Allow the user to position the instrument */
750 				for (;;) {		/* retry loop */
751 					if ((rv = it->xy_locate_start(it)) == inst_ok)
752 						break;
753 					if (ierror(it, rv) == 0)	/* Ignore */
754 						continue;
755 					break;						/* Abort */
756 				}
757 				if (rv != inst_ok)
758 					break;			/* Abort */
759 
760 				if (c != 3) {
761 					printf("!!! Unexpected: XY instrument used for emissive measurements !!!\n");
762 					continue;
763 				}
764 
765 				printf("Using the XY table controls, position the instrument sight\n");
766 				printf("so as to read the paper,\n");
767 
768 			/* Purely manual instrument */
769 			} else {
770 
771 				if (c == '1') {
772 					if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
773 						printf("\n(If applicable) set instrument to ambient measurenent mode, or place\n");
774 						printf("ambient adapter on it, and position it so as to measure the illuminant directly.\n");
775 					} else {
776 						printf("\n(If applicable) set instrument to emissive measurenent mode,\n");
777 						printf("and position it so as to measure the illuminant directly.\n");
778 					}
779 				} else if (c == '2') {
780 					if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
781 						printf("\n(If applicable) set instrument to telephoto measurenent mode,\n");
782 						printf("position it so as to measure the illuminant reflected from the paper.\n");
783 					} else {
784 						printf("\n(If applicable) set instrument to emsissive measurenent mode,\n");
785 						printf("position it so as to measure the illuminant reflected from the paper.\n");
786 					}
787 				} else if (c == '3') {
788 					printf("\n(If applicable) set instrument to reflective measurenent mode,\n");
789 					printf("position it so as to measure the paper.");
790 				} else
791 					error("Unexpected choice");
792 			}
793 			if (uswitch)
794 				printf("Hit ESC or Q to abort, or instrument switch or any other key to take a reading: ");
795 			else
796 				printf("Hit ESC or Q to abort, any any other key to take a reading: ");
797 			fflush(stdout);
798 
799 			if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
800 
801 				/* Wait for the user to hit a key */
802 				for (;;) {
803 					if ((rv = inst_get_uicallback()(inst_get_uicontext(), inst_armed)) != inst_ok)
804 						break;
805 				}
806 
807 				if (rv == inst_user_abort) {
808 					break;				/* Abort */
809 
810 				} else if (rv == inst_user_trig) {
811 					double lx, ly;
812 					inst_code ev;
813 
814 					/* Take the location set on the sight, and move the instrument */
815 					/* to take the measurement there. */
816 					if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
817 						for (;;) {		/* retry loop */
818 							if ((rv = it->xy_get_location(it, &lx, &ly)) == inst_ok)
819 								break;
820 							if (ierror(it, rv) == 0)	/* Ignore */
821 								continue;
822 							break;						/* Abort */
823 						}
824 						if (rv != inst_ok)
825 							break;			/* Abort */
826 
827 						for (;;) {		/* retry loop */
828 							if ((rv = it->xy_locate_end(it)) == inst_ok)
829 								break;
830 							if (ierror(it, rv) == 0)	/* Ignore */
831 								continue;
832 							break;						/* Abort */
833 						}
834 						if (rv != inst_ok)
835 							break;			/* Abort */
836 
837 						for (;;) {		/* retry loop */
838 							if ((rv = it->xy_position(it, 1, lx, ly)) == inst_ok)
839 								break;
840 							if (ierror(it, rv) == 0)	/* Ignore */
841 								continue;
842 							break;						/* Abort */
843 						}
844 						if (rv != inst_ok)
845 							break;			/* Abort */
846 					}
847 					rv = it->read_sample(it, "SPOT", &val, 1);
848 
849 					/* Restore the location the instrument to have the location */
850 					/* sight over the selected patch. */
851 					for (;;) {		/* retry loop */
852 						if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
853 							break;
854 						if (ierror(it, ev) == 0)	/* Ignore */
855 							continue;
856 						break;						/* Abort */
857 					}
858 					if (ev != inst_ok)
859 						break;			/* Abort */
860 				}
861 				/* else what ? */
862 
863 			/* Not an XY instrument */
864 			} else {
865 				rv = it->read_sample(it, "SPOT", &val, 1);
866 			}
867 
868 			/* Release paper */
869 			if (cap2 & inst2_xy_holdrel) {
870 				it->xy_clear(it);
871 			}
872 
873 #ifdef DEBUG
874 			printf("read_sample returned '%s' (%s)\n",
875 		       it->inst_interp_error(it, rv), it->interp_error(it, rv));
876 #endif /* DEBUG */
877 
878 			/* Deal with a trigger or command */
879 			if ((rv & inst_mask) == inst_user_trig) {
880 			    ch = inst_get_uih_char() & 0xff;
881 
882 			/* Deal with a command or abort */
883 			} else if ((rv & inst_mask) == inst_user_abort) {
884 			    ch = inst_get_uih_char();
885 
886 				if (ch & DUIH_CMND) {
887 			    	ch &= 0xff;
888 				} else if (ch & DUIH_ABORT) {
889 					printf("\nIlluminant measure aborted at user request!\n");
890 					continue;
891 				}
892 
893 			/* Deal with a needs calibration */
894 			} else if ((rv & inst_mask) == inst_needs_cal) {
895 				inst_code ev;
896 				printf("\nIlluminant measure failed because instruments needs calibration.\n");
897 				ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0);
898 				continue;
899 
900 			/* Deal with a bad sensor position */
901 			} else if ((rv & inst_mask) == inst_wrong_config) {
902 				printf("\nIlluminant measure failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv));
903 				continue;
904 
905 			/* Deal with a misread */
906 			} else if ((rv & inst_mask) == inst_misread) {
907 				printf("\nIlluminant measure failed due to misread (%s)\n",it->interp_error(it, rv));
908 				continue;
909 
910 			/* Deal with a communications error */
911 			} else if ((rv & inst_mask) == inst_coms_fail) {
912 				empty_con_chars();
913 				printf("\nIlluminant measure failed due to communication problem.\n");
914 				printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
915 				continue;
916 
917 			/* Some other fatal error */
918 			} else if (rv != inst_ok) {
919 				printf("\nGot fatal error '%s' (%s)\n",
920 					it->inst_interp_error(it, rv), it->interp_error(it, rv));
921 				continue;
922 			}
923 
924 			if (c == '1') {		/* Illuminant */
925 				i_sp = val.sp;
926 				if (tmode && rd_i == 0) {
927 					strcpy(tnp, "_i.sp");
928 					write_xspect(tname, inst_mrt_emission, &i_sp);
929 				}
930 			} else if (c == '2') {	/* Illuminant reflected on paper */
931 				r_sp = val.sp;
932 				if (tmode && rd_r == 0) {
933 					strcpy(tnp, "_r.sp");
934 					write_xspect(tname, inst_mrt_emission, &r_sp);
935 				}
936 			} else if (c == '3') {	/* Paper reflectance */
937 				p_sp = val.sp;
938 
939 				/* Get the illuminant spectrum too */
940 				if (inst_illuminant(&insp, itype) != 0)
941 					error ("Instrument doesn't have an FWA illuminent");
942 
943 				if (tmode && rd_p == 0) {
944 					/* Should save instrument type/instrument illuminant spectrum !!! */
945 					strcpy(tnp, "_p.sp");
946 					write_xspect(tname, inst_mrt_reflective, &p_sp);
947 				}
948 			}
949 
950 			if (pspec) {
951 				double xx[XSPECT_MAX_BANDS];
952 				double y1[XSPECT_MAX_BANDS];
953 				double xmin, xmax, ymin, ymax;
954 				int nn;
955 
956 				if (val.sp.spec_n <= 0)
957 					error("Instrument didn't return spectral data");
958 
959 				printf("Spectrum from %f to %f nm in %d steps\n",
960 			                val.sp.spec_wl_short, val.sp.spec_wl_long, val.sp.spec_n);
961 
962 				if (val.sp.spec_n > XSPECT_MAX_BANDS)
963 					error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,val.sp.spec_n);
964 
965 				for (j = 0; j < val.sp.spec_n; j++) {
966 					GCC_BUGFIX(j)
967 					xx[j] = val.sp.spec_wl_short
968 					      + j * (val.sp.spec_wl_long - val.sp.spec_wl_short)/(val.sp.spec_n-1);
969 
970 					y1[j] = value_xspect(&val.sp, xx[j]);
971 				}
972 
973 				xmax = val.sp.spec_wl_long;
974 				xmin = val.sp.spec_wl_short;
975 				ymin = ymax = 0.0;	/* let it scale */
976 				do_plot_x(xx, y1, NULL, NULL, val.sp.spec_n, 1,
977 				          xmin, xmax, ymin, ymax, 2.0);
978 			}
979 
980 			continue;
981 		}	/* End of take a measurement */
982 
983 		/* Deal with selecting the instrument */
984 		if (c == '4') {
985 
986 			if (it != NULL)
987 				it->del(it);
988 			it = NULL;
989 			itype = instUnknown;
990 
991 			if (icmps == NULL)
992 				icmps = new_icompaths(g_log);
993 			else
994 				icmps->refresh(icmps);
995 			if (icmps != NULL) {
996 				icompath **paths;
997 				if ((paths = icmps->paths) != NULL) {
998 					int i;
999 					for (i = 0; ; i++) {
1000 						if (paths[i] == NULL)
1001 							break;
1002 						if ((paths[i]->itype == instSpyder1 && setup_spyd2(0) == 0)
1003 						 || (paths[i]->itype == instSpyder2 && setup_spyd2(1) == 0))
1004 							fprintf(stderr,"    %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
1005 						else
1006 							fprintf(stderr,"    %d = '%s'\n",i+1,paths[i]->name);
1007 					}
1008 					printf("Select device 1 - %d: \n",i);
1009 					empty_con_chars();
1010 					c = next_con_char();
1011 
1012 					if (c < '1' || c > ('0' + i)) {
1013 						printf("'%c' is out of range - ignored !\n",c);
1014 					} else {
1015 						comno = c - '0';
1016 					}
1017 
1018 				} else {
1019 					fprintf(stderr,"No ports to select from!\n");
1020 				}
1021 			}
1022 			continue;
1023 		}
1024 		if (c == '5' || c == '6') {		/* Compute result */
1025 			xspect cpisp;		/* FWA corrected calculated initial paper reflectance */
1026 			double gain;
1027 			bfinds bf;	/* Optimization context */
1028 			double xyz0[3], xyz1[3];
1029 			double tt[2], sr[2];
1030 			double rv;
1031 
1032 			if (i_sp.spec_n == 0) {
1033 				printf("Need to measure the direct illuminant\n");
1034 				continue;
1035 			}
1036 			if (r_sp.spec_n == 0) {
1037 				printf("Need to measure the illuminant reflected off paper\n");
1038 				continue;
1039 			}
1040 			if (p_sp.spec_n == 0) {
1041 				printf("Need to measure the paper\n");
1042 				continue;
1043 			}
1044 
1045 			/* Normalize direct illumination */
1046 			for (gain = 0.0, i = 0; i < i_sp.spec_n; i++)
1047 				gain += i_sp.spec[i];
1048 			gain /= i_sp.spec_n;
1049 			for (i = 0; i < i_sp.spec_n; i++)
1050 				i_sp.spec[i] /= gain;
1051 
1052 			/* Normalize indirect illumination */
1053 			for (gain = 0.0, i = 0; i < r_sp.spec_n; i++)
1054 				gain += r_sp.spec[i];
1055 			gain /= r_sp.spec_n;
1056 			for (i = 0; i < r_sp.spec_n; i++)
1057 				r_sp.spec[i] /= gain;
1058 
1059 			/* Normalize paper reflectance to 1.0 */
1060 			xspect_denorm(&p_sp);
1061 
1062 			bf.i_sp = &i_sp;
1063 			bf.r_sp = &r_sp;
1064 			bf.p_sp = &p_sp;
1065 
1066 			if ((bf.pap = new_xsp2cie(icxIT_custom, &i_sp, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
1067 				error("new_xsp2cie pap failed");
1068 
1069 			if (bf.pap->set_fwa(bf.pap, &insp, NULL, &p_sp) != 0)
1070 				error ("Setting FWA compensation failed");
1071 
1072 			/* Setup the equal energy to Lab conversion */
1073 			if ((bf.ref = new_xsp2cie(icxIT_E, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
1074 				error("new_xsp2cie ref failed");
1075 
1076 			/* Estimate an initial gain match */
1077 			tt[0] = 0.0;
1078 			tt[1] = 1.0;
1079 			bfindfunc((void *)&bf, tt);
1080 			icmLab2XYZ(&icmD50, xyz0, bf.lab0);
1081 			icmLab2XYZ(&icmD50, xyz1, bf.lab1);
1082 
1083 			gain = xyz0[1] / xyz1[1];
1084 //printf("~1 Target XYZ %f %f %f, is %f %f %f, gain needed = %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2],gain);
1085 
1086 			for (i = 0; i < r_sp.spec_n; i++)
1087 				r_sp.spec[i] *= gain;
1088 
1089 			/* Check initial gain match is OK */
1090 			bfindfunc((void *)&bf, tt);
1091 			cpisp = bf.cpsp;			/* Copy initial match */
1092 			icmLab2XYZ(&icmD50, xyz0, bf.lab0);
1093 			icmLab2XYZ(&icmD50, xyz1, bf.lab1);
1094 #ifdef NEVER
1095 			printf("~1 Target XYZ %f %f %f, now %f %f %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2]);
1096 #endif
1097 
1098 			tt[0] = 0.1, tt[1] = 1.0;	/* Search parameter starting values */
1099 			sr[0] = sr[1] = 0.1;		/* Search parameter search radiuses */
1100 
1101 			if (powell(&rv, 2, tt, sr, 0.0001, 1000,
1102 			           bfindfunc, (void *)&bf, NULL, NULL) != 0) {
1103 				printf("Optimization search failed\n");
1104 				continue;
1105 			}
1106 			printf("(Best match DE %f, UV content = %f (gain match %f))\n", rv, tt[0], tt[1]);
1107 
1108 			/* Compute the result */
1109 			bfindfunc((void *)&bf, tt);
1110 			ill = bf.ill;
1111 
1112 			if (c == '5' && nacc > 0) {
1113 				for (i = 0; i < ill.spec_n; i++)
1114 					aill.spec[i] += ill.spec[i];
1115 				nacc++;
1116 			} else {
1117 				aill = ill;
1118 				nacc = 1;
1119 			}
1120 
1121 			/* Save the result */
1122 			if (aill.spec_n == 0) {
1123 				printf("Nothing to save!\n");
1124 	 		} else {
1125 				for (i = 0; i < ill.spec_n; i++)
1126 					ill.spec[i] = aill.spec[i]/nacc;
1127 
1128 				if(write_xspect(outname, inst_mrt_ambient, &ill))
1129 					printf("\nWriting file '%s' failed\n",outname);
1130 				else
1131 					printf("\nWriting file '%s' succeeded\n",outname);
1132 
1133 				if (tmode) {
1134 					strcpy(tnp, "_mpir.sp");		// Measured paper under illuminant spectrum
1135 					write_xspect(tname, inst_mrt_reflective, &bf.srop);
1136 					strcpy(tnp, "_cpir.sp");		// Computed paper under illuminant spectrum
1137 					write_xspect(tname, inst_mrt_reflective, &bf.cpsp);
1138 				}
1139 			}
1140 
1141 			/* Plot the result */
1142 			if (pspec) {
1143 				double xx[XSPECT_MAX_BANDS];
1144 				double y1[XSPECT_MAX_BANDS];
1145 				double y2[XSPECT_MAX_BANDS];
1146 				double y3[XSPECT_MAX_BANDS];
1147 				double xmin, xmax, ymin, ymax;
1148 				int nn;
1149 
1150 #ifdef SHOWDXX
1151 				cfinds cf;	/* Optimization context */
1152 				double tt[2], sr[2];
1153 				double rv;
1154 				xspect cpdsp;		/* FWA corrected calculated daylight paper reflectance */
1155 
1156 				/* Setup the referencec comversion */
1157 				if ((cf.ref = new_xsp2cie(icxIT_E, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
1158 					error("new_xsp2cie ref failed");
1159 
1160 				cf.ill = bf.ill;
1161 
1162 				/* Set starting values */
1163 				tt[0] = 5000.0;		/* degrees */
1164 				tt[1] = 1.0;
1165 				cfindfunc((void *)&cf, tt);
1166 				icmLab2XYZ(&icmD50, xyz0, cf.lab0);
1167 				icmLab2XYZ(&icmD50, xyz1, cf.lab1);
1168 
1169 				tt[1] = xyz0[1] / xyz1[1];
1170 
1171 				sr[0] = 10.0;
1172 				sr[1] = 0.1;		/* Search parameter search radiuses */
1173 
1174 				if (powell(&rv, 2, tt, sr, 0.0001, 1000,
1175 				           cfindfunc, (void *)&cf, NULL, NULL) != 0) {
1176 					error("Optimization search failed\n");
1177 				}
1178 				printf("(Best daylight match DE %f, temp = %f (gain match %f))\n", rv, tt[0], tt[1]);
1179 
1180 				/* Compute the result */
1181 				cfindfunc((void *)&cf, tt);
1182 
1183 				printf("Illuminant: Black - Measured, Red - with estimated UV, Green - daylight\n");
1184 
1185 				if (bf.ill.spec_n > XSPECT_MAX_BANDS)
1186 					error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
1187 
1188 				for (j = 0; j < bf.ill.spec_n; j++) {
1189 					GCC_BUGFIX(j)
1190 					xx[j] = XSPECT_XWL(&bf.ill, j);
1191 					y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
1192 					y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
1193 					y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
1194 				}
1195 
1196 				xmax = bf.ill.spec_wl_long;
1197 				xmin = bf.ill.spec_wl_short;
1198 				ymin = ymax = 0.0;	/* let it scale */
1199 				do_plot_x(xx, y1, y2, y3, bf.ill.spec_n, 1,
1200 				          xmin, xmax, ymin, ymax, 2.0);
1201 
1202 				/* Update the conversion to the matched Dayligh */
1203 				if (bf.pap->update_fwa_custillum(bf.pap, NULL, &cf.dxx) != 0)
1204 					error ("Updating FWA compensation to daylight failed");
1205 
1206 				/* Apply FWA compensation to the paper reflectance */
1207 				bf.pap->sconvert(bf.pap, &cpdsp, NULL, bf.p_sp);
1208 
1209 				printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
1210 //				printf("Paper Reflectance: Black - Measured, Red - FWA Modelled, Green - Daylight modelled\n");
1211 
1212 				for (j = 0; j < bf.cpsp.spec_n; j++) {
1213 					GCC_BUGFIX(j)
1214 					xx[j] = XSPECT_XWL(&bf.cpsp, j);
1215 					y1[j] = value_xspect(&bf.srop, xx[j]); 	/* Measured reflectance (black) */
1216 					y2[j] = value_xspect(&cpisp, xx[j]);	 /* Computed initial reflectance (red) */
1217 					y3[j] = value_xspect(&bf.cpsp, xx[j]); 	/* Computed final reflectance (green) */
1218 //					y3[j] = value_xspect(&cpdsp, xx[j]); 	/* Computed daylight reflectance (green) */
1219 				}
1220 
1221 				xmax = bf.cpsp.spec_wl_long;
1222 				xmin = bf.cpsp.spec_wl_short;
1223 				ymin = ymax = 0.0;	/* let it scale */
1224 				do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
1225 				          xmin, xmax, ymin, ymax, 2.0);
1226 
1227 #else	// !SHOWDXX
1228 				printf("Illuminant: Black - Measured, Red - with estimated UV\n");
1229 
1230 				if (bf.ill.spec_n > XSPECT_MAX_BANDS)
1231 					error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
1232 
1233 				for (j = 0; j < bf.ill.spec_n; j++) {
1234 					GCC_BUGFIX(j)
1235 					xx[j] = XSPECT_XWL(&bf.ill, j);
1236 					y1[j] = value_xspect(bf.i_sp, xx[j]);	/* Measured (black) */
1237 					y2[j] = value_xspect(&bf.ill, xx[j]);	/* Computed (red)*/
1238 				}
1239 
1240 				xmax = bf.ill.spec_wl_long;
1241 				xmin = bf.ill.spec_wl_short;
1242 				ymin = ymax = 0.0;	/* let it scale */
1243 				do_plot_x(xx, y1, y2, NULL, bf.ill.spec_n, 1,
1244 				          xmin, xmax, ymin, ymax, 2.0);
1245 
1246 				printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
1247 
1248 				for (j = 0; j < bf.cpsp.spec_n; j++) {
1249 					GCC_BUGFIX(j)
1250 					xx[j] = XSPECT_XWL(&bf.cpsp, j);
1251 					y1[j] = value_xspect(&bf.srop, xx[j]);	/* Measured reflectance (black) */
1252 					y2[j] = value_xspect(&cpisp, xx[j]);	/* Computed initial reflectance (red) */
1253 					y3[j] = value_xspect(&bf.cpsp, xx[j]);	/* Computed final reflectance (green) */
1254 				}
1255 
1256 				xmax = bf.cpsp.spec_wl_long;
1257 				xmin = bf.cpsp.spec_wl_short;
1258 				ymin = ymax = 0.0;	/* let it scale */
1259 				do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
1260 				          xmin, xmax, ymin, ymax, 2.0);
1261 
1262 #endif	// !SHOWDXX
1263 				printf("%s illuminant with UV:\n",c == '5' ? "Averaged" : "Computed");
1264 
1265 				for (j = 0; j < ill.spec_n; j++) {
1266 					GCC_BUGFIX(j)
1267 					xx[j] = XSPECT_XWL(&ill, j);
1268 					y1[j] = value_xspect(&ill, xx[j]);
1269 				}
1270 
1271 				xmax = ill.spec_wl_long;
1272 				xmin = ill.spec_wl_short;
1273 				ymin = ymax = 0.0;	/* let it scale */
1274 				do_plot_x(xx, y1, NULL, NULL, ill.spec_n, 1,
1275 				          xmin, xmax, ymin, ymax, 2.0);
1276 			}
1277 
1278 			/* Make sure that the illuminant is re-measured for another reading */
1279 			i_sp.spec_n = 0;
1280 			r_sp.spec_n = 0;
1281 
1282 			continue;
1283 		}
1284 
1285 		if (c == '7' || c == 0x3) {		/* Exit */
1286 			break;
1287 		}
1288 
1289 	}	/* Next command */
1290 
1291 #ifdef DEBUG
1292 	printf("About to exit\n");
1293 #endif
1294 
1295 	/* Free instrument */
1296 	if (it != NULL)
1297 		it->del(it);
1298 
1299 	return 0;
1300 }
1301 
1302 
1303 
1304 
1305