1 #ifndef I1PRO_IMP_H
2 
3 /*
4  * Argyll Color Correction System
5  *
6  * Gretag i1Pro implementation defines
7  */
8 
9 /*
10  * Author: Graeme W. Gill
11  * Date:   20/12/2006
12  *
13  * Copyright 2006 - 2013 Graeme W. Gill
14  * All rights reserved.
15  *
16  * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
17  * see the License2.txt file for licencing details.
18  */
19 
20 #ifdef __cplusplus
21 	extern "C" {
22 #endif
23 
24 /*
25    If you make use of the instrument driver code here, please note
26    that it is the author(s) of the code who take responsibility
27    for its operation. Any problems or queries regarding driving
28    instruments with the Argyll drivers, should be directed to
29    the Argyll's author(s), and not to any other party.
30 
31    If there is some instrument feature or function that you
32    would like supported here, it is recommended that you
33    contact Argyll's author(s) first, rather than attempt to
34    modify the software yourself, if you don't have firm knowledge
35    of the instrument communicate protocols. There is a chance
36    that an instrument could be damaged by an incautious command
37    sequence, and the instrument companies generally cannot and
38    will not support developers that they have not qualified
39    and agreed to support.
40  */
41 
42 /* Implementation resources for i1pro driver */
43 
44 /* -------------------------------------------------- */
45 /* Implementation class */
46 
47 typedef int i1pro_code;		/* Type to use for error codes */
48 
49 /* I1PRO mode state. This is implementation data that */
50 /* depends on the mode the instrument is in. */
51 /* Each mode has a separate calibration, and configured instrument state. */
52 
53 typedef enum {
54 	i1p_refl_spot      = 0,
55 	i1p_refl_scan      = 1,
56 	i1p_emiss_spot_na  = 2,
57 	i1p_emiss_spot     = 3,
58 	i1p_emiss_scan     = 4,
59 	i1p_amb_spot       = 5,
60 	i1p_amb_flash      = 6,
61 	i1p_trans_spot     = 7,
62 	i1p_trans_scan     = 8,
63 	i1p_no_modes       = 9		/* Number of modes */
64 } i1p_mode;
65 
66 struct _i1pro_state {
67 	i1p_mode mode;		/* Mode number */
68 
69 	/* Just one of the following 3 must always be set */
70 	int emiss;			/* flag - Emissive mode */
71 	int trans;			/* flag - Transmissive mode */
72 	int reflective;		/* flag - Reflective mode */
73 
74 	/* The following can be added to emiss */
75 	int ambient;		/* flag - Ambient mode */
76 
77 	/* The following can be added to any of the 3: */
78 	int scan;			/* flag - Scanning mode */
79 	int adaptive;		/* flag - adaptive mode */
80 
81 	/* The following can be added to scan: */
82 	int flash;			/* flag - Flash detection from scan mode */
83 
84 	/* Configuration & state information */
85 	double targoscale;	/* Optimal reading scale factor <= 1.0 */
86 						/* Would determine scan sample rate, except we're not doing it that way! */
87 	double targmaxitime;/* maximum integration time to aim for  (ie. 2.0 sec) */
88 	double targoscale2;/* Proportion of targoscale allowed to meed targmaxitime */
89 	int gainmode;		/* Gain mode, 0 = normal, 1 = high */
90 	double inttime;		/* Integration time */
91 	double lamptime;	/* Lamp turn on time */
92 
93 	double dadaptime;	/* Target adaptive dark read time - sets number of readings */
94 	double wadaptime;	/* Target adaptive white/sample read time - sets number of readings */
95 
96 	double dcaltime;	/* Target dark calibration time - sets number of readings */
97 	double wcaltime;	/* Target white calibration time - sets number of readings */
98 
99 	double dreadtime;	/* Target dark on-the-fly cal time - sets number of readings */
100 	double wreadtime;	/* Target white/sample reading time - sets number of readings */
101 
102 	double maxscantime;	/* Maximum scan time sets buffer size allocated */
103 
104 	double min_wl;		/* Minimum wavelegth to report for this mode */
105 
106 	/* calibration information for this mode */
107 	int wl_valid;			/* wavelength calibration factor valid */
108 	time_t wldate;			/* Date/time of last wavelength calibration */
109 	double wl_led_off;		/* Wavelength LED reference spectrum current offset */
110 
111 	int dark_valid;			/* dark calibration factor valid */
112 	time_t ddate;			/* Date/time of last dark calibration */
113 	double dark_int_time;	/* Integration time used for dark data */
114 	double *dark_data;		/* [-1 nraw] of dark level to subtract. Note that the dark value */
115 							/* depends on integration time. */
116 	int dark_gain_mode;		/* Gain mode used for dark data */
117 
118 	int cal_valid;			/* calibration factor valid */
119 	time_t cfdate;			/* Date/time of last cal factor calibration */
120 	double *cal_factor[2];	/* [low res, high res][nwav] calibration scale factor for this mode */
121 	double *white_data;		/* [-1 nraw] linear absolute dark subtracted white data */
122 							/*        used to compute cal_factor */
123 
124 	/* Adaptive emission/transparency black data */
125 	int idark_valid;		/* idark calibration factors valid */
126 	time_t iddate;			/* Date/time of last dark idark calibration */
127 	double idark_int_time[4];
128 	double **idark_data;	/* [4][-1 nraw] of dark level for inttime/gains of : */
129 							/* 0.01 norm, 4.0 norm, 0.01 high, 2.0 high */
130 
131 	int want_calib;			/* Want White calibration at start */
132 	int want_dcalib;		/* Want Dark Calibration at start */
133 
134 	/* Display mode calibration state (emmis && !scan && !adaptive) */
135 	int    dispswap;		/* 0 = default time, 1 = dark_int_time2, 2 = dark_int_time3 */
136 	                        /* 3 = dark_int_time4 */
137 	double done_dintsel;	/* A display integration time selection has been done */
138 	time_t diseldate;		/* Date/time of last display integration time selection */
139 	double dcaltime2;		/* Target dark calibration time - sets number of readings */
140 	double dark_int_time2;	/* Integration time used for dark data 2 */
141 	double *dark_data2;		/* [-1 nraw] of dark level to subtract for dark_int_time2. */
142 	double dcaltime3;		/* Target dark calibration time - sets number of readings */
143 	double dark_int_time3;	/* Integration time used for dark data 3 */
144 	double *dark_data3;		/* [-1 nraw] of dark level to subtract for dark_int_time3. */
145 	double dcaltime4;		/* Target dark calibration time - sets number of readings */
146 	double dark_int_time4;	/* Integration time used for dark data 4 */
147 	double *dark_data4;		/* [-1 nraw] of dark level to subtract for dark_int_time4. */
148 
149 }; typedef struct _i1pro_state i1pro_state;
150 
151 /* Pointers to the three tables that allow a raw to wave filter conversion */
152 typedef struct {
153 	int *index;			/* [nwav] Matrix CCD sample starting index for each out wavelength */
154 	int *nocoef; 		/* [nwav] Number of matrix cooeficients for each out wavelength */
155 	double *coef;		/* [nwav * mtx_nocoef] Matrix cooeficients to compute each wavelength */
156 } i1pro_r2wtab;
157 
158 /* RevE capability bits */
159 #define I1PRO_CAP2_AMBIENT		0x01		/* Has ambient measurement capability */
160 #define I1PRO_CAP2_WL_LED		0x02		/* Has wavelenght LED */
161 #define I1PRO_CAP2_UV_LED		0x04		/* Has Ultra Violet LED */
162 #define I1PRO_CAP2_ZEB_RUL		0x08		/* Has zerbra ruler sensor */
163 #define I1PRO_CAP2_IND_LED		0x10		/* Has indicator LEDs */
164 #define I1PRO_CAP2_UV_FILT		0x20		/* Has Ultra Violet Filter */
165 
166 /* I1PRO implementation class */
167 struct _i1proimp {
168 	i1pro *p;
169 
170 	/* Misc. and top level */
171 	struct _i1data *data;		/* EEProm data container */
172 	athread *th;				/* Switch monitoring thread (NULL if not used) */
173 	volatile int switch_count;	/* Incremented in thread */
174 	volatile int hide_switch;	/* Set to supress switch event during read */
175 	usb_cancelt sw_cancel;		/* Token to allow cancelling switch I/O */
176 	volatile int th_term;		/* Terminate thread on next return */
177 	volatile int th_termed;		/* Thread has terminated */
178 	usb_cancelt rd_sync;		/* Token to allow meas. read to be synchronized */
179 	inst_opt_type trig;			/* Reading trigger mode */
180 	int noinitcalib;			/* Disable initial calibration if not essential */
181 	int highres;				/* High resolution mode */
182 	int hr_inited;				/* High resolution has been initialized */
183 
184 	/* Current settings */
185 	i1p_mode mmode;					/* Current measurement mode selected */
186 	i1pro_state ms[i1p_no_modes];	/* Mode state */
187 	int spec_en;				/* NZ to enable reporting of spectral data */
188 	int uv_en;					/* NZ to do UV reflective measurement */
189 								/* ~~ change this to uv_mode of none, uv, strip1, 2pass */
190 
191 	xcalstd native_calstd;		/* Instrument native calibration standard */
192 	xcalstd target_calstd;		/* Returned calibration standard */
193 
194 	double intclkp;				/* Integration clock period (typically 68 usec) */
195 	int subclkdiv;				/* Sub clock divider ratio */
196 	int subtmode;				/* Reading 127 subtract mode (version 301 or greater) */
197 
198 	/* Current state of hardware, to avoid uncessary operations */
199 	double c_inttime;			/* Integration time */
200 	double l_inttime;			/* Last Integration time (for Rev A+/B quirk fix) */
201 	double c_lamptime;			/* Lamp turn on time */
202 	int c_mcmode;				/* special clock mode we're in (if rev >= 301) */
203 	int c_intclocks;			/* Number of integration clocks (set using setmeasparams() */
204 	int c_lampclocks;			/* Number of integration clocks (set using setmeasparams() */
205 	int c_nummeas;				/* Number of measurements (set using setmeasparams() */
206 	int c_measmodeflags;		/* Measurement mode flags (set using setmeasparams() */
207 	int c_measmodeflags2;		/* Measurement mode flags Rev E (set using setmeasparams() */
208 	unsigned int slamponoff;	/* The second last time the lamp was switched from on to off */
209 	unsigned int llampoffon;	/* The last time the lamp was switched from off to on, in msec */
210 	unsigned int llamponoff;	/* The last time the lamp was switched from on to off, in msec */
211 
212 
213 	/* Values read from GetMisc() */
214 	int fwrev;					/* int - Firmware revision number, from getmisc() */
215 								/* Used for internal switching ?? */
216 								/* 101 = Rev A, 202 = Rev A update, 302 = Rev B, */
217 								/* 502, 505, 631 = Rev D, 629 = Rev E (i1pro2) */
218 
219 	int cpldrev;				/* int - CPLD revision number in EEProm */
220 								/* Not used internaly ???? */
221 								/* 101 = Rev A, 2 = Rev A update, 301 = Rev B, 999 = Rev D */
222 
223 	unsigned char chipid[8];	/* HW serial number - Rev E */
224 
225 	int eesize;					/* EEProm size in bytes */
226 	int maxpve;					/* Maximum +ve value of Sensor Data + 1 */
227 	int powmode;				/* Power mode status, 0 = high, 8 = low */
228 
229 	/* Values from i1pro2_getmeaschar() */
230 	double intclkp2;			/* Rev E Integration clock period (typically 36 usec) */
231 	int subclkdiv2;				/* Sub clock divider ratio (typically 136) */
232 
233 	/* Values read from GetMeasureParameters() - are these needed ? */
234 	int r_intclocks;			/* Number of integration clocks (read from instrument) */
235 	int r_lampclocks;			/* Number of lamp turn on sub-clocks (read from instrument) */
236 	int r_nummeas;				/* Number of measurements (read from instrument) */
237 	int r_measmodeflags;		/* Measurement mode flags (read from instrument) */
238 
239 
240 	/* Information about the instrument from the EEprom */
241 	int serno;				/* serial number */
242 	char sserno[14];		/* serial number as string */
243 	int dom;				/* Date of manufacture DDMMYYYY ? */
244 	int capabilities;		/* Capabilities flag */
245 							/* Ambient capability if val & 0x6000 != 0 */
246 	int physfilt;			/* int - physical filter */
247 							/* 0x80 == no filter */
248 							/* 0x81 == emission only ?? */
249 							/* 0x82 == UV filter */
250 	int capabilities2;		/* Rev E capabilities - set #defines above */
251 							/* Also set for RevA-D */
252 
253 	/* Underlying calibration information */
254 	int nsen;				/* Raw + extra sample bands read = 128 for i1pro, 136 for Rev E */
255 							/* Rev <= D have exactly 128 */
256 							/* Rev E has 134, of which 128 are measurements. */
257 							/* 5 are skipped at the start, and 1 at the end */
258 							/* The first 4 are used as a dark consistency check. */
259 							/* ie. 4 + 1 + 128 + 1 */
260 	int nraw;				/* Raw sample bands stored = 128 (Must be signed!) */
261 	unsigned int nwav[2];	/* [low res, high res] cooked spectrum bands stored, ie = 36 */
262 	double wl_short[2];		/* [low res, high res] cooked spectrum bands short wavelength, ie 380 */
263 	double wl_long[2];		/* [low res, high res] cooked spectrum bands short wavelength, ie 730 */
264 
265 	unsigned int nlin0;		/* Number in array */
266 	double *lin0;			/* Array of linearisation polinomial factors, normal gain. */
267 
268 	unsigned int nlin1;		/* Number in array */
269 	double *lin1;			/* Array of linearisation polinomial factors, high gain. */
270 
271 	double min_int_time;	/* Minimum integration time (secs) */
272 	double max_int_time;	/* Maximum integration time (secs) */
273 
274 	i1pro_r2wtab mtx[2][2];	/* Raw to wav filters [normal res, high res][emis/trans, reflective] */
275 							/* These are all pointers to tables allocated below */
276 
277 	i1pro_r2wtab mtx_o;		/* Underlying original filters from EEProm calibration info. */
278 	i1pro_r2wtab mtx_c[2][2];	/* Underlying allocated for RevE wavelength and hi-res calibrated */
279 
280 	double *white_ref[2];	/* [low res, high res][nwav] White cal tile reflectance values */
281 	double *emis_coef[2];	/* [low res, high res][nwav] Emission cal coefficients */
282 	double *amb_coef[2];	/* [low res, high res][nwav] Ambient light cal values */
283 							/* (compound with Emission), NULL if ambient not supported */
284 	int emis_hr_cal;		/* NZ if emis_coef[1] has been fine calibrated using reflective cal. */
285 
286 	double **straylight[2];		/* [nwav][nwav] Stray light convolution matrix (Rev E) */
287 
288 	double highgain;		/* High gain mode gain */
289 	double scan_toll_ratio;	/* Modifier of scan tollerance */
290 
291 	int sens_target;		/* sensor optimal target value */
292 	int sens_dark;			/* sensor dark reference threshold */
293 	int sens_sat0;			/* Normal gain sensor saturated threshold */
294 	int sens_sat1;			/* High gain sensor saturated threshold */
295 
296 	/* RevA-D alternative to RevE calibration information */
297 	rspl *raw2wav;          /* Lookup from CCD index to wavelength, NULL until highres inited */
298 
299 	/* Rev E calibration information */
300 	double wl_cal_inttime;	/* Wavelength calibration integration time */
301 	double wl_cal_min_level;	/* Normalized wavelength calibration minumum peak level */
302 	double wl_cal_fwhm;		/* Wavelength cal expected FWHM (nm) */
303 	double wl_cal_fwhm_tol;	/* Wavelength cal expected FWHM tollerance (nm) */
304 	double *wl_led_spec;	/* Wavelength LED reference spectrum */
305 	unsigned int wl_led_count;	/* Wavelength LED reference spectrum number of entries */
306 	double wl_led_ref_off;	/* Wavelength LED reference spectrum ref. offset */
307 	double wl_err_max;		/* Wavelength error maximum value (ie. 5.0) */
308 	double *wlpoly1, *wlpoly2;	/* CCD bin to wavelength polinomial equations */
309 							/* for reflective and emissive/transmissuce modes respectively. */
310 
311 	/* log variables */
312 	int meascount;			/* Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
313 							/* but not the pre-Remission dark calibration. */
314 	time_t caldate;			/* Remspotcal last calibration date */
315 	int calcount;			/* Remission spot measure count at last Remspotcal. */
316 	double rpinttime;		/* Last remision spot reading integration time */
317 	int rpcount;			/* Remission spot measure count */
318 	int acount;				/* Remission scan measure count (Or all scan ??) */
319 	double lampage;			/* Total lamp usage time in seconds (??) */
320 
321 	/* Trigger houskeeping & diagnostics */
322 	int transwarn;			/* Transmission calibration warning state */
323 	int lo_secs;			/* Seconds since last opened (from calibration file mod time) */
324 	int msec;				/* msec_time() at creation */
325 	athread *trig_thread;	/* Delayed trigger thread */
326 	int trig_delay;			/* Trigger delay in msec */
327 	int tr_t1, tr_t2, tr_t3, tr_t4, tr_t5, tr_t6, tr_t7;	/* Trigger/read timing diagnostics */
328 							/* 1->2 = time to execute trigger */
329 							/* 2->3 = time to between end trigger and start of first read */
330 							/* 3->4 = time to exectute first read */
331 							/* 6->5 = time between end of second last read and start of last read */
332 	int trig_se;			/* Delayed trigger icoms error */
333 	i1pro_code trig_rv;		/* Delayed trigger result */
334 
335 	volatile double whitestamp;	/* meas_delay() white timestamp */
336 	volatile double trigstamp;	/* meas_delay() trigger timestamp */
337 
338 }; typedef struct _i1proimp i1proimp;
339 
340 /* Add an implementation structure */
341 i1pro_code add_i1proimp(i1pro *p);
342 
343 /* Destroy implementation structure */
344 void del_i1proimp(i1pro *p);
345 
346 /* ============================================================ */
347 /* Error codes returned from i1pro_imp */
348 
349 /* Note: update i1pro_interp_error() and i1pro_interp_code() in i1pro.c */
350 /* if anything of these #defines are added or subtracted */
351 
352 /* Fake Error codes */
353 #define I1PRO_INTERNAL_ERROR			0x71		/* Internal software error */
354 #define I1PRO_COMS_FAIL					0x72		/* Communication failure */
355 #define I1PRO_UNKNOWN_MODEL				0x73		/* Not an i1pro */
356 #define I1PRO_DATA_PARSE_ERROR  		0x74		/* Read data parsing error */
357 
358 #define I1PRO_USER_ABORT		    	0x75		/* uicallback returned abort */
359 #define I1PRO_USER_TRIG 		    	0x76		/* uicallback retuned trigger */
360 
361 #define I1PRO_UNSUPPORTED		   		0x79		/* Unsupported function */
362 #define I1PRO_CAL_SETUP                 0x7A		/* Cal. retry with correct setup is needed */
363 #define I1PRO_RD_TRANSWHITEWARN         0x7B		/* Transmission white ref wl are low */
364 
365 /* Real error code */
366 #define I1PRO_OK   						0x00
367 
368 #define I1PRO_DATA_COUNT			    0x01		/* count unexpectedly small */
369 #define I1PRO_DATA_BUFSIZE			    0x02		/* buffer too small */
370 #define I1PRO_DATA_MAKE_KEY				0x03		/* creating key failed */
371 #define I1PRO_DATA_MEMORY 				0x04		/* memory alloc failure */
372 #define I1PRO_DATA_KEYNOTFOUND			0x05		/* a key value wasn't found */
373 #define I1PRO_DATA_WRONGTYPE			0x06		/* a key is the wrong type */
374 #define I1PRO_DATA_KEY_CORRUPT		    0x07		/* key table seems to be corrupted */
375 #define I1PRO_DATA_KEY_COUNT_SMALL	    0x08		/* key table count is too small */
376 #define I1PRO_DATA_KEY_COUNT_LARGE	    0x09		/* key table count is too big */
377 #define I1PRO_DATA_KEY_UNKNOWN		    0x0a		/* unknown key type */
378 #define I1PRO_DATA_KEY_MEMRANGE		    0x0b		/* key data is out of range of EEProm */
379 #define I1PRO_DATA_KEY_ENDMARK		    0x0c		/* And end section marker was missing */
380 
381 /* HW errors */
382 #define I1PRO_HW_HIGHPOWERFAIL			0x10		/* Switch to high power mode failed */
383 #define I1PRO_HW_EE_SIZE		        0x11		/* EEProm is too small */
384 #define I1PRO_HW_EE_SHORTREAD		    0x12		/* Read fewer EEProm bytes than expected */
385 #define I1PRO_HW_EE_SHORTWRITE		    0x13		/* Read fewer EEProm bytes than expected */
386 #define I1PRO_HW_ME_SHORTREAD		    0x14		/* Read measurement bytes than expected */
387 #define I1PRO_HW_ME_ODDREAD			    0x15		/* Read measurement bytes was not mult 256 */
388 #define I1PRO_HW_SW_SHORTREAD           0x16		/* Read less bytes for Switch read than expected */
389 #define I1PRO_HW_LED_SHORTWRITE         0x17		/* Wrote fewer LED sequence bytes than expected */
390 #define I1PRO_HW_UNEX_SPECPARMS		    0x18		/* Unexpacted spectral parameter values */
391 #define I1PRO_HW_CALIBINFO			    0x19		/* calibration info is missing or corrupted */
392 #define I1PRO_WL_TOOLOW                 0x1A		/* WL calibration measurement too low */
393 #define I1PRO_WL_SHAPE                  0x1B		/* WL calibration measurement shape is wrong */
394 #define I1PRO_WL_ERR2BIG                0x1C		/* WL calibration correction is too big */
395 
396 /* Sample read operation errors */
397 #define I1PRO_RD_DARKREADINCONS		    0x30		/* Dark calibration reading inconsistent */
398 #define I1PRO_RD_SENSORSATURATED	    0x31		/* Sensor is saturated */
399 #define I1PRO_RD_DARKNOTVALID   	    0x32		/* Dark reading is not valid (too light) */
400 #define I1PRO_RD_NEEDS_CAL 		        0x33		/* Mode needs calibration */
401 #define I1PRO_RD_WHITEREADINCONS        0x34		/* White reference readings are inconsistent */
402 #define I1PRO_RD_WHITEREFERROR 	        0x35		/* White reference reading error */
403 #define I1PRO_RD_LIGHTTOOLOW 	        0x36		/* Light level is too low */
404 #define I1PRO_RD_LIGHTTOOHIGH 	        0x37		/* Light level is too high */
405 #define I1PRO_RD_SHORTMEAS              0x38		/* Measurment was too short */
406 #define I1PRO_RD_READINCONS             0x39		/* Reading is inconsistent */
407 #define I1PRO_RD_TRANSWHITERANGE        0x3A		/* Transmission white reference is out of range */
408 #define I1PRO_RD_NOTENOUGHPATCHES       0x3B		/* Not enough patches */
409 #define I1PRO_RD_TOOMANYPATCHES         0x3C		/* Too many patches */
410 #define I1PRO_RD_NOTENOUGHSAMPLES       0x3D		/* Not enough samples per patch */
411 #define I1PRO_RD_NOFLASHES              0x3E		/* No flashes recognized */
412 #define I1PRO_RD_NOAMBB4FLASHES         0x3F		/* No ambient before flashes found */
413 #define I1PRO_RD_NOREFR_FOUND           0x40		/* Unable to measure refresh rate */
414 #define I1PRO_RD_NOTRANS_FOUND          0x41		/* Unable to measure delay transition */
415 
416 /* Internal errors */
417 #define I1PRO_INT_NO_COMS 		        0x50
418 #define I1PRO_INT_EETOOBIG 		        0x51		/* EEProm read size is too big */
419 #define I1PRO_INT_ODDREADBUF 	        0x52		/* Measurment read buffer is not mult 256 */
420 #define I1PRO_INT_SMALLREADBUF 	        0x53		/* Measurment read buffer too small */
421 #define I1PRO_INT_INTTOOBIG				0x55		/* Integration time is too big */
422 #define I1PRO_INT_INTTOOSMALL			0x56		/* Integration time is too small */
423 #define I1PRO_INT_ILLEGALMODE			0x57		/* Illegal measurement mode selected */
424 #define I1PRO_INT_WRONGMODE  			0x58		/* In wrong mode for request */
425 #define I1PRO_INT_ZEROMEASURES 			0x59		/* Number of measurements requested is zero */
426 #define I1PRO_INT_WRONGPATCHES 			0x5A		/* Number of patches to match is wrong */
427 #define I1PRO_INT_MEASBUFFTOOSMALL 		0x5B		/* Measurement read buffer is too small */
428 #define I1PRO_INT_NOTIMPLEMENTED 		0x5C		/* Support not implemented */
429 #define I1PRO_INT_NOTCALIBRATED 		0x5D		/* Unexpectedely invalid calibration */
430 #define I1PRO_INT_NOINTERPDARK 		    0x5E		/* Need interpolated dark and don't have it */
431 #define I1PRO_INT_THREADFAILED 		    0x5F		/* Creation of thread failed */
432 #define I1PRO_INT_BUTTONTIMEOUT 	    0x60		/* Switch status read timed out */
433 #define I1PRO_INT_CIECONVFAIL 	        0x61		/* Creating spectral to CIE converted failed */
434 #define I1PRO_INT_PREP_LOG_DATA         0x62		/* Error in preparing log data */
435 #define I1PRO_INT_MALLOC                0x63		/* Error in mallocing memory */
436 #define I1PRO_INT_CREATE_EEPROM_STORE   0x64		/* Error in creating EEProm store */
437 #define I1PRO_INT_SAVE_SUBT_MODE        0x65		/* Can't save calibration if in subt mode */
438 #define I1PRO_INT_NO_CAL_TO_SAVE        0x66		/* No calibration data to save */
439 #define I1PRO_INT_EEPROM_DATA_MISSING   0x67		/* EEProm data is missing */
440 #define I1PRO_INT_NEW_RSPL_FAILED       0x68		/* Creating RSPL object faild */
441 #define I1PRO_INT_CAL_SAVE              0x69		/* Unable to save calibration to file */
442 #define I1PRO_INT_CAL_RESTORE           0x6A		/* Unable to restore calibration from file */
443 #define I1PRO_INT_CAL_TOUCH             0x6B		/* Unable to touch calibration file */
444 #define I1PRO_INT_ADARK_INVALID         0x6C		/* Adaptive dark calibration is invalid */
445 #define I1PRO_INT_NO_HIGH_GAIN          0x6D		/* Rev E mode doesn't support high gain mode */
446 #define I1PRO_INT_ASSERT                0x6F		/* Internal assert */
447 
448 int icoms2i1pro_err(int se);
449 
450 /* ============================================================ */
451 /* High level implementatation */
452 
453 /* Initialise our software state from the hardware */
454 i1pro_code i1pro_imp_init(i1pro *p);
455 
456 /* Return a pointer to the serial number */
457 char *i1pro_imp_get_serial_no(i1pro *p);
458 
459 /* Return non-zero if capable of ambient mode */
460 int i1pro_imp_ambient(i1pro *p);
461 
462 /* Set the measurement mode. It may need calibrating */
463 i1pro_code i1pro_imp_set_mode(
464 	i1pro *p,
465 	i1p_mode mmode,		/* i1pro mode to use */
466 	inst_mode m);		/* full mode mask */
467 
468 /* Implement get_n_a_cals */
469 i1pro_code i1pro_imp_get_n_a_cals(i1pro *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals);
470 
471 /* Calibrate for the current mode. */
472 /* Request an instrument calibration of the current mode. */
473 i1pro_code i1pro_imp_calibrate(
474 	i1pro *p,
475 	inst_cal_type *calt,	/* Calibration type to do/remaining */
476 	inst_cal_cond *calc,	/* Current condition/desired condition */
477 	inst_calc_id_type *idtype,	/* Condition identifier type */
478 	char id[100]			/* Condition identifier (ie. white reference ID) */
479 );
480 
481 /* Measure a patch or strip in the current mode. */
482 i1pro_code i1pro_imp_measure(
483 	i1pro *p,
484 	ipatch *val,		/* Pointer to array of instrument patch value */
485 	int nvals,			/* Number of values */
486 	instClamping clamp	/* Clamp XYZ/Lab to be +ve */
487 );
488 
489 /* Do a dummy reflective read, to fix Lamp Drift. */
490 i1pro_code i1pro_imp_lamp_fix(
491 	i1pro *p,
492 	double seconds	/* Number of seconds to turn lamp on for */
493 );
494 
495 /* Measure the emissive refresh rate */
496 i1pro_code i1pro_imp_meas_refrate(
497 	i1pro *p,
498 	double *ref_rate
499 );
500 
501 /* Measure the display update delay */
502 i1pro_code i1pro_imp_meas_delay(
503 	i1pro *p,
504 	int *pdispmsec,
505 	int *pinstmsec);
506 
507 /* Timestamp the white patch change during meas_delay() */
508 inst_code i1pro_imp_white_change(i1pro *p, int init);
509 
510 /* Given a raw measurement of the wavelength LED, */
511 /* Compute the base offset that best fits it to the reference */
512 i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw);
513 
514 /* Compute downsampling filters using the default filters. */
515 /* mtx_index1, mtx_nocoef1, mtx_coef1 given the */
516 /* current wl_led_off */
517 i1pro_code i1pro_compute_wav_filters(i1pro *p, int hires, int reflective);
518 
519 /* return nz if high res is supported */
520 int i1pro_imp_highres(i1pro *p);
521 
522 /* Set to high resolution mode */
523 i1pro_code i1pro_set_highres(i1pro *p);
524 
525 /* Set to standard resolution mode */
526 i1pro_code i1pro_set_stdres(i1pro *p);
527 
528 /* Modify the scan consistency tollerance */
529 i1pro_code i1pro_set_scan_toll(i1pro *p, double toll_ratio);
530 
531 
532 /* Update the single remission calibration and instrument usage log */
533 i1pro_code i1pro_update_log(i1pro *p);
534 
535 /* Save the reflective spot calibration information to the EEPRom data object. */
536 /* Note we don't actually write to the EEProm here! */
537 static i1pro_code i1pro_set_log_data(i1pro *p);
538 
539 /* Restore the reflective spot calibration information from the EEPRom */
540 /* Always returns success, even if the restore fails */
541 i1pro_code i1pro_restore_refspot_cal(i1pro *p);
542 
543 
544 /* Save the calibration for all modes, stored on local system */
545 i1pro_code i1pro_save_calibration(i1pro *p);
546 
547 /* Restore the all modes calibration from the local system */
548 i1pro_code i1pro_restore_calibration(i1pro *p);
549 
550 /* Update the modification time on the file, so we can */
551 /* track when the instrument was last open. */
552 i1pro_code i1pro_touch_calibration(i1pro *p);
553 
554 /* ============================================================ */
555 /* Intermediate routines  - composite commands/processing */
556 
557 i1pro_code i1pro_establish_high_power(i1pro *p);
558 
559 /* Take a dark reference measurement - part 1 */
560 i1pro_code i1pro_dark_measure_1(
561 	i1pro *p,
562 	int nummeas,			/* Number of readings to take */
563 	double *inttime, 		/* Integration time to use/used */
564 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
565 	unsigned char *buf,		/* USB reading buffer to use */
566 	unsigned int bsize		/* Size of buffer */
567 );
568 
569 /* Take a dark reference measurement - part 2 */
570 i1pro_code i1pro_dark_measure_2(
571 	i1pro *p,
572 	double *absraw,			/* Return array [-1 nraw] of absraw values */
573 	int nummeas,			/* Number of readings to take */
574 	double inttime, 		/* Integration time to use/used */
575 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
576 	unsigned char *buf,		/* raw USB reading buffer to process */
577 	unsigned int bsize		/* Buffer size to process */
578 );
579 
580 /* Take a dark measurement */
581 i1pro_code i1pro_dark_measure(
582 	i1pro *p,
583 	double *absraw,			/* Return array [-1 nraw] of absraw values */
584 	int nummeas,			/* Number of readings to take */
585 	double *inttime, 		/* Integration time to use/used */
586 	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
587 );
588 
589 /* Take a white reference measurement - part 3 */
590 /* Average, check, and convert to output wavelengths */
591 i1pro_code i1pro_whitemeasure_3(
592 	i1pro *p,
593 	double *abswav1,		/* Return array [nwav1] of abswav values (may be NULL) */
594 	double *abswav2,		/* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
595 	double *absraw,			/* Return array [-1 nraw] of absraw values */
596 	double *optscale,		/* Factor to scale gain/int time by to make optimal (may be NULL) */
597 	int nummeas,			/* Number of readings to take */
598 	double inttime, 		/* Integration time to use/used */
599 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
600 	double targoscale,		/* Optimal reading target scale factor */
601 	double **multimes,		/* Multiple measurement results */
602 	double darkthresh		/* Raw dark threshold */
603 );
604 
605 /* Take a white reference measurement */
606 /* (Subtracts black and processes into wavelenths) */
607 i1pro_code i1pro_whitemeasure(
608 	i1pro *p,
609 	double *abswav1,		/* Return array [nwav1] of abswav values (may be NULL) */
610 	double *abswav2,		/* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
611 	double *absraw,			/* Return array [-1 nraw] of absraw values */
612 	double *optscale,		/* Factor to scale gain/int time by to make optimal (may be NULL) */
613 	int nummeas,			/* Number of readings to take */
614 	double *inttime, 		/* Integration time to use/used */
615 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
616 	double targoscale,		/* Optimal reading scale factor */
617 	int ltocmode			/* 1 = Lamp turn on compensation mode */
618 );
619 
620 /* Process a single raw white reference measurement */
621 /* (Subtracts black and processes into wavelenths) */
622 i1pro_code i1pro_whitemeasure_buf(
623 	i1pro *p,
624 	double *abswav1,		/* Return array [nwav1] of abswav values (may be NULL) */
625 	double *abswav2,		/* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
626 	double *absraw,			/* Return array [-1 nraw] of absraw values */
627 	double inttime, 		/* Integration time to used */
628 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
629 	unsigned char *buf		/* Raw buffer */
630 );
631 
632 /* Take a wavelength reference measurement */
633 /* (Measure and subtracts black and convert to absraw) */
634 i1pro_code i1pro2_wl_measure(
635 	i1pro *p,
636 	double *absraw,			/* Return array [-1 nraw] of absraw values */
637 	double *optscale,		/* Factor to scale gain/int time by to make optimal (may be NULL) */
638 	double *inttime, 		/* Integration time to use/used */
639 	double targoscale		/* Optimal reading scale factor */
640 );
641 
642 /* Take a measurement reading using the current mode (combined parts 1 & 2a) */
643 /* Converts to completely processed output readings, without averaging or extracting */
644 /* sample patches. */
645 /* (NOTE:- this can't be used for calibration, as it implements uv mode) */
646 i1pro_code i1pro_read_patches_all(
647 	i1pro *p,
648 	double **specrd,		/* Return array [numpatches][nwav] of spectral reading values */
649 	int numpatches,			/* Number of sample to measure */
650 	double *inttime, 		/* Integration time to use/used */
651 	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
652 );
653 
654 /* Take a measurement reading using the current mode, part 1 */
655 /* Converts to completely processed output readings. */
656 i1pro_code i1pro_read_patches_1(
657 	i1pro *p,
658 	int minnummeas,			/* Minimum number of measurements to take */
659 	int maxnummeas,			/* Maximum number of measurements to allow for */
660 	double *inttime, 		/* Integration time to use/used */
661 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
662 	int *nmeasuered,		/* Number actually measured */
663 	unsigned char *buf,		/* Raw USB reading buffer */
664 	unsigned int bsize
665 );
666 
667 /* Take a measurement reading using the current mode, part 2 */
668 /* Converts to completely processed output readings. */
669 i1pro_code i1pro_read_patches_2(
670 	i1pro *p,
671 	double *duration,		/* return flash duration (secs) */
672 	double **specrd,		/* Return array [numpatches][nwav] of spectral reading values */
673 	int numpatches,			/* Number of patches to return */
674 	double inttime, 		/* Integration time to used */
675 	int gainmode,			/* Gain mode useed, 0 = normal, 1 = high */
676 	int nmeasuered,			/* Number actually measured */
677 	unsigned char *buf,		/* Raw USB reading buffer */
678 	unsigned int bsize
679 );
680 
681 /* Take a measurement reading using the current mode. */
682 /* Converts to completely processed output readings. */
683 i1pro_code i1pro_read_patches(
684 	i1pro *p,
685 	double *duration,		/* Return flash duration */
686 	double **specrd,		/* Return array [numpatches][nwav] of spectral reading values */
687 	int numpatches,			/* Number of patches to return */
688 	int minnummeas,			/* Minimum number of measurements to take */
689 	int maxnummeas,			/* Maximum number of measurements to allow for */
690 	double *inttime, 		/* Integration time to use/used */
691 	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
692 );
693 
694 /* Take a trial measurement reading using the current mode. */
695 /* Used to determine if sensor is saturated, or not optimal */
696 i1pro_code i1pro_trialmeasure(
697 	i1pro *p,
698 	int *saturated,			/* Return nz if sensor is saturated */
699 	double *optscale,		/* Factor to scale gain/int time by to make optimal */
700 	int nummeas,			/* Number of readings to take */
701 	double *inttime, 		/* Integration time to use/used */
702 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
703 	double targoscale		/* Optimal reading scale factor */
704 );
705 
706 /* Measurement modifier. Modifes the default current measurement mode */
707 /* for the measurement. Bit 0x10 indicates that incandescent illumination */
708 /* is possible, bit 0x20 indicates that any scan mode is to be ignored */
709 typedef enum {
710 	i1p_norm         = 0x10,	/* Normal measurement for current mode */
711 	i1p2_UV          = 0x01,	/* Measurement using UV LED instead of incandescent (Rev E) */
712 	i1p_cal          = 0x32,	/* No scan, with current mode illumination */
713 	i1p_dark_cal     = 0x23,	/* No scan, no illumination */
714 	i1p2_wl_cal      = 0x24		/* No scan, wavelength reference LED illumination (Rev E) */
715 } i1p_mmodif;
716 
717 /* Trigger a single measurement cycle. This could be a dark calibration, */
718 /* a calibration, or a real measurement. Used to create the higher */
719 /* level "calibrate" and "take reading" functions. */
720 /* The setup for the operation is in the current mode state. */
721 /* The called then needs to call i1pro_readmeasurement() */
722 i1pro_code
723 i1pro_trigger_one_measure(
724 	i1pro *p,
725 	int nummeas,			/* Number of measurements to make */
726 	double *inttime, 		/* Integration time to use/used */
727 	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
728 	i1p_mmodif mmodif		/* Measurement modifier enum */
729 );
730 
731 /* ============================================================ */
732 /* lower level reading processing */
733 
734 /* Take a buffer full of sensor readings, and convert them to */
735 /* absolute raw values. Linearise if Rev A..D */
736 /* Note the rev E darkthresh returned has NOT been converted to an absolute raw value */
737 i1pro_code i1pro_sens_to_absraw(
738 	i1pro *p,
739 	double **absraw,		/* Array of [nummeas][-1 nraw] value to return */
740 	unsigned char *buf,		/* Raw measurement data must be 256 * nummeas */
741 	int nummeas,			/* Return number of readings measured */
742 	double inttime, 		/* Integration time used */
743 	int gainmode,			/* Gain mode, 0 = normal, 1 = high */
744 	double *pdarkthresh     /* Return a dark threshold value (Rev E) */
745 );
746 
747 /* Take a raw value, and convert it into an absolute raw value. */
748 /* Note that linearisation is ignored, since it is assumed to be insignificant */
749 /* to the black threshold and saturation values. */
750 double i1pro_raw_to_absraw(
751 	i1pro *p,
752 	double raw,				/* Input value */
753 	double inttime, 		/* Integration time used */
754 	int gainmode			/* Gain mode, 0 = normal, 1 = high */
755 );
756 
757 /* Take a single set of absolute linearised sensor values and */
758 /* convert them back into i1pro Rev A..D raw reading values. */
759 i1pro_code i1pro_absraw_to_meas(
760 	i1pro *p,
761 	int *meas,				/* Return raw measurement data */
762 	double *absraw,			/* Array of [-1 nraw] value to process */
763 	double inttime, 		/* Integration time used */
764 	int gainmode			/* Gain mode, 0 = normal, 1 = high */
765 );
766 
767 /* Average a set of measurements into one. */
768 /* Return zero if readings are consistent and not saturated. */
769 /* Return nz with bit 1 set if the readings are not consistent */
770 /* Return nz with bit 2 set if the readings are saturated */
771 /* Return the highest individual element. */
772 /* Return the overall average. */
773 int i1pro_average_multimeas(
774 	i1pro *p,
775 	double *avg,			/* return average [-1 nraw] */
776 	double **multimeas,		/* Array of [nummeas][-1 nraw] value to average */
777 	int nummeas,			/* Return number of readings measured */
778 	double *phighest,		/* If not NULL, return highest value from all bands and msrmts. */
779 	double *poallavg,		/* If not NULL, return overall average of bands and measurements */
780 	double satthresh,		/* Sauration threshold, 0 for none */
781 	double darkthresh		/* Dark threshold (used for consistency check scaling) */
782 );
783 
784 /* Recognise the required number of ref/trans patch locations, */
785 /* and average the measurements within each patch. */
786 /* Return flags zero if readings are consistent and not saturated. */
787 /* Return flags nz with bit 1 set if the readings are not consistent */
788 /* Return flags nz with bit 2 set if the readings are saturated */
789 /* Return the highest individual element. */
790 i1pro_code i1pro_extract_patches_multimeas(
791 	i1pro *p,
792 	int *flags,             /* return flags */
793 	double **pavg,			/* return patch average [naptch][-1 nraw] */
794 	int npatch,				/* number of patches to recognise */
795 	double **multimeas,		/* Array of [nummeas][-1 nraw] value to extract from */
796 	int nummeas,			/* number of readings to recognise them from */
797 	double *phighest,		/* If not NULL, return highest value from all bands and msrmts. */
798 	double satthresh,		/* Sauration threshold, 0 for none */
799 	double inttime			/* Integration time (used to adjust consistency threshold) */
800 );
801 
802 /* Recognise any flashes in the readings, and */
803 /* and average their values together as well as summing their duration. */
804 /* Return nz on an error */
805 i1pro_code i1pro_extract_patches_flash(
806 	i1pro *p,
807 	int *flags,				/* return flags */
808 	double *duration,		/* return duration */
809 	double *pavg,			/* return patch average [-1 nraw] */
810 	double **multimeas,		/* Array of [nummeas][-1 nraw] value to extract from */
811 	int nummeas,			/* number of readings made */
812 	double inttime			/* Integration time (used to compute duration) */
813 );
814 
815 /* Subtract one absraw array from another */
816 /* If Rev E, also adjust according to shielded cells, and linearise. */
817 void i1pro_sub_absraw(
818 	i1pro *p,
819 	int nummeas,			/* Return number of readings measured */
820 	double inttime,			/* Integration time used */
821 	int gainmode,			/* Gain mode, 0 = normal, 1 = high */
822 	double **absraw,		/* Source/Desination array [-1 nraw] */
823 	double *sub				/* Black value to subtract [-1 nraw] */
824 );
825 
826 /* Convert an absraw array from raw wavelengths to output wavelenths */
827 /* for the current resolution */
828 void i1pro_absraw_to_abswav(
829 	i1pro *p,
830 	int highres,
831 	int reflective,
832 	int nummeas,			/* Return number of readings measured */
833 	double **abswav,		/* Desination array [nwav] */
834 	double **absraw			/* Source array [-1 nraw] */
835 );
836 
837 /* Convert an abswav array of output wavelengths to scaled output readings. */
838 void i1pro_scale_specrd(
839 	i1pro *p,
840 	double **outspecrd,		/* Destination */
841 	int numpatches,			/* Number of readings/patches */
842 	double **inspecrd		/* Source */
843 );
844 
845 /* Convert from spectral to XYZ, and transfer to the ipatch array */
846 i1pro_code i1pro_conv2XYZ(
847 	i1pro *p,
848 	ipatch *vals,		/* Values to return */
849 	int nvals,			/* Number of values */
850 	double **specrd,	/* Spectral readings */
851 	instClamping clamp	/* Clamp XYZ/Lab to be +ve */
852 );
853 
854 /* Check a reflective white measurement, and check that */
855 /* it seems reasonable. Return inst_ok if it is, error if not. */
856 i1pro_code i1pro_check_white_reference1(
857 	i1pro *p,
858 	double *abswav			/* Measurement to check */
859 );
860 
861 /* Compute a calibration factor given the reading of the white reference. */
862 /* Return I1PRO_RD_TRANSWHITEWARN if any of the transmission wavelengths are low */
863 i1pro_code i1pro_compute_white_cal(
864 	i1pro *p,
865 	double *cal_factor0,	/* [nwav0] Calibration factor to compute */
866 	double *white_ref0,		/* [nwav0] White reference to aim for, NULL for 1.0 */
867 	double *white_read0,	/* [nwav0] The white that was read */
868 	double *cal_factor1,	/* [nwav1] Calibration factor to compute */
869 	double *white_ref1,		/* [nwav1] White reference to aim for, NULL for 1.0 */
870 	double *white_read1,	/* [nwav1] The white that was read */
871 	int do_emis_ft			/* Do emission hires fine tune with this info. */
872 );
873 
874 /* For adaptive mode, compute a new integration time and gain mode */
875 /* in order to optimise the sensor values. */
876 i1pro_code i1pro_optimise_sensor(
877 	i1pro *p,
878 	double *pnew_int_time,
879 	int    *pnew_gain_mode,
880 	double cur_int_time,
881 	int    cur_gain_mode,
882 	int    permithg,		/* nz to permit switching to high gain mode */
883 	int    permitclip,		/* nz to permit clipping out of range int_time, else error */
884 	double targoscale,		/* Optimising target scale ( <= 1.0) */
885 	double scale			/* scale needed of current int time to reach optimum */
886 );
887 
888 /* Compute the number of measurements needed, given the target */
889 /* time and integration time. Will return 0 if target time is 0 */
890 int i1pro_comp_nummeas(
891 	i1pro *p,
892 	double meas_time,
893 	double int_time
894 );
895 
896 /* Convert the dark interpolation data to a useful state */
897 void i1pro_prepare_idark(i1pro *p);
898 
899 /* Create the dark reference for the given integration time and gain */
900 /* by interpolating from the 4 readings taken earlier. */
901 i1pro_code i1pro_interp_dark(
902 	i1pro *p,
903 	double *result,		/* Put result of interpolation here */
904 	double inttime,
905 	int gainmode
906 );
907 
908 /* Create or re-create high resolution mode references */
909 i1pro_code i1pro_create_hr(i1pro *p);
910 
911 /* Set the noinitcalib mode */
912 void i1pro_set_noinitcalib(i1pro *p, int v, int losecs);
913 
914 /* Set the trigger config */
915 void i1pro_set_trig(i1pro *p, inst_opt_type trig);
916 
917 /* Return the trigger config */
918 inst_opt_type i1pro_get_trig(i1pro *p);
919 
920 /* Set the trigger return */
921 void i1pro_set_trigret(i1pro *p, int val);
922 
923 /* Switch thread handler */
924 int i1pro_switch_thread(void *pp);
925 
926 /* ============================================================ */
927 /* Low level i1pro commands */
928 
929 /* USB Commands */
930 
931 /* Reset the instrument */
932 i1pro_code
933 i1pro_reset(
934 	struct _i1pro *p,
935 	int mask	/* reset mask ?. Known values ar 0x1f, 0x07, 0x01 */
936 );
937 
938 /* Read from the EEProm */
939 i1pro_code
940 i1pro_readEEProm(
941 	struct _i1pro *p,
942 	unsigned char *buf,		/* Where to read it to */
943 	int addr,				/* Address in EEprom to read from */
944 	int size				/* Number of bytes to read (max 65535) */
945 );
946 
947 /* Write to the EEProm */
948 i1pro_code
949 i1pro_writeEEProm(
950 	i1pro *p,
951 	unsigned char *buf,		/* Where to write from */
952 	int addr,				/* Address in EEprom to write to */
953 	int size				/* Number of bytes to write (max 65535) */
954 );
955 
956 /* Get the miscelanious status */
957 /* return pointers may be NULL if not needed. */
958 i1pro_code
959 i1pro_getmisc(
960 	i1pro *p,
961 	int *fwrev,		/* Return the hardware version number */
962 	int *unkn1,		/* Unknown status, set after doing a measurement */
963 	int *maxpve,	/* Maximum positive value in sensor readings */
964 	int *unkn3,		/* Unknown status, usually 1 */
965 	int *powmode	/* 0 = high power mode, 8 = low power mode */
966 );
967 
968 /* Get the current measurement parameters */
969 /* return pointers may be NULL if not needed. */
970 i1pro_code
971 i1pro_getmeasparams(
972 	i1pro *p,
973 	int *intclocks,		/* Number of integration clocks (Up to 65535) */
974 	int *lampclocks,	/* Number of lamp turn on sub-clocks (Up to 65535) */
975 	int *nummeas,		/* Number of measurements (Up to 65535) */
976 	int *measmodeflags	/* Measurement mode flags (4 bits, see below) */
977 );
978 
979 /* These bits correspond with the instruction flags */
980 #define I1PRO_MMF_SCAN		0x01	/* Scan mode bit, else spot mode */
981 #define I1PRO_MMF_NOLAMP	0x02	/* No lamp mode, else use illumination lamp */
982 #define I1PRO_MMF_LOWGAIN	0x04	/* Normal gain mode, else high gain */
983 #define I1PRO_MMF_UNKN		0x08	/* Unknown. Not usually set */
984 
985 /* Scan mode continues measuring until the user releases the button. */
986 /* (Does scan mode do the given number of readings as a minimum ???) */
987 /* Spot mode does the given number of readings. */
988 
989 /* Set the measurement parameters */
990 i1pro_code
991 i1pro_setmeasparams(
992 	i1pro *p,
993 	int intclocks,		/* Number of integration clocks */
994 	int lampclocks,		/* Number of lamp turn on sub-clocks */
995 	int nummeas,		/* Number of measurements to make */
996 	int measmodeflags	/* Measurement mode flags */
997 );
998 
999 /* Trigger a measurement after the delay in msec. */
1000 /* The actual return code will be in m->trig_rv after the delay */
1001 i1pro_code
1002 i1pro_triggermeasure(i1pro *p, int delay);
1003 
1004 
1005 /* Read a measurements results */
1006 static i1pro_code
1007 i1pro_readmeasurement(
1008 	i1pro *p,
1009 	int inummeas,			/* Initial number of measurements to expect */
1010 	int scanflag,			/* NZ if in scan mode to continue reading */
1011 	unsigned char *buf,		/* Where to read it to */
1012 	int bsize,				/* Bytes available in buffer */
1013 	int *nummeas,			/* Return number of readings measured */
1014 	i1p_mmodif mmodif		/* Measurement modifier enum */
1015 );
1016 
1017 
1018 /* Set the measurement clock mode */
1019 /* Version >= 301 only */
1020 i1pro_code
1021 i1pro_setmcmode(
1022 	i1pro *p,
1023 	int mcmode	/* Measurement clock mode, 1..mxmcmode */
1024 );
1025 
1026 
1027 /* Get the current measurement clock mode */
1028 /* Return pointers may be NULL if not needed. */
1029 /* Version >= 301 only */
1030 i1pro_code
1031 i1pro_getmcmode(
1032 	i1pro *p,
1033 	int *maxmcmode,		/* mcmode must be < maxmcmode */
1034 	int *mcmode,		/* readback current mcmode */
1035 	int *subclkdiv,		/* Sub clock divider ratio */
1036 	int *intclkusec,	/* Integration clock in usec */
1037 	int *subtmode		/* Subtract mode on read using average of value 127 */
1038 );
1039 
1040 /* ============================================================ */
1041 /* Low level Rev E  commands */
1042 
1043 /* Get the EEProm size */
1044 i1pro_code
1045 i1pro2_geteesize(
1046     i1pro *p,
1047     int *eesize
1048 );
1049 
1050 /* Get the Chip ID (Also valid for Rev D) */
1051 /* Only returns a valid result after reading the EEProm ! */
1052 i1pro_code
1053 i1pro2_getchipid(
1054     i1pro *p,
1055     unsigned char chipid[8]
1056 );
1057 
1058 /* Get Extra Parameters */
1059 i1pro_code
1060 i1pro2_getmeaschar(
1061   i1pro *p,
1062     int *clkusec,
1063     int *xraw,
1064     int *nraw,
1065     int *subdiv
1066 );
1067 
1068 /* These bits correspond with the instruction flags */
1069 #define I1PRO2_MMF_LAMP 	   0x0100	/* Use the Incandescent Lamp as the illuminant */
1070 #define I1PRO2_MMF_UV_LED	   0x0200	/* Use the Ultra Violet LED as the illuminant */
1071 #define I1PRO2_MMF_WL_LED	   0x0300	/* Use the Wavelength Reference LED as the illuminant */
1072 
1073 //#define I1PRO2_MMF_HIGHGAIN    0x0000	/* Rev E mode has no high gain mode ? */
1074 #define I1PRO2_MMF_SCAN	       0x0001	/* Scan mode bit, else spot mode */
1075 #define I1PRO2_MMF_RULER_START 0x0004	/* Start ruler tracking in scan mode */
1076 #define I1PRO2_MMF_RULER_END   0x0008	/* End ruler tracking in scan mode */
1077 
1078 /* Delayed trigger implementation, called from thread */
1079 /* We assume that the Rev E measurement parameters have been set in */
1080 /* the i1proimp structure c_* values */
1081 static int
1082 i1pro2_delayed_trigger(void *pp);
1083 
1084 /* Trigger a measurement after the nominated delay */
1085 /* The actual return code will be in m->trig_rv after the delay. */
1086 /* This allows us to start the measurement read before the trigger, */
1087 /* ensuring that process scheduling latency can't cause the read to fail. */
1088 i1pro_code
1089 i1pro2_triggermeasure(i1pro *p, int delay);
1090 
1091 
1092 /* Get the UV before and after measurement voltage drop */
1093 i1pro_code
1094 i1pro2_getUVvolts(
1095     i1pro *p,
1096     int *before,
1097     int *after
1098 );
1099 
1100 /* Terminate Ruler tracking (???) */
1101 /* The parameter seems to be always 0 ? */
1102 static int
1103 i1pro2_stop_ruler(void *pp, int parm);
1104 
1105 
1106 /* Send a LED sequence */
1107 static int
1108 i1pro2_indLEDseq(void *pp, unsigned char *buf, int size);
1109 
1110 /* Turn indicator LEDs off */
1111 static int
1112 i1pro2_indLEDoff(void *pp);
1113 
1114 // ~~~~9999
1115 
1116 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */
1117 
1118 /* Wait for a reply triggered by a button press */
1119 i1pro_code i1pro_waitfor_switch(i1pro *p, double top);
1120 
1121 /* Wait for a reply triggered by a button press (thread version) */
1122 i1pro_code i1pro_waitfor_switch_th(i1pro *p, double top);
1123 
1124 /* Terminate button handling ? */
1125 i1pro_code i1pro_terminate_switch(i1pro *p);
1126 
1127 /* -------------------------------------------------- */
1128 /* Key/Value storage */
1129 
1130 /* Calibration data storage class */
1131 /* The i1pro stores all it's calibration information */
1132 /* using a key/values arrangement. */
1133 /* We provide a place to store and retrieve that information here. */
1134 
1135 /* We haven't implemented a full set of functions - it's not possible */
1136 /* to create the store from scratch, re-allocate key/value entries, */
1137 /* resize entries or anything else of this sort. */
1138 
1139 
1140 /* Data Key identifiers */
1141 
1142 /* Note that array sizes are nominal. They could change with */
1143 /* driver and instrument changes. */
1144 
1145 /* "Log" data is keys 2710-2715, 271a-271d, 2724-2725 */
1146 
1147 /* The log data seems largly devoted to the last remission spot calibration */
1148 /* or reading, and some general statistics. */
1149 
1150 typedef enum {
1151 
1152 // Note 0x2710 = 10000
1153 	key_meascount	= 0x2715,	/* int, Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
1154 								/* but not the pre-Remission dark calibration. */
1155 	key_darkreading	= 0x271a,	/* int[128] Remspotcal Dark data */
1156 	key_whitereading= 0x271b,	/* int[128] Remspotcal White data */
1157 	key_gainmode	= 0x271c,	/* int - Remspotcal gain mode, Values 1 (normal) or 0 (high) */
1158 	key_inttime		= 0x271d,	/* double - Remspotcal integration time */
1159 	key_caldate		= 0x2724,	/* int date - Remspotcal last calibration date */
1160 	key_calcount	= 0x2725,	/* int - Remission spot measure Count at last Remspotcal. */
1161 	key_checksum	= 0x2710,	/* int - Log checksum */
1162 	key_rpinttime	= 0x2711,	/* double - Last remision spot reading integration time */
1163 	key_rpcount		= 0x2712,	/* int - Remission spot measure Count */
1164 	key_acount		= 0x2713,	/* int - Remission scan measure Count (??) */
1165 	key_lampage		= 0x2714,	/* double - Total lamp usage time (??) */
1166 
1167 /* Duplicate of above, keys += 0x3E8 (+1000) */
1168 // (0x2af8 = 11000)
1169 
1170 	key_2logoff		= 0x03e8,	/* Offset from first to second copy of log keys */
1171 
1172 
1173 /* Calibration parameters are 3e8-3ec, 44c-44e, 4b4-4b5, 4b7-4b8, 4bb-4bd, */
1174 /* 4c5-4c6, bb9-bba, bbf-bc6, fa0 */
1175 
1176 // Note 0x3e8 = 1000
1177 //      0x44c = 1100
1178 //      0x4b0 = 1200
1179 //      0xbb8 = 3000
1180 //      0xfa0 = 4000
1181 
1182 /* Linearisation uses Polinomial equation, ie: y = c0 + c1 * x + c2 * x^2 + c3 * x^3 etc. */
1183 /* and is applied to the raw (integer) sensor data. */
1184 
1185 	key_ng_lin		= 0x03e8,	/* double[4] */
1186 								/* Normal gain polinomial linearisation coefficients */
1187 
1188 	key_hg_lin		= 0x03e9,	/* double[4] */
1189 								/* High gain polinomial linearisation coefficients */
1190 
1191 	key_min_int_time= 0x04c5,	/* double - Minumum integration time */
1192 								/* default 8.84000025689601900e-003 in EEProm */
1193 								/* Overwritten in MinilinoLowLevelDriver constructor: */
1194 								/* Default to 8.84000025689601900e-003 if cpldrev == 101 Ver A */
1195 								/* Default to 4.71600005403161050e-003 if cpldrev == 301 Ver B+ */
1196 
1197 	key_max_int_time= 0x04c6,	/* double - Maximum integration time */
1198 								/* Typically 4.4563798904418945 */
1199 
1200 	key_mtx_index	= 0x03ea,	/* int[36] */
1201 								/* Matrix CCD sample index for each out wavelength */
1202 								/* 380 - 730nm */
1203 
1204 	key_mtx_nocoef	= 0x03eb,	/* int[36] */
1205 								/* Number of matrix cooeficients for each out wavelength */
1206 
1207 	key_mtx_coef	= 0x03ec,	/* double[36 x 16] */
1208 								/* Matrix cooeficients to compute each wavelength */
1209 
1210 	key_0bb9		= 0x0bb9,	/* int - value typically -1*/
1211 	key_0bba		= 0x0bba,	/* int - value typically -1 */
1212 
1213 	key_white_ref	= 0x044c,	/* double[36] */
1214 								/* White calibration tile reflectance values */
1215 
1216 	key_emis_coef	= 0x044d,	/* double[36] */
1217 								/* Emission calibration coefficients */
1218 
1219 	key_amb_coef	= 0x044e,	/* double[36] */
1220 								/* Ambient light calibration values (compound with Emission) */
1221 								/* May be < 36, values -1.0 if Ambient is not supported */
1222 
1223 	key_0fa0		= 0x0fa0,	/* int */
1224 	key_0bbf		= 0x0bbf,	/* int */
1225 
1226 	key_cpldrev		= 0x0bc0,	/* int - Firmware revision number */
1227 
1228 	key_0bc1		= 0x0bc1,	/* int[5] */
1229 
1230 	key_capabilities= 0x0bc2,	/* int */
1231 								/* Capabilities flag ? */
1232 								/* ie. has Ambient capability if val & 0x6000 != 0 */
1233 
1234 	key_0bc3		= 0x0bc3,	/* int */
1235 
1236 	key_physfilt	= 0x0bc4,	/* int - physical filter */
1237 								/* 0x80 == no filter */
1238 								/* 0x82 == UV filter */
1239 
1240 	key_0bc5		= 0x0bc5,	/* int */
1241 
1242 	key_0bc6		= 0x0bc6,	/* double */
1243 
1244 	key_sens_target	= 0x04b4,	/* int - sensor optimal target value */
1245 								/* typical value 37000 */
1246 
1247 	key_sens_dark	= 0x04b5,	/* int - sensor dark reference threshold */
1248 								/* typically value 150 */
1249 
1250 	key_ng_sens_sat	= 0x04b7,	/* int */
1251 								/* Normal gain sensor saturated threshold */
1252 								/* typically value 45000 */
1253 
1254 	key_hg_sens_sat	= 0x04b8,	/* int */
1255 								/* High gain sensor saturated threshold */
1256 								/* typically value 45000 */
1257 
1258 	key_serno		= 0x04bb,	/* int - serial number */
1259 
1260 	key_dom			= 0x04bc,	/* int - unknown */
1261 								/* Possibly date of manufacture DDMMYYYY ? */
1262 								/* ie., decimal 10072002 would be 10/7/2002 ? */
1263 
1264 	key_hg_factor	= 0x04bd,	/* double */
1265 								/* High gain mode gain factor, ie 9.5572.. */
1266 
1267 
1268 	key2_chip_id	= 0x2ee1,	/* uchar[8], chip id */
1269 
1270 	key2_capabilities = 0x2ee2,	/* int, capabilities bits */
1271 
1272 	key2_sens_target = 0x2eeb,	/* int - sensor optimal target value ? */
1273 								/* typical value 30000 */
1274 
1275 	key2_sens_sat 	= 0x2eec,	/* int - sensor saturation value ? */
1276 								/* typical value 55000 */
1277 
1278 	key2_uvcal_intt = 0x2ef9,	/* double, UV calibration initial integration time */
1279 
1280 	key2_wlcal_intt = 0x2efa,	/* double, wavelength calibration initial integration time */
1281 
1282 	key2_wlcal_minlev = 0x2efe,	/* int, wavelength calibration normalized minimum peak level */
1283 
1284 	key2_wlcal_spec = 0x2f44,	/* double[50], wavelength calibration reference spectrum */
1285 
1286 	key2_wlcal_ooff = 0x2f45,	/* int, Reference WL Led spectral offset */
1287 
1288 	key2_wlcal_fwhm  = 0x2f4e,	/* double, wavelength calibration nominal fwhm (nm) */
1289 	key2_wlcal_fwhm_tol  = 0x2f4f,	/* double, wavelength calibration fwhm tollerance (nm) */
1290 
1291 	key2_wlcal_max  = 0x2f46,	/* double, wavelength calibration error limit, ie. 5.0 */
1292 
1293 	key2_wlpoly_1   = 0x2f62,	/* double[4], CCD bin to wavelength polinomial #1 (normal) */
1294 	key2_wlpoly_2   = 0x2f63,	/* double[4], CCD bin to wavelength polinomial #2 ??? */
1295 
1296 	key2_straylight = 0x2f58,	/* int16[36][6] signed stray light values */
1297 	key2_straylight_scale = 0x2f59	/* double stray light scale factor */
1298 
1299 } i1key;
1300 
1301 
1302 /* Data type */
1303 typedef enum {
1304 	i1_dtype_unknown = 0,
1305 	i1_dtype_char    = 1,		/* Array of bytes */
1306 	i1_dtype_short   = 2,		/* 16 bit int, date */
1307 	i1_dtype_int     = 3,		/* 32 bit int, date */
1308 	i1_dtype_double  = 4,		/* 64 bit double, serialized as 32 bit float */
1309 	i1_dtype_section = 5		/* End of section marker */
1310 } i1_dtype;
1311 
1312 /* A key/value entry */
1313 struct _i1keyv {
1314 	void          *data;		/* Array of data */
1315 	unsigned int    count;		/* Count of data */
1316 	i1_dtype        type;		/* Type of data */
1317 	int             addr;		/* EEProm address */
1318 	int             size;		/* Size in bytes */
1319 	int             key;		/* 16 bit key */
1320 	struct _i1keyv *next;		/* Link to next keyv */
1321 }; typedef struct _i1keyv i1keyv;
1322 
1323 struct _i1data {
1324   /* private: */
1325 	i1pro *p;
1326 	i1proimp *m;
1327 
1328 	a1log *log;				/* reference to instrument log */
1329 	i1keyv *head;			/* Pointer to first in chain of keyv */
1330 	i1keyv *last;			/* Pointer to last in chain of keyv */
1331 
1332   /* public: */
1333 
1334 	/* Search the linked list for the given key */
1335 	/* Return NULL if not found */
1336 	i1keyv *(* find_key)(struct _i1data *d, i1key key);
1337 
1338 	/* Search the linked list for the given key and */
1339 	/* return it, or create the key if it doesn't exist. */
1340 	/* Return NULL on error */
1341 	i1keyv *(* make_key)(struct _i1data *d, i1key key);
1342 
1343 	/* Return type of data associated with key. Return i1_dtype_unknown if not found */
1344 	i1_dtype (*get_type)(struct _i1data *d, i1key key);
1345 
1346 	/* Return the number of data items in a keyv. Return 0 if not found */
1347 	unsigned int (*get_count)(struct _i1data *d, i1key key);
1348 
1349 	/* Return a int pointer to the 16 bit int data for the key. */
1350 	/* Optionally return the number of items too. */
1351 	/* Return NULL if not found or wrong type */
1352 	int *(*get_shorts)(struct _i1data *d, unsigned int *count, i1key key);
1353 
1354 	/* Return a pointer to the 32 bit int data for the key. */
1355 	/* Optionally return the number of items too. */
1356 	/* Return NULL if not found or wrong type */
1357 	int *(*get_ints)(struct _i1data *d, unsigned int *count, i1key key);
1358 
1359 	/* Return a pointer to the double data for the key. */
1360 	/* Optionally return the number of items too. */
1361 	/* Return NULL if not found or wrong type */
1362 	double *(*get_doubles)(struct _i1data *d, unsigned int *count, i1key key);
1363 
1364 
1365 	/* Return pointer to one of the int data for the key. */
1366 	/* Return NULL if not found or wrong type or out of range index. */
1367 	int *(*get_int)(struct _i1data *d, i1key key, unsigned int index);
1368 
1369 	/* Return pointer to one of the double data for the key. */
1370 	/* Return NULL if not found or wrong type or out of range index. */
1371 	double *(*get_double)(struct _i1data *d, i1key key, double *data, unsigned int index);
1372 
1373 
1374 	/* Un-serialize a char buffer into an i1key keyv */
1375 	/* (Don't change addr if its is -1) */
1376 	i1pro_code (*unser_ints)(struct _i1data *d, i1key key, int addr,
1377 	                        unsigned char *buf, unsigned int size);
1378 
1379 	/* Un-serialize a char buffer of floats into a double keyv */
1380 	/* (Don't change addr if its is -1) */
1381 	i1pro_code (*unser_doubles)(struct _i1data *d, i1key key, int addr,
1382 	                           unsigned char *buf, unsigned int size);
1383 
1384 
1385 	/* Serialize an i1key keyv into a char buffer. Error if it is outside the buffer */
1386 	i1pro_code (*ser_ints)(struct _i1data *d, i1keyv *k, unsigned char *buf, unsigned int size);
1387 
1388 	/* Serialize a double keyv as floats into a char buffer. Error if the buf is not big enough */
1389 	i1pro_code (*ser_doubles)(struct _i1data *d, i1keyv *k, unsigned char *buf, unsigned int size);
1390 
1391 	/* Initialise the data from the EEprom contents */
1392 	i1pro_code (*parse_eeprom)(struct _i1data *d, unsigned char *buf, unsigned int len, int extra);
1393 
1394 
1395 	/* Serialise all the keys up to the first marker into a buffer. */
1396 	i1pro_code (*prep_section1)(struct _i1data *d, unsigned char **buf, unsigned int *len);
1397 
1398 	/* Copy an array full of ints to the key (must be same size as existing) */
1399 	i1pro_code (*add_ints)(struct _i1data *d, i1key key, int *data, unsigned int count);
1400 
1401 	/* Copy an array full of doubles to the key (must be same size as existing) */
1402 	i1pro_code (*add_doubles)(struct _i1data *d, i1key key, double *data, unsigned int count);
1403 
1404 
1405 	/* Destroy ourselves */
1406 	void (*del)(struct _i1data *d);
1407 
1408 	/* Other utility methods */
1409 
1410 	/* Return the data type for the given key identifier */
1411 	i1_dtype (*det_type)(struct _i1data *d, i1key key);
1412 
1413 	/* Given an index starting at 0, return the matching key code */
1414 	/* for keys that get checksummed. Return 0 if outside range. */
1415 	i1key (*chsum_keys)(struct _i1data *d, int index);
1416 
1417 	/* Compute a checksum. */
1418 	int (*checksum)(struct _i1data *d, i1key keyoffset);
1419 
1420 }; typedef struct _i1data i1data;
1421 
1422 /* Constructor. Construct from the EEprom contents */
1423 extern i1data *new_i1data(i1proimp *m);
1424 
1425 #ifdef __cplusplus
1426 	}
1427 #endif
1428 
1429 #define I1PRO_IMP
1430 #endif /* I1PRO_IMP */
1431