1
2 /*
3 * Argyll Color Correction System
4 *
5 * Gretag i1Monitor & i1Pro related functions
6 */
7
8 /*
9 * Author: Graeme W. Gill
10 * Date: 24/11/2006
11 *
12 * Copyright 2006 - 2014, Graeme W. Gill
13 * All rights reserved.
14 *
15 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
16 * see the License2.txt file for licencing details.
17 */
18
19 /*
20 If you make use of the instrument driver code here, please note
21 that it is the author(s) of the code who take responsibility
22 for its operation. Any problems or queries regarding driving
23 instruments with the Argyll drivers, should be directed to
24 the Argyll's author(s), and not to any other party.
25
26 If there is some instrument feature or function that you
27 would like supported here, it is recommended that you
28 contact Argyll's author(s) first, rather than attempt to
29 modify the software yourself, if you don't have firm knowledge
30 of the instrument communicate protocols. There is a chance
31 that an instrument could be damaged by an incautious command
32 sequence, and the instrument companies generally cannot and
33 will not support developers that they have not qualified
34 and agreed to support.
35 */
36
37 /*
38 TTBD
39
40 There may be a bug in HiRes emissive calibration - if you do an initial
41 cal. in normal, then switch to HiRes, no white plate cal is performed.
42 Is it using a previous cal result for this ?
43
44 Should add extra filter compensation support.
45
46 Should alias projector mode to display mode ??
47
48 */
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <ctype.h>
53 #include <string.h>
54 #include <time.h>
55 #include <stdarg.h>
56 #include <math.h>
57 #ifndef SALONEINSTLIB
58 #include "copyright.h"
59 #include "aconfig.h"
60 #include "numlib.h"
61 #include "rspl.h"
62 #else /* SALONEINSTLIB */
63 #include "sa_config.h"
64 #include "numsup.h"
65 #include "rspl1.h"
66 #endif /* SALONEINSTLIB */
67 #include "xspect.h"
68 #include "insttypes.h"
69 #include "conv.h"
70 #include "icoms.h"
71 #include "i1pro.h"
72 #include "i1pro_imp.h"
73
74 #define MAX_MES_SIZE 500 /* Maximum normal message reply size */
75 #define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
76
77 /* Convert a machine specific error code into an abstract inst code */
78 static inst_code i1pro_interp_code(i1pro *p, i1pro_code ec);
79
80 /* ------------------------------------------------------------------------ */
81
82 /* Establish communications with a I1DISP */
83 /* If it's a serial port, use the baud rate given, and timeout in to secs */
84 /* Return I1PRO_COMS_FAIL on failure to establish communications */
85 static inst_code
i1pro_init_coms(inst * pp,baud_rate br,flow_control fc,double tout)86 i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
87 i1pro *p = (i1pro *) pp;
88 int rsize, se;
89 icomuflags usbflags = icomuf_none;
90 #ifdef UNIX_APPLE
91 /* If the X-Rite software has been installed, then there may */
92 /* be a daemon process that has the device open. Kill that process off */
93 /* so that we can open it here, before it re-spawns. */
94 char *pnames[] = {
95 // "i1iSisDeviceService",
96 "i1ProDeviceService",
97 NULL
98 };
99 int retries = 20;
100 #else /* !UNIX_APPLE */
101 char **pnames = NULL;
102 int retries = 0;
103 #endif /* !UNIX_APPLE */
104
105 a1logd(p->log, 2, "i1pro_init_coms: called\n");
106
107 if (p->icom->port_type(p->icom) != icomt_usb) {
108 a1logd(p->log, 1, "i1pro_init_coms: wrong communications type for device!\n");
109 return inst_coms_fail;
110 }
111
112 a1logd(p->log, 2, "i1pro_init_coms: about to init USB\n");
113
114 /* Set config, interface, write end point, read end point, read quanta */
115 /* ("serial" end points aren't used - the i1display uses USB control messages) */
116 if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames))
117 != ICOM_OK) {
118 a1logd(p->log, 1, "i1pro_init_coms: failed ICOM err 0x%x\n",se);
119 return i1pro_interp_code(p, icoms2i1pro_err(se));
120 }
121
122 a1logd(p->log, 2, "i1pro_init_coms: init coms has suceeded\n");
123
124 p->gotcoms = 1;
125 return inst_ok;
126 }
127
128 static inst_code
i1pro_determine_capabilities(i1pro * p)129 i1pro_determine_capabilities(i1pro *p) {
130
131 /* Set the base Monitor/Pro capabilities mask */
132 p->cap = inst_mode_emis_spot
133 | inst_mode_emis_tele
134 | inst_mode_emis_strip /* Also likely to be light table reading */
135 | inst_mode_trans_spot /* Support this manually using a light table */
136 | inst_mode_trans_strip
137 | inst_mode_emis_nonadaptive
138 | inst_mode_colorimeter
139 | inst_mode_spectral
140 ;
141
142 /* Set the Pro capabilities mask */
143 if (p->itype == instI1Pro
144 || p->itype == instI1Pro2) {
145 p->cap |= inst_mode_ref_spot
146 | inst_mode_ref_strip
147 ;
148 }
149
150 /* Set the Pro2 capabilities mask */
151 if (p->itype == instI1Pro2) {
152 p->cap |= inst_mode_ref_uv
153 ;
154 }
155
156 if (i1pro_imp_highres(p)) /* This is static */
157 p->cap |= inst_mode_highres;
158
159 if (i1pro_imp_ambient(p)) { /* This depends on the instrument */
160 p->cap |= inst_mode_emis_ambient
161 | inst_mode_emis_ambient_flash
162 ;
163 }
164
165 p->cap2 = inst2_prog_trig
166 | inst2_user_trig
167 | inst2_user_switch_trig
168 | inst2_bidi_scan
169 | inst2_has_scan_toll
170 | inst2_no_feedback
171 ;
172
173 if (p->m != NULL) {
174 i1proimp *m = (i1proimp *)p->m;
175 i1pro_state *s = &m->ms[m->mmode];
176 if (s->emiss) {
177 p->cap2 |= inst2_meas_disp_update;
178 p->cap2 |= inst2_emis_refr_meas;
179 }
180 }
181
182 p->cap3 = inst3_none;
183
184 return inst_ok;
185 }
186
187 /* Initialise the I1PRO */
188 /* return non-zero on an error, with inst error code */
189 static inst_code
i1pro_init_inst(inst * pp)190 i1pro_init_inst(inst *pp) {
191 i1pro *p = (i1pro *)pp;
192 i1pro_code ev = I1PRO_OK;
193
194 a1logd(p->log, 2, "i1pro_init_inst: called\n");
195
196 if (p->gotcoms == 0)
197 return i1pro_interp_code(p, I1PRO_INT_NO_COMS); /* Must establish coms before calling init */
198 if ((ev = i1pro_imp_init(p)) != I1PRO_OK) {
199 a1logd(p->log, 1, "i1pro_init_inst: failed with 0x%x\n",ev);
200 return i1pro_interp_code(p, ev);
201 }
202
203 p->inited = 1;
204 a1logd(p->log, 2, "i1pro_init_inst: instrument inited OK\n");
205
206 /* Now it's initied, we can get true capabilities */
207 i1pro_determine_capabilities(p);
208
209 return i1pro_interp_code(p, ev);
210 }
211
i1pro_get_serial_no(inst * pp)212 static char *i1pro_get_serial_no(inst *pp) {
213 i1pro *p = (i1pro *)pp;
214
215 if (!pp->gotcoms)
216 return "";
217 if (!pp->inited)
218 return "";
219
220 return i1pro_imp_get_serial_no(p);
221 }
222
223 /* Read a set of strips */
224 static inst_code
i1pro_read_strip(inst * pp,char * name,int npatch,char * pname,int sguide,double pwid,double gwid,double twid,ipatch * vals)225 i1pro_read_strip(
226 inst *pp,
227 char *name, /* Strip name (7 chars) */
228 int npatch, /* Number of patches in the pass */
229 char *pname, /* Pass name (3 chars) */
230 int sguide, /* Guide number */
231 double pwid, /* Patch length in mm (DTP41) */
232 double gwid, /* Gap length in mm (DTP41) */
233 double twid, /* Trailer length in mm (DTP41T) */
234 ipatch *vals) { /* Pointer to array of instrument patch values */
235 i1pro *p = (i1pro *)pp;
236 i1pro_code rv;
237
238 if (!p->gotcoms)
239 return inst_no_coms;
240 if (!p->inited)
241 return inst_no_init;
242
243 rv = i1pro_imp_measure(p, vals, npatch, instClamp);
244
245 return i1pro_interp_code(p, rv);
246 }
247
248 /* Read a single sample */
249 static inst_code
i1pro_read_sample(inst * pp,char * name,ipatch * val,instClamping clamp)250 i1pro_read_sample(
251 inst *pp,
252 char *name, /* Strip name (7 chars) */
253 ipatch *val, /* Pointer to instrument patch value */
254 instClamping clamp) { /* Clamp XYZ/Lab to be +ve */
255 i1pro *p = (i1pro *)pp;
256 i1pro_code rv;
257
258 if (!p->gotcoms)
259 return inst_no_coms;
260 if (!p->inited)
261 return inst_no_init;
262
263 rv = i1pro_imp_measure(p, val, 1, clamp);
264
265 return i1pro_interp_code(p, rv);
266 }
267
268 /* Read an emissive refresh rate */
269 static inst_code
i1pro_read_refrate(inst * pp,double * ref_rate)270 i1pro_read_refrate(
271 inst *pp,
272 double *ref_rate) {
273 i1pro *p = (i1pro *)pp;
274 i1pro_code rv;
275
276 if (!p->gotcoms)
277 return inst_no_coms;
278 if (!p->inited)
279 return inst_no_init;
280
281 if (ref_rate != NULL)
282 *ref_rate = 0.0;
283
284 rv = i1pro_imp_meas_refrate(p, ref_rate);
285
286
287
288 return i1pro_interp_code(p, rv);
289 }
290
291 /* Read the display update delay */
292 static inst_code
i1pro_meas_delay(inst * pp,int * pdispmsec,int * pinstmsec)293 i1pro_meas_delay(
294 inst *pp,
295 int *pdispmsec, /* Return display update delay in msec */
296 int *pinstmsec) { /* Return instrument reaction time in msec */
297 i1pro *p = (i1pro *)pp;
298 i1pro_code rv;
299
300 if (!p->gotcoms)
301 return inst_no_coms;
302 if (!p->inited)
303 return inst_no_init;
304
305 rv = i1pro_imp_meas_delay(p, pdispmsec, pinstmsec);
306
307 return i1pro_interp_code(p, rv);
308 }
309
310 /* Timestamp the white patch change during meas_delay() */
i1pro_white_change(inst * pp,int init)311 static inst_code i1pro_white_change(
312 inst *pp,
313 int init) {
314 i1pro *p = (i1pro *)pp;
315
316 return i1pro_imp_white_change(p, init);
317 }
318
319 /* Return needed and available inst_cal_type's */
i1pro_get_n_a_cals(inst * pp,inst_cal_type * pn_cals,inst_cal_type * pa_cals)320 static inst_code i1pro_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
321 i1pro *p = (i1pro *)pp;
322 i1pro_code rv;
323
324 rv = i1pro_imp_get_n_a_cals(p, pn_cals, pa_cals);
325 return i1pro_interp_code(p, rv);
326 }
327
328 /* Request an instrument calibration. */
i1pro_calibrate(inst * pp,inst_cal_type * calt,inst_cal_cond * calc,inst_calc_id_type * idtype,char id[CALIDLEN])329 static inst_code i1pro_calibrate(
330 inst *pp,
331 inst_cal_type *calt, /* Calibration type to do/remaining */
332 inst_cal_cond *calc, /* Current condition/desired condition */
333 inst_calc_id_type *idtype, /* Condition identifier type */
334 char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
335 ) {
336 i1pro *p = (i1pro *)pp;
337 i1pro_code rv;
338
339 if (!p->gotcoms)
340 return inst_no_coms;
341 if (!p->inited)
342 return inst_no_init;
343
344 rv = i1pro_imp_calibrate(p, calt, calc, idtype, id);
345 return i1pro_interp_code(p, rv);
346 }
347
348 /* Instrument specific error codes interpretation */
349 static char *
i1pro_interp_error(inst * pp,i1pro_code ec)350 i1pro_interp_error(inst *pp, i1pro_code ec) {
351 // i1pro *p = (i1pro *)pp;
352 ec &= inst_imask;
353 switch (ec) {
354 case I1PRO_INTERNAL_ERROR:
355 return "Internal software error";
356 case I1PRO_COMS_FAIL:
357 return "Communications failure";
358 case I1PRO_UNKNOWN_MODEL:
359 return "Not an i1 Pro";
360 case I1PRO_DATA_PARSE_ERROR:
361 return "Data from i1 Display didn't parse as expected";
362
363 case I1PRO_USER_ABORT:
364 return "User abort";
365
366 case I1PRO_USER_TRIG:
367 return "User trigger";
368
369 case I1PRO_UNSUPPORTED:
370 return "Unsupported function";
371 case I1PRO_CAL_SETUP:
372 return "Calibration retry with correct setup is needed";
373
374 case I1PRO_OK:
375 return "No device error";
376
377 case I1PRO_DATA_COUNT:
378 return "EEProm data count unexpectedly small";
379 case I1PRO_DATA_BUFSIZE:
380 return "EEProm data buffer too small";
381 case I1PRO_DATA_MAKE_KEY:
382 return "EEProm data creating key failed";
383 case I1PRO_DATA_MEMORY:
384 return "EEProm memory alloc failure";
385 case I1PRO_DATA_KEYNOTFOUND:
386 return "EEProm key value wasn't found";
387 case I1PRO_DATA_WRONGTYPE:
388 return "EEProm key is the wrong type";
389 case I1PRO_DATA_KEY_CORRUPT:
390 return "EEProm key table seems to be corrupted";
391 case I1PRO_DATA_KEY_COUNT_SMALL:
392 return "EEProm key table size is too small for expected number of keys";
393 case I1PRO_DATA_KEY_COUNT_LARGE:
394 return "EEProm key table size is too large for expected number of keys";
395 case I1PRO_DATA_KEY_UNKNOWN:
396 return "EEProm unknown key type";
397 case I1PRO_DATA_KEY_MEMRANGE:
398 return "EEProm key data is out of range of EEProm";
399 case I1PRO_DATA_KEY_ENDMARK:
400 return "EEProm end section marker was missing";
401
402 case I1PRO_HW_HIGHPOWERFAIL:
403 return "Failed to switch to high power mode";
404 case I1PRO_HW_EE_SIZE:
405 return "EEProm size is too small";
406 case I1PRO_HW_EE_SHORTREAD:
407 return "Read less bytes for EEProm read than expected";
408 case I1PRO_HW_EE_SHORTWRITE:
409 return "Wrote less bytes for EEProm write than expected";
410 case I1PRO_HW_ME_SHORTREAD:
411 return "Read less bytes for measurement read than expected";
412 case I1PRO_HW_ME_ODDREAD:
413 return "Read a number of bytes not a multiple of 256";
414 case I1PRO_HW_SW_SHORTREAD:
415 return "Read less bytes for Switch read than expected";
416 case I1PRO_HW_LED_SHORTWRITE:
417 return "Wrote fewer LED sequence bytes than expected";
418 case I1PRO_HW_UNEX_SPECPARMS:
419 return "Instrument has unexpected spectral parameters";
420 case I1PRO_HW_CALIBINFO:
421 return "Instrument calibration info is missing or corrupted";
422 case I1PRO_WL_TOOLOW:
423 return "Wavelength calibration reading is too low";
424 case I1PRO_WL_SHAPE:
425 return "Wavelength calibration reading shape is incorrect";
426 case I1PRO_WL_ERR2BIG:
427 return "Wavelength calibration correction is excessive";
428
429 case I1PRO_RD_DARKREADINCONS:
430 return "Dark calibration reading is inconsistent";
431 case I1PRO_RD_SENSORSATURATED:
432 return "Sensor is saturated";
433 case I1PRO_RD_DARKNOTVALID:
434 return "Dark reading is not valid (too light)";
435 case I1PRO_RD_NEEDS_CAL:
436 return "Mode needs calibration";
437 case I1PRO_RD_WHITEREADINCONS:
438 return "White calibration reading is inconsistent";
439 case I1PRO_RD_WHITEREFERROR:
440 return "White reference reading error";
441 case I1PRO_RD_LIGHTTOOLOW:
442 return "Light level is too low";
443 case I1PRO_RD_LIGHTTOOHIGH:
444 return "Light level is too high";
445 case I1PRO_RD_SHORTMEAS:
446 return "Reading is too short";
447 case I1PRO_RD_READINCONS:
448 return "Reading is inconsistent";
449 case I1PRO_RD_TRANSWHITERANGE:
450 return "Transmission white reference is out of range";
451 case I1PRO_RD_NOTENOUGHPATCHES:
452 return "Not enough patches";
453 case I1PRO_RD_TOOMANYPATCHES:
454 return "Too many patches";
455 case I1PRO_RD_NOTENOUGHSAMPLES:
456 return "Not enough samples per patch - Slow Down!";
457 case I1PRO_RD_NOFLASHES:
458 return "No flashes recognized";
459 case I1PRO_RD_NOAMBB4FLASHES:
460 return "No ambient found before first flash";
461 case I1PRO_RD_NOREFR_FOUND:
462 return "No refresh rate detected or failed to measure it";
463 case I1PRO_RD_NOTRANS_FOUND:
464 return "No delay calibration transition found";
465
466 case I1PRO_INT_NO_COMS:
467 return "Communications hasn't been established";
468 case I1PRO_INT_EETOOBIG:
469 return "Read of EEProm is too big (> 65536)";
470 case I1PRO_INT_ODDREADBUF:
471 return "Measurement read buffer is not a multiple of reading size";
472 case I1PRO_INT_SMALLREADBUF:
473 return "Measurement read buffer is too small for initial measurement";
474 case I1PRO_INT_INTTOOBIG:
475 return "Integration time is too big";
476 case I1PRO_INT_INTTOOSMALL:
477 return "Integration time is too small";
478 case I1PRO_INT_ILLEGALMODE:
479 return "Illegal measurement mode selected";
480 case I1PRO_INT_ZEROMEASURES:
481 return "Number of measurements requested is zero";
482 case I1PRO_INT_WRONGPATCHES:
483 return "Number of patches to match is wrong";
484 case I1PRO_INT_MEASBUFFTOOSMALL:
485 return "Measurement exceeded read buffer";
486 case I1PRO_INT_NOTIMPLEMENTED:
487 return "Support not implemented";
488 case I1PRO_INT_NOTCALIBRATED:
489 return "Unexpectedely invalid calibration";
490 case I1PRO_INT_NOINTERPDARK:
491 return "Need interpolated dark and don't have it";
492 case I1PRO_INT_THREADFAILED:
493 return "Creation of thread failed";
494 case I1PRO_INT_BUTTONTIMEOUT:
495 return "Button status read timed out";
496 case I1PRO_INT_CIECONVFAIL:
497 return "Creating spectral to CIE converted failed";
498 case I1PRO_INT_PREP_LOG_DATA:
499 return "Error in preparing log data";
500 case I1PRO_INT_MALLOC:
501 return "Error in allocating memory";
502 case I1PRO_INT_CREATE_EEPROM_STORE:
503 return "Error in creating EEProm store";
504 case I1PRO_INT_SAVE_SUBT_MODE:
505 return "Can't save calibration if in subt mode";
506 case I1PRO_INT_NO_CAL_TO_SAVE:
507 return "No calibration data to save";
508 case I1PRO_INT_EEPROM_DATA_MISSING:
509 return "EEProm data is missing";
510 case I1PRO_INT_NEW_RSPL_FAILED:
511 return "Creating RSPL object faild";
512 case I1PRO_INT_CAL_SAVE:
513 return "Unable to save calibration to file";
514 case I1PRO_INT_CAL_RESTORE:
515 return "Unable to restore calibration from file";
516 case I1PRO_INT_CAL_TOUCH:
517 return "Unable to update calibration file modification time";
518 case I1PRO_INT_ADARK_INVALID:
519 return "Adaptive dark calibration is invalid";
520 case I1PRO_INT_NO_HIGH_GAIN:
521 return "Rev E mode doesn't have a high gain mode";
522 case I1PRO_INT_ASSERT:
523 return "Assert fail";
524
525 default:
526 return "Unknown error code";
527 }
528 }
529
530
531 /* Convert a machine specific error code into an abstract inst code */
532 static inst_code
i1pro_interp_code(i1pro * p,i1pro_code ec)533 i1pro_interp_code(i1pro *p, i1pro_code ec) {
534
535 ec &= inst_imask;
536 switch (ec) {
537
538 case I1PRO_OK:
539 return inst_ok;
540
541 case I1PRO_INTERNAL_ERROR:
542 return inst_internal_error | ec;
543
544 case I1PRO_COMS_FAIL:
545 return inst_coms_fail | ec;
546
547 case I1PRO_UNKNOWN_MODEL:
548 return inst_unknown_model | ec;
549
550 case I1PRO_DATA_PARSE_ERROR:
551 return inst_protocol_error | ec;
552
553 case I1PRO_USER_ABORT:
554 return inst_user_abort;
555
556 case I1PRO_USER_TRIG:
557 return inst_user_trig;
558
559 case I1PRO_UNSUPPORTED:
560 return inst_unsupported | ec;
561
562 case I1PRO_CAL_SETUP:
563 return inst_cal_setup | ec;
564
565 case I1PRO_DATA_COUNT:
566 case I1PRO_DATA_BUFSIZE:
567 case I1PRO_DATA_MAKE_KEY:
568 case I1PRO_DATA_MEMORY:
569 case I1PRO_DATA_KEYNOTFOUND:
570 case I1PRO_DATA_WRONGTYPE:
571 case I1PRO_DATA_KEY_CORRUPT:
572 case I1PRO_DATA_KEY_COUNT_SMALL:
573 case I1PRO_DATA_KEY_COUNT_LARGE:
574 case I1PRO_DATA_KEY_UNKNOWN:
575 case I1PRO_DATA_KEY_MEMRANGE:
576 case I1PRO_DATA_KEY_ENDMARK:
577
578 case I1PRO_HW_HIGHPOWERFAIL:
579 case I1PRO_HW_EE_SIZE:
580 case I1PRO_HW_EE_SHORTREAD:
581 case I1PRO_HW_EE_SHORTWRITE:
582 case I1PRO_HW_ME_SHORTREAD:
583 case I1PRO_HW_ME_ODDREAD:
584 case I1PRO_HW_SW_SHORTREAD:
585 case I1PRO_HW_LED_SHORTWRITE:
586 case I1PRO_HW_UNEX_SPECPARMS:
587 case I1PRO_HW_CALIBINFO:
588 case I1PRO_WL_TOOLOW:
589 case I1PRO_WL_SHAPE:
590 case I1PRO_WL_ERR2BIG:
591 return inst_hardware_fail | ec;
592
593 case I1PRO_RD_DARKREADINCONS:
594 case I1PRO_RD_SENSORSATURATED:
595 case I1PRO_RD_DARKNOTVALID:
596 case I1PRO_RD_WHITEREADINCONS:
597 case I1PRO_RD_WHITEREFERROR:
598 case I1PRO_RD_LIGHTTOOLOW:
599 case I1PRO_RD_LIGHTTOOHIGH:
600 case I1PRO_RD_SHORTMEAS:
601 case I1PRO_RD_READINCONS:
602 case I1PRO_RD_TRANSWHITERANGE:
603 case I1PRO_RD_NOTENOUGHPATCHES:
604 case I1PRO_RD_TOOMANYPATCHES:
605 case I1PRO_RD_NOTENOUGHSAMPLES:
606 case I1PRO_RD_NOFLASHES:
607 case I1PRO_RD_NOAMBB4FLASHES:
608 case I1PRO_RD_NOREFR_FOUND:
609 case I1PRO_RD_NOTRANS_FOUND:
610 return inst_misread | ec;
611
612 case I1PRO_RD_NEEDS_CAL:
613 return inst_needs_cal | ec;
614
615 case I1PRO_INT_NO_COMS:
616 case I1PRO_INT_EETOOBIG:
617 case I1PRO_INT_ODDREADBUF:
618 case I1PRO_INT_SMALLREADBUF:
619 case I1PRO_INT_INTTOOBIG:
620 case I1PRO_INT_INTTOOSMALL:
621 case I1PRO_INT_ILLEGALMODE:
622 case I1PRO_INT_ZEROMEASURES:
623 case I1PRO_INT_MEASBUFFTOOSMALL:
624 case I1PRO_INT_NOTIMPLEMENTED:
625 case I1PRO_INT_NOTCALIBRATED:
626 case I1PRO_INT_NOINTERPDARK:
627 case I1PRO_INT_THREADFAILED:
628 case I1PRO_INT_BUTTONTIMEOUT:
629 case I1PRO_INT_CIECONVFAIL:
630 case I1PRO_INT_PREP_LOG_DATA:
631 case I1PRO_INT_MALLOC:
632 case I1PRO_INT_CREATE_EEPROM_STORE:
633 case I1PRO_INT_SAVE_SUBT_MODE:
634 case I1PRO_INT_NO_CAL_TO_SAVE:
635 case I1PRO_INT_EEPROM_DATA_MISSING:
636 case I1PRO_INT_NEW_RSPL_FAILED:
637 case I1PRO_INT_CAL_SAVE:
638 case I1PRO_INT_CAL_RESTORE:
639 case I1PRO_INT_CAL_TOUCH:
640 case I1PRO_INT_ADARK_INVALID:
641 case I1PRO_INT_NO_HIGH_GAIN:
642 case I1PRO_INT_ASSERT:
643 return inst_internal_error | ec;
644 }
645 return inst_other_error | ec;
646 }
647
648 /* Return the instrument capabilities */
i1pro_capabilities(inst * pp,inst_mode * pcap1,inst2_capability * pcap2,inst3_capability * pcap3)649 static void i1pro_capabilities(inst *pp,
650 inst_mode *pcap1,
651 inst2_capability *pcap2,
652 inst3_capability *pcap3) {
653 i1pro *p = (i1pro *)pp;
654
655 if (pcap1 != NULL)
656 *pcap1 = p->cap;
657 if (pcap2 != NULL)
658 *pcap2 = p->cap2;
659 if (pcap3 != NULL)
660 *pcap3 = p->cap3;
661 }
662
663 /* Return the corresponding i1pro measurement mode, */
664 /* or i1p_no_modes if invalid */
i1pro_convert_mode(i1pro * p,inst_mode m)665 static i1p_mode i1pro_convert_mode(i1pro *p, inst_mode m) {
666 i1p_mode mmode = 0; /* Instrument measurement mode */
667
668 /* Simple test */
669 if (m & ~p->cap) {
670 return i1p_no_modes;
671 }
672
673 if (IMODETST(m, inst_mode_ref_spot)) {
674 mmode = i1p_refl_spot;
675 } else if (IMODETST(m, inst_mode_ref_strip)) {
676 mmode = i1p_refl_scan;
677 } else if (IMODETST(m, inst_mode_trans_spot)) {
678 mmode = i1p_trans_spot;
679 } else if (IMODETST(m, inst_mode_trans_strip)) {
680 mmode = i1p_trans_scan;
681 } else if (IMODETST(m, inst_mode_emis_spot)
682 || IMODETST(m, inst_mode_emis_tele)) {
683 if (IMODETST(m, inst_mode_emis_nonadaptive))
684 mmode = i1p_emiss_spot_na;
685 else
686 mmode = i1p_emiss_spot;
687 } else if (IMODETST(m, inst_mode_emis_strip)) {
688 mmode = i1p_emiss_scan;
689 } else if (IMODETST(m, inst_mode_emis_ambient)
690 && (p->cap & inst_mode_emis_ambient)) {
691 mmode = i1p_amb_spot;
692 } else if (IMODETST(m, inst_mode_emis_ambient_flash)
693 && (p->cap & inst_mode_emis_ambient_flash)) {
694 mmode = i1p_amb_flash;
695 } else {
696 return i1p_no_modes;
697 }
698
699 return mmode;
700 }
701
702 /* Check device measurement mode */
i1pro_check_mode(inst * pp,inst_mode m)703 static inst_code i1pro_check_mode(inst *pp, inst_mode m) {
704 i1pro *p = (i1pro *)pp;
705 i1p_mode mmode = 0; /* Instrument measurement mode */
706
707 if (!p->gotcoms)
708 return inst_no_coms;
709 if (!p->inited)
710 return inst_no_init;
711
712 if (i1pro_convert_mode(p, m) == i1p_no_modes)
713 return inst_unsupported;
714
715 return inst_ok;
716 }
717
718 /* Set device measurement mode */
i1pro_set_mode(inst * pp,inst_mode m)719 static inst_code i1pro_set_mode(inst *pp, inst_mode m) {
720 i1pro *p = (i1pro *)pp;
721 i1p_mode mmode; /* Instrument measurement mode */
722 inst_code rv;
723
724 if (!p->gotcoms)
725 return inst_no_coms;
726 if (!p->inited)
727 return inst_no_init;
728
729 if ((mmode = i1pro_convert_mode(p, m)) == i1p_no_modes)
730 return inst_unsupported;
731
732 if ((rv = i1pro_interp_code(p, i1pro_imp_set_mode(p, mmode, m))) != inst_ok)
733 return rv;
734
735 i1pro_determine_capabilities(p);
736
737 return inst_ok;
738 }
739
740 /*
741 * set or reset an optional mode
742 *
743 * Some options talk to the instrument, and these will
744 * error if it hasn't been initialised.
745 */
746 static inst_code
i1pro_get_set_opt(inst * pp,inst_opt_type m,...)747 i1pro_get_set_opt(inst *pp, inst_opt_type m, ...) {
748 i1pro *p = (i1pro *)pp;
749
750 if (m == inst_opt_initcalib) { /* default */
751 i1pro_set_noinitcalib(p, 0, 0);
752 return inst_ok;
753
754 } else if (m == inst_opt_noinitcalib) {
755 va_list args;
756 int losecs = 0;
757
758 va_start(args, m);
759 losecs = va_arg(args, int);
760 va_end(args);
761
762 i1pro_set_noinitcalib(p, 1, losecs);
763 return inst_ok;
764
765 /* Record the trigger mode */
766 } else if (m == inst_opt_trig_prog
767 || m == inst_opt_trig_user
768 || m == inst_opt_trig_user_switch) {
769 i1pro_set_trig(p, m);
770 return inst_ok;
771 }
772
773 if (m == inst_opt_scan_toll) {
774 va_list args;
775 double toll_ratio = 1.0;
776
777 va_start(args, m);
778 toll_ratio = va_arg(args, double);
779 va_end(args);
780 return i1pro_interp_code(p, i1pro_set_scan_toll(p, toll_ratio));
781 }
782
783 if (!p->gotcoms)
784 return inst_no_coms;
785 if (!p->inited)
786 return inst_no_init;
787
788 /* Not sure if this can be set before init */
789 if (m == inst_opt_highres) {
790 return i1pro_interp_code(p, i1pro_set_highres(p));
791 } else if (m == inst_opt_stdres) {
792 return i1pro_interp_code(p, i1pro_set_stdres(p));
793 }
794
795 /* Return the filter */
796 if (m == inst_stat_get_filter) {
797 i1proimp *imp = (i1proimp *)p->m;
798 inst_opt_filter *filt;
799 va_list args;
800
801 va_start(args, m);
802 filt = va_arg(args, inst_opt_filter *);
803 va_end(args);
804
805 *filt = inst_opt_filter_none;
806
807 if (imp->physfilt == 0x82)
808 *filt = inst_opt_filter_UVCut;
809
810 return inst_ok;
811 }
812
813 /* Set xcalstd */
814 if (m == inst_opt_set_xcalstd) {
815 i1proimp *imp = (i1proimp *)p->m;
816 xcalstd standard;
817 va_list args;
818
819 va_start(args, m);
820 standard = va_arg(args, xcalstd);
821 va_end(args);
822
823 imp->target_calstd = standard;
824
825 return inst_ok;
826 }
827
828 /* Get the current effective xcalstd */
829 if (m == inst_opt_get_xcalstd) {
830 i1proimp *imp = (i1proimp *)p->m;
831 xcalstd *standard;
832 va_list args;
833
834 va_start(args, m);
835 standard = va_arg(args, xcalstd *);
836 va_end(args);
837
838 if (imp->target_calstd == xcalstd_native)
839 *standard = imp->native_calstd; /* If not overridden */
840 else
841 *standard = imp->target_calstd; /* Overidden std. */
842
843 return inst_ok;
844 }
845
846 /* Return the white calibration tile spectrum */
847 /* (We always return the normal rez. reference values) */
848 if (m == inst_opt_get_cal_tile_sp) {
849 i1proimp *imp = (i1proimp *)p->m;
850 xspect *sp;
851 inst_code rv;
852 va_list args;
853 int i;
854
855 va_start(args, m);
856 sp = va_arg(args, xspect *);
857 va_end(args);
858
859 if (imp->white_ref[0] == NULL)
860 return inst_no_init;
861
862 sp->spec_n = imp->nwav[0];
863 sp->spec_wl_short = imp->wl_short[0];
864 sp->spec_wl_long = imp->wl_long[0];
865 sp->norm = 100.0;
866
867 for (i = 0; i < sp->spec_n; i++)
868 sp->spec[i] = imp->white_ref[0][i] * 100.0;
869
870 return inst_ok;
871 }
872
873 /* Lamp drift remediation */
874 if (m == inst_opt_lamp_remediate) {
875 i1pro_code ev;
876 va_list args;
877 double seconds;
878
879 va_start(args, m);
880 seconds = va_arg(args, double);
881 va_end(args);
882
883 ev = i1pro_imp_lamp_fix(p, seconds);
884
885 return i1pro_interp_code(p, ev);
886 }
887
888 /* Use default implementation of other inst_opt_type's */
889 {
890 inst_code rv;
891 va_list args;
892
893 va_start(args, m);
894 rv = inst_get_set_opt_def(pp, m, args);
895 va_end(args);
896
897 return rv;
898 }
899 }
900
901 /* Destroy ourselves */
902 static void
i1pro_del(inst * pp)903 i1pro_del(inst *pp) {
904 i1pro *p = (i1pro *)pp;
905
906 del_i1proimp(p);
907 if (p->icom != NULL)
908 p->icom->del(p->icom);
909 p->vdel(pp);
910 free(p);
911 }
912
913 /* Constructor */
new_i1pro(icoms * icom,instType itype)914 extern i1pro *new_i1pro(icoms *icom, instType itype) {
915 i1pro *p;
916 int rv;
917 if ((p = (i1pro *)calloc(sizeof(i1pro),1)) == NULL) {
918 a1loge(icom->log, 1, "new_i1pro: malloc failed!\n");
919 return NULL;
920 }
921
922 p->log = new_a1log_d(icom->log);
923
924 /* Inst methods */
925 p->init_coms = i1pro_init_coms;
926 p->init_inst = i1pro_init_inst;
927 p->capabilities = i1pro_capabilities;
928 p->get_serial_no = i1pro_get_serial_no;
929 p->check_mode = i1pro_check_mode;
930 p->set_mode = i1pro_set_mode;
931 p->get_set_opt = i1pro_get_set_opt;
932 p->read_strip = i1pro_read_strip;
933 p->read_sample = i1pro_read_sample;
934 p->read_refrate = i1pro_read_refrate;
935 p->get_n_a_cals = i1pro_get_n_a_cals;
936 p->calibrate = i1pro_calibrate;
937 p->meas_delay = i1pro_meas_delay;
938 p->white_change = i1pro_white_change;
939 p->interp_error = i1pro_interp_error;
940 p->del = i1pro_del;
941
942 p->icom = icom;
943 p->itype = itype;
944
945 i1pro_determine_capabilities(p);
946
947 if ((rv = add_i1proimp(p)) != I1PRO_OK) {
948 free(p);
949 a1loge(icom->log, 1, "new_i1pro: error %d creating i1proimp\n",rv);
950 return NULL;
951 }
952
953 return p;
954 }
955
956