summaryrefslogtreecommitdiff
path: root/spectro/munki_imp.h
blob: ea9451fcca3ab1becf8befb2015a5062aba0ff8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073

#ifndef MUNKI_IMP_H

 /* X-Rite ColorMunki related defines */

/* 
 * Argyll Color Correction System
 *
 * Author: Graeme W. Gill
 * Date:   12/1/2009
 *
 * Copyright 2006 - 2013, Graeme W. Gill
 * All rights reserved.
 *
 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
 * see the License2.txt file for licencing details.
 *
 * (Base on i1pro_imp.h)
 */

/* 
   If you make use of the instrument driver code here, please note
   that it is the author(s) of the code who take responsibility
   for its operation. Any problems or queries regarding driving
   instruments with the Argyll drivers, should be directed to
   the Argyll's author(s), and not to any other party.

   If there is some instrument feature or function that you
   would like supported here, it is recommended that you
   contact Argyll's author(s) first, rather than attempt to
   modify the software yourself, if you don't have firm knowledge
   of the instrument communicate protocols. There is a chance
   that an instrument could be damaged by an incautious command
   sequence, and the instrument companies generally cannot and
   will not support developers that they have not qualified
   and agreed to support.
 */

#ifdef __cplusplus
	extern "C" {
#endif

/* Implementation resources for munki driver */

/* -------------------------------------------------- */
/* Implementation class */

typedef int munki_code;		/* Type to use for error codes */

/* MUNKI mode state. This is implementation data that */
/* depends on the mode the instrument is in. */
/* Each mode has a separate calibration, and configured instrument state. */

typedef enum {
	mk_refl_spot      = 0,
	mk_refl_scan      = 1,
	mk_emiss_spot_na  = 2,		
	mk_tele_spot_na   = 3,		
	mk_emiss_spot     = 4,
	mk_tele_spot      = 5,
	mk_emiss_scan     = 6,
	mk_amb_spot       = 7,
	mk_amb_flash      = 8,
	mk_trans_spot     = 9,
	mk_trans_scan     = 10,
	mk_no_modes       = 11
} mk_mode;

struct _munki_state {
	mk_mode mode;		/* Mode number */

	/* Just one of the following 3 must always be set */
	int emiss;			/* flag - Emissive mode */
	int trans;			/* flag - Transmissive mode */
	int reflective;		/* flag - Reflective mode */

	/* The following modify emiss */
	int ambient;		/* flag - Ambient position mode */
	int projector;		/* flag - Projector position (tele) mode */

	/* The following can be added to any of the 3: */
	int scan;			/* flag - Scanning mode */
	int adaptive;		/* flag - adaptive mode (emiss - adapt for each measurement) */

	/* The following can be added to scan: */
	int flash;			/* flag - Flash detection from scan mode */

	/* Configuration & state information */
	double targoscale;	/* Optimal reading scale factor <= 1.0 */
	double targmaxitime;/* maximum integration time to aim for  (ie. 2.0 sec) */
	double targoscale2;	/* Proportion of targoscale allowed to meed targmaxitime */
	int auto_gain;		/* Whether high gain mode should be used */
	int gainmode;		/* Gain mode, 0 = normal, 1 = high */
	double inttime;		/* Integration time */
	double invsampt;	/* Invalid sample time */

	double dpretime;	/* Target pre-read dark read time - sets no. of readings */
	double wpretime;	/* Target pre-read white/sample read time - sets no. of readings */

	double dcaltime;	/* Target dark calibration time - sets number of readings */
	double wcaltime;	/* Target white calibration time - sets number of readings (not used?) */

	double dreadtime;	/* Target dark on-the-fly cal time - sets number of readings */
	double wreadtime;	/* Target white/sample reading time - sets number of readings */

	double maxscantime;	/* Maximum scan time sets buffer size allocated */

	/* calibration information for this mode */
	int dark_valid;			/* dark calibration factor valid */
	time_t ddate;			/* Date/time of last dark calibration */
	double dark_int_time;	/* Integration time used for dark data */
	double *dark_data;		/* [-1 nraw] of dark level to subtract. Note that the dark value */
							/* depends on integration time and gain mode. */
	int dark_gain_mode;		/* Gain mode used for dark data */

	int cal_valid;			/* calibration factor valid */
	time_t cfdate;			/* Date/time of last cal factor calibration */
	double *cal_factor;		/* [nwav] of calibration scale factor for this mode */
	double *cal_factor1, *cal_factor2;	/* (Underlying tables for two resolutions) */
	double *white_data;		/* [-1 nraw] linear absolute dark subtracted white data */
							/*        used to compute cal_factors (at reftemp) */
	double **iwhite_data;	/* [-1 nraw][2] LED temperature data to interpolate white_data from */
	double reftemp;			/* Reference temperature to correct to */

	/* Adaptive emission/transparency black data */
	int idark_valid;		/* idark calibration factors valid */
	time_t iddate;			/* Date/time of last dark idark calibration */
	double idark_int_time[4];
	double **idark_data;	/* [4][-1 nraw] of dark level for inttime/gains of : */
							/* 0.01 norm, 1.0 norm, 0.01 high, 1.0 high */
							/* then it's converted to base + increment with inttime */

	int want_calib;			/* Initial White calibration wanted */
	int want_dcalib;		/* Initial Dark Calibration wanted */

	/* Display mode calibration state (emmis && !scan && !adaptive) */
	int    dispswap;		/* 0 = default time, 1 = dark_int_time2, 2 = dark_int_time3 */
	double done_dintsel;	/* A display integration time selection has been done */
	time_t diseldate;       /* Date/time of last display integration time selection */
	double dcaltime2;		/* Target dark calibration time - sets number of readings */
	double dark_int_time2;	/* Integration time used for dark data 2 */
	double *dark_data2;		/* [-1 nraw] of dark level to subtract for dark_int_time2. */
	double dcaltime3;		/* Target dark calibration time - sets number of readings */
	double dark_int_time3;	/* Integration time used for dark data 3 */
	double *dark_data3;		/* [-1 nraw] of dark level to subtract for dark_int_time3. */

	char padding[1];		/* to change structure size to invalidate cal file */

}; typedef struct _munki_state munki_state;
 


/* MUNKI implementation class */
struct _munkiimp {
	munki *p;

	/* Misc. and top level */
	struct _mkdata *data;		/* EEProm data container */
	athread *th;				/* Switch monitoring thread (NULL if not used) */
	volatile int switch_count;	/* Incremented in thread */
	volatile int hide_switch;	/* Set to supress switch event during read */
	usb_cancelt sw_cancel;		/* Token to allow cancelling switch I/O */
	volatile int th_term;		/* Thread terminate on error rather than retry */
	volatile int th_termed;		/* Thread has terminated */
	inst_opt_type trig;			/* Reading trigger mode */
	int noinitcalib;			/* Disable initial calibration if not essential */
	int nocalibask;				/* Disable asking user to proceed with calibration */
								/* even when the instrument is in correct configuration */
	int nosposcheck;			/* Disable checking the sensor position */
	int highres;				/* High resolution mode */
	int hr_inited;				/* High resolution has been initialized */

	/* Current settings */
	mk_mode mmode;					/* Current measurement mode selected */
	munki_state ms[mk_no_modes];	/* Mode state */
	int spec_en;				/* Enable reporting of spectral data */

	double intclkp;				/* Integration clock period (computed from tickdur) */

	/* Current state of hardware (~~99 are all these used ??) */
	double c_inttime;			/* Integration period (=inttime + deadtime) */
	int c_measmodeflags;		/* Measurement mode flags (set by trigger() */

	/* Information from the HW */
	int fwrev;					/* int - Firmware revision number, from getfirm() */
								/* Typically 0120 = V1.32 */
	unsigned char chipid[8];	/* HW serial number */
	char vstring[37];			/* Asciiz version string */
	int tickdur;				/* Tick duration (usec, converted to intclkp) */
	int minintcount;			/* Minimum integration tick count */
	int noeeblocks;				/* Number of EEPROM blocks */
	int eeblocksize;			/* Size of each block */

	/* Information from the EEProm */
	int calver;					/* Effective calibration version number */
	int prodno;					/* Production number */
	char serno[17];             /* serial number string */
	int adctype;				/* A/D converter type */

	double minsval;				/* Minimum sensor value target */
	double optsval;				/* Optimal sensor value target */
	double maxsval;				/* Maximum sensor value target */
	double satlimit;			/* Saturation limit */ 

	int ledholdtempdc;			/* LED Hold temparature duty cycle */
								/* Parameter used in measure instruction. [0] */
	double ledpreheattime;		/* LED Pre-heat time, Seconds [1.0] */
								/* Time to turn LED on before determining */
								/* integration time that achieves optimal sensor value. */
	double cal_int_time;		/* Calibration integration time in seconds. [0.018208] */
								/* Starting integration time use for achieving */
								/* the optimal sensor value. */
	double ledwaittime;			/* LED Wait time, Seconds [1.0] */
								/* Time to wait for LED to cool down */
								/* before determining temperature/output characteristic. */
	double calscantime;			/* Calibration scan time used for determining temp/output */
								/* characteristic of LED, Seconds. [3.0] */
	double refinvalidsampt;		/* Reflection invalid sample time in seconds. [0.1] */
								/* This sets the number of extra samples to add to a */
								/* reflective read, and then to discard from */
								/* the start of the measurements. This allows for LED */
								/* thermal warmup. */ 

	double min_int_time;	/* Minimum integration time (secs) (set from minintcount) */
							/* (Typical value is 0.007168 = 139.5 times/sec) */
	double max_int_time;	/* Maximum integration time (secs) (fixed in sw) */

	/* Underlying calibration information */
	int nsen;				/* There are 137 provided from the device, with */
							/* 6 skipped at the start, and 3 at the end. */
							/* The first 4 are photo shielded. */
							/* The last reading is the LED voltage drop */
							/* 2 at the start and 2 at the end are unused. */
	int nraw;				/* Raw sample bands stored = 128 (Must be signed!) */
	int nwav;				/* Current cooked spectrum bands stored, usually = 36 */
	double wl_short;		/* Cooked spectrum bands short wavelength, usually 380 */
	double wl_long;			/* Cooked spectrum bands short wavelength, usually 730 */

	unsigned int nwav1, nwav2;	/* Available bands for standard and high-res modes */
	double wl_short1, wl_short2, wl_long1, wl_long2;

							/* Reflection */
	int *rmtx_index;		/* [nwav] Matrix CCD sample starting index for each out wavelength */
	int *rmtx_nocoef; 		/* [nwav] Number of matrix cooeficients for each out wavelength */
	double *rmtx_coef;		/* [nwav * rmtx_nocoef] Matrix coeef's to compute each wavelength */
	int *rmtx_index1, *rmtx_index2;		/* Underlying arrays for the two resolutions */
	int *rmtx_nocoef1, *rmtx_nocoef2;	/* first [nwav1], second [nwav2] */
	double *rmtx_coef1, *rmtx_coef2;

							/* Emission */
	int *emtx_index;		/* [nwav] Matrix CCD sample starting index for each out wavelength */
	int *emtx_nocoef; 		/* [nwav] Number of matrix cooeficients for each out wavelength */
	double *emtx_coef;		/* [nwav * emtx_nocoef] Matrix coeef's to compute each wavelength */
	int *emtx_index1, *emtx_index2;		/* Underlying arrays for the two resolutions */
	int *emtx_nocoef1, *emtx_nocoef2;	/* first [nwav1], second [nwav2] */
	double *emtx_coef1, *emtx_coef2;

	unsigned int nlin0;		/* Number in array */
	double *lin0;			/* Array of linearisation polinomial factors, normal gain. */

	unsigned int nlin1;		/* Number in array */
	double *lin1;			/* Array of linearisation polinomial factors, high gain. */
		
	double *white_ref;		/* [nwav] White calibration tile reflectance values */
	double *emis_coef;		/* [nwav] Emission calibration coefficients */
	double *amb_coef;		/* [nwav] Ambient light cal values (compound with Emission) */
	double *proj_coef;		/* [nwav] Projector light cal values (compound with Emission) */
	double *white_ref1, *white_ref2;	/* Underlying tables for normal/high res modes */
	double *emis_coef1, *emis_coef2;
	double *amb_coef1, *amb_coef2;
	double *proj_coef1, *proj_coef2;

	double **straylight;		/* [nwav][nwav] Stray light convolution matrix */
	double **straylight1, **straylight2;	/* Underlying tables for normal/high res modes */

	double highgain;		/* High gain mode gain */
	double scan_toll_ratio;	/* Modifier of scan tollerance */

	/* Trigger houskeeping & diagnostics */
	int transwarn;			/* Transmission calibration warning state */
	int lo_secs;            /* Seconds since last opened (from calibration file mod time) */
	int tr_t1, tr_t2, tr_t3, tr_t4, tr_t5, tr_t6, tr_t7;	/* Trigger/read timing diagnostics */
							/* 1->2 = time to execute trigger */
							/* 2->3 = time to between end trigger and start of first read */
							/* 3->4 = time to exectute first read */
							/* 6->5 = time between end of second last read and start of last read */
	int trig_se;			/* Delayed trigger icoms error */
	munki_code trig_rv;		/* Delayed trigger result */

	athread *spos_th;				/* Position change filter thread */
	volatile int spos_th_term;		/* nz to terminate thread */
	volatile int spos_th_termed;	/* nz when terminated */
	volatile int spos_change;		/* counter that increments on an spos event change */
	unsigned int spos_msec;			/* Time when spos last changes */

	volatile double whitestamp;		/* meas_delay() white timestamp */
	volatile double trigstamp;		/* meas_delay() trigger timestamp */

}; typedef struct _munkiimp munkiimp;

/* Add an implementation structure */
munki_code add_munkiimp(munki *p);

/* Destroy implementation structure */
void del_munkiimp(munki *p);

/* ============================================================ */
/* Error codes returned from munki_imp */

/* Note: update munki_interp_error() and munki_interp_code() in munki.c */
/* if anything of these #defines are added or subtracted */

/* Fake Error codes */
#define MUNKI_INTERNAL_ERROR			0x71		/* Internal software error */
#define MUNKI_COMS_FAIL					0x72		/* Communication failure */
#define MUNKI_UNKNOWN_MODEL				0x73		/* Not an munki */
#define MUNKI_DATA_PARSE_ERROR  		0x74		/* Read data parsing error */

#define MUNKI_USER_ABORT		    	0x75		/* uicallback returned abort */
#define MUNKI_USER_TRIG 		    	0x76		/* uicallback retuned trigger */

#define MUNKI_UNSUPPORTED		   		0x79		/* Unsupported function */
#define MUNKI_CAL_SETUP                 0x7A		/* Cal. retry with correct setup is needed */

/* Real error code */
#define MUNKI_OK   						0x00

/* EEprop parsing errors */
#define MUNKI_DATA_RANGE			    0x02		/* out of range of buffer */
#define MUNKI_DATA_MEMORY 				0x03		/* memory alloc failure */

/* HW errors */
#define MUNKI_HW_EE_SHORTREAD		    0x21		/* Read fewer EEProm bytes than expected */
#define MUNKI_HW_ME_SHORTREAD		    0x22		/* Read measurement bytes than expected */
#define MUNKI_HW_ME_ODDREAD			    0x23		/* Read measurement bytes was not mult 274 */
#define MUNKI_HW_CALIBVERSION		    0x24		/* calibration version is unknown */
#define MUNKI_HW_CALIBMATCH		        0x25		/* calibration doesn't match device */

/* Sample read operation errors */
#define MUNKI_RD_DARKREADINCONS		    0x30		/* Dark calibration reading inconsistent */
#define MUNKI_RD_SENSORSATURATED	    0x31		/* Sensor is saturated */
#define MUNKI_RD_DARKNOTVALID   	    0x32		/* Dark reading is not valid (too light) */
#define MUNKI_RD_NEEDS_CAL 		        0x33		/* Mode needs calibration */
#define MUNKI_RD_WHITEREADINCONS        0x34		/* White reference readings are inconsistent */
#define MUNKI_RD_WHITEREFERROR 	        0x35		/* White reference reading error */
#define MUNKI_RD_LIGHTTOOLOW 	        0x36		/* Light level is too low */
#define MUNKI_RD_LIGHTTOOHIGH 	        0x37		/* Light level is too high */
#define MUNKI_RD_SHORTMEAS              0x38		/* Measurment was too short */
#define MUNKI_RD_READINCONS             0x39		/* Reading is inconsistent */
#define MUNKI_RD_REFWHITENOCONV         0x3A		/* White calibration didn't converge */
#define MUNKI_RD_NOTENOUGHPATCHES       0x3B		/* Not enough patches */
#define MUNKI_RD_TOOMANYPATCHES         0x3C		/* Too many patches */
#define MUNKI_RD_NOTENOUGHSAMPLES       0x3D		/* Not enough samples per patch */
#define MUNKI_RD_NOFLASHES              0x3E		/* No flashes recognized */
#define MUNKI_RD_NOAMBB4FLASHES         0x3F		/* No ambient before flashes found */
#define MUNKI_RD_NOREFR_FOUND           0x40		/* Unable to measure refresh rate */
#define MUNKI_RD_NOTRANS_FOUND          0x41		/* Unable to measure delay transition */

#define MUNKI_SPOS_PROJ                 0x48		/* Sensor needs to be in projector position */
#define MUNKI_SPOS_SURF                 0x49		/* Sensor needs to be in surface position */
#define MUNKI_SPOS_CALIB                0x4A		/* Sensor needs to be in calibration position */
#define MUNKI_SPOS_AMB                  0x4B		/* Sensor needs to be in ambient position */

/* Internal errors */
#define MUNKI_INT_NO_COMS 		        0x50
#define MUNKI_INT_EESIZE                0x51        /* EEProm read size is too big */
#define MUNKI_INT_EEOUTOFRANGE 		    0x52		/* EEProm size is unexpected */
#define MUNKI_INT_CALTOOSMALL 		    0x53		/* Calibration EEProm size is too small */
#define MUNKI_INT_CALTOOBIG 		    0x54		/* Calibration EEProm size is too big */
#define MUNKI_INT_CALBADCHSUM 		    0x55		/* Calibration has a bad checksum */
#define MUNKI_INT_ODDREADBUF 	        0x56		/* Measurment read buffer is not mult 274 */
#define MUNKI_INT_INTTOOBIG				0x57		/* Integration time is too big */
#define MUNKI_INT_INTTOOSMALL			0x58		/* Integration time is too small */
#define MUNKI_INT_ILLEGALMODE			0x59		/* Illegal measurement mode selected */
#define MUNKI_INT_ZEROMEASURES 			0x5A		/* Number of measurements requested is zero */
#define MUNKI_INT_WRONGPATCHES 			0x5B		/* Number of patches to match is wrong */
#define MUNKI_INT_MEASBUFFTOOSMALL 		0x5C		/* Measurement read buffer is too small */
#define MUNKI_INT_NOTIMPLEMENTED 		0x5D		/* Support not implemented */
#define MUNKI_INT_NOTCALIBRATED 		0x5E		/* Unexpectedely invalid calibration */
#define MUNKI_INT_THREADFAILED 		    0x5F		/* Creation of thread failed */
#define MUNKI_INT_BUTTONTIMEOUT 	    0x60		/* Switch status read timed out */
#define MUNKI_INT_CIECONVFAIL 	        0x61		/* Creating spectral to CIE converted failed */
#define MUNKI_INT_MALLOC                0x62		/* Error in mallocing memory */
#define MUNKI_INT_CREATE_EEPROM_STORE   0x63		/* Error in creating EEProm store */
#define MUNKI_INT_NEW_RSPL_FAILED       0x64		/* Creating RSPL object faild */
#define MUNKI_INT_CAL_SAVE              0x65		/* Unable to save calibration to file */
#define MUNKI_INT_CAL_RESTORE           0x66		/* Unable to restore calibration from file */
#define MUNKI_INT_CAL_TOUCH             0x67        /* Unable to touch calibration file */


#define MUNKI_INT_ASSERT                0x6F		/* Internal assert */


int icoms2munki_err(int se);

/* ============================================================ */
/* High level implementatation */

/* Initialise our software state from the hardware */
munki_code munki_imp_init(munki *p);

/* Return a pointer to the serial number */
char *munki_imp_get_serial_no(munki *p);

/* Set the measurement mode. It may need calibrating */
munki_code munki_imp_set_mode(
	munki *p,
	mk_mode mmode,		/* Operating mode */
	inst_mode mode		/* Full mode mask for options */
);

/* Implement get_n_a_cals */
munki_code munki_imp_get_n_a_cals(munki *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals);

/* Calibrate for the current mode. */
/* Request an instrument calibration of the current mode. */
munki_code munki_imp_calibrate(
munki *p,
inst_cal_type *calt,	/* Calibration type to do/remaining */
inst_cal_cond *calc,	/* Current condition/desired condition */
char id[100]			/* Condition identifier (ie. white reference ID) */
);

/* Measure a patch or strip in the current mode. */
munki_code munki_imp_measure(
	munki *p,
	ipatch *val,		/* Pointer to array of instrument patch value */
	int nvals,			/* Number of values */	
	instClamping clamp	/* Clamp XYZ/Lab to be +ve */
);

/* Measure the emissive refresh rate */
munki_code munki_imp_meas_refrate(
	munki *p,
	double *ref_rate
);

/* Measure the display update delay */
munki_code munki_imp_meas_delay(
munki *p,
int *pdispmsec,
int *pinstmsec);

/* Timestamp the white patch change during meas_delay() */
inst_code munki_imp_white_change(munki *p, int init);

/* return nz if high res is supported */
int munki_imp_highres(munki *p);

/* Set to high resolution mode */
munki_code munki_set_highres(munki *p);

/* Set to standard resolution mode */
munki_code munki_set_stdres(munki *p);

/* Modify the scan consistency tollerance */
munki_code munki_set_scan_toll(munki *p, double toll_ratio);


/* Save the calibration for all modes, stored on local system */
munki_code munki_save_calibration(munki *p);

/* Restore the all modes calibration from the local system */
munki_code munki_restore_calibration(munki *p);


/* ============================================================ */
/* Intermediate routines  - composite commands/processing */

/* Take a dark reference measurement - part 1 */
munki_code munki_dark_measure_1(
	munki *p,
	int nummeas,			/* Number of readings to take */
	double *inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	unsigned char *buf,		/* USB reading buffer to use */
	unsigned int bsize		/* Size of buffer */
);

/* Take a dark reference measurement - part 2 */
munki_code munki_dark_measure_2(
	munki *p,
	double *sens,			/* Return array [-1 nraw] of sens values */
	int nummeas,			/* Number of readings to take */
	double inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	unsigned char *buf,		/* raw USB reading buffer to process */
	unsigned int bsize		/* Buffer size to process */
);

/* Take a dark measurement */
munki_code munki_dark_measure(
	munki *p,
	double *sens,			/* Return array [-1 nraw] of sens values */
	int nummeas,			/* Number of readings to take */
	double *inttime, 		/* Integration time to use/used */
	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
);

/* Take a white reference measurement */
/* (Subtracts black and processes into wavelenths) */
munki_code munki_whitemeasure(
	munki *p,
	double *absraw,			/* Return array [-1 nraw] of absraw values (may be NULL) */
	double *optscale,		/* Factor to scale gain/int time by to make optimal (may be NULL) */
	int nummeas,			/* Number of readings to take */
	double *inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	double targoscale		/* Optimal reading scale factor */
);

/* Given an absraw white reference measurement, */
/* compute the wavelength equivalents. */
/* (absraw is usually ->white_data) */
/* (abswav1 is usually ->cal_factor1) */
/* (abswav2 is usually ->cal_factor2) */
munki_code munki_compute_wav_whitemeas(
	munki *p,
	double *abswav1,		/* Return array [nwav1] of abswav values (may be NULL) */
	double *abswav2,		/* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
	double *absraw			/* Given array [-1 nraw] of absraw values */
);

/* Take a reflective white reference measurement, */
/* subtracts black and decompose into base + LED temperature components */
munki_code munki_ledtemp_whitemeasure(
	munki *p,
	double *white,			/* Return [-1 nraw] of temperature compensated white reference */
	double **iwhite,		/* Return array [-1 nraw][2] of absraw base and scale values */
	double *reftemp,		/* Return a reference temperature to normalize to */
	int nummeas,			/* Number of readings to take */
	double inttime, 		/* Integration time to use */
	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
);

/* Given the ledtemp base and scale values, */
/* return a raw reflective white reference for the */
/* given temperature */ 
munki_code munki_ledtemp_white(
	munki *p,
	double *absraw,			/* Return array [-1 nraw] of absraw base and scale values */
	double **iwhite,		/* ledtemp base and scale */
	double ledtemp			/* LED temperature value */
);

/* Given a set of absraw sensor readings and the corresponding temperature, */
/* compensate the readings to be at the nominated temperature. */
munki_code munki_ledtemp_comp(
	munki *p,
	double **absraw,		/* [nummeas][raw] measurements to compensate */
	double *ledtemp,		/* LED temperature for each measurement */
	int nummeas,			/* Number of measurements */
	double reftemp,			/* LED reference temperature to compensate to */
	double **iwhite			/* ledtemp base and scale information */
);

/* Heat the LED up for given number of seconds by taking a reading */
munki_code munki_heatLED(
	munki *p,
	double htime		/* Heat up time */
);

/* Process a single raw white reference measurement */
/* (Subtracts black and processes into wavelenths) */
munki_code munki_whitemeasure_buf(
	munki *p,
	double *abswav1,		/* Return array [nwav1] of abswav values (may be NULL) */
	double *abswav2,		/* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
	double *absraw,			/* Return array [-1 nraw] of absraw values */
	double inttime, 		/* Integration time to used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	unsigned char *buf		/* Raw buffer */
);

/* Take a measurement reading using the current mode (combined parts 1 & 2a) */
/* Converts to completely processed output readings, without averaging or extracting */
/* sample patches, for emissive measurement mode. */
/* This is used for delay & refresh rate measurement. */
munki_code munki_read_patches_all(
	munki *p,
	double **specrd,		/* Return array [numpatches][nwav] of spectral reading values */
	int numpatches,			/* Number of sample to measure */
	double *inttime, 		/* Integration time to use/used */
	int gainmode			/* Gain mode to use, 0 = normal, 1 = high */
);

/* Take a measurement reading using the current mode, part 1 */
/* Converts to completely processed output readings. */
munki_code munki_read_patches_1(
	munki *p,
	int ninvmeas,			/* Number of extra invalid measurements at start */
	int minnummeas,			/* Minimum number of measurements to take */
	int maxnummeas,			/* Maximum number of measurements to allow for */
	double *inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	int *nmeasuered,		/* Number actually measured (excluding ninvmeas) */
	unsigned char *buf,		/* Raw USB reading buffer */
	unsigned int bsize
);

/* Take a measurement reading using the current mode, part 2 */
/* Converts to completely processed output readings. */
munki_code munki_read_patches_2(
	munki *p,
	double *duration,		/* return flash duration (secs) */
	double **specrd,		/* Return array [numpatches][nwav] of spectral reading values */
	int numpatches,			/* Number of patches to return */
	double inttime, 		/* Integration time to used */
	int gainmode,			/* Gain mode useed, 0 = normal, 1 = high */
	int ninvmeas,			/* Number of extra invalid measurements at start */
	int nmeasuered,			/* Number actually measured */
	unsigned char *buf,		/* Raw USB reading buffer */
	unsigned int bsize
);

/* Take a trial measurement reading using the current mode. */
/* Used to determine if sensor is saturated, or not optimal */
munki_code munki_trialmeasure(
	munki *p,
	int *saturated,			/* Return nz if sensor is saturated */
	double *optscale,		/* Factor to scale gain/int time by to make optimal */
	int nummeas,			/* Number of readings to take */
	double *inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	double targoscale		/* Optimal reading scale factor */
);

/* Trigger a single measurement cycle. This could be a dark calibration, */
/* a calibration, or a real measurement. Used to create the higher */
/* level "calibrate" and "take reading" functions. */
/* The setup for the operation is in the current mode state. */
/* The called then needs to call munki_readmeasurement() */
static munki_code
munki_trigger_one_measure(
	munki *p,
	int nummeas,			/* Number of measurements to make */
	double *inttime, 		/* Integration time to use/used */
	int gainmode,			/* Gain mode to use, 0 = normal, 1 = high */
	int calib_measure,		/* flag - nz if this is a calibration measurement */
	int dark_measure		/* flag - nz if this is a dark measurement */
);

/* ============================================================ */
/* lower level reading processing */

/* Take a buffer full of sensor readings, and convert them to */
/* directly to floating point raw values. */
/* Return MUNKI_RD_SENSORSATURATED if any is saturated */
munki_code munki_sens_to_raw(
	munki *p,
	double **raw,			/* Array of [nummeas-ninvalid][-1 nraw] value to return */
	double *ledtemp,		/* Optional array [nummeas-ninvalid] LED temperature values to return */
	unsigned char *buf,		/* Sensor measurement data must be 274 * nummeas */
	int nummeas,			/* Number of readings measured */
	int ninvalid,			/* Number of initial invalid readings to skip */
	double satthresh,		/* Sauration threshold in raw units */
	double *darkthresh		/* Return a dark threshold value */
);

/* Subtract the black from raw values and convert to */
/* absolute (integration & gain scaled), zero offset based, */
/* linearized sensor values. */
void munki_sub_raw_to_absraw(
	munki *p,
	int nummeas,			/* Return number of readings measured */
	double inttime, 		/* Integration time used */
	int gainmode,			/* Gain mode, 0 = normal, 1 = high */
	double **absraw,		/* Source/Desination array [-1 nraw] */
	double *sub,			/* Value to subtract [-1 nraw] */
	double *trackmax, 		/* absraw values that should be offset the same as max */
	int ntrackmax,			/* Number of trackmax values */
	double *maxv			/* If not NULL, return the maximum value */
);

/* Average a set of sens or absens measurements into one. */
/* (Make sure darkthresh is tracked if absens is being averaged!) */
/* Return zero if readings are consistent and not saturated. */
/* Return nz if the readings are not consistent */
/* Return the overall average. */
int munki_average_multimeas(
	munki *p,
	double *avg,			/* return average [-1 nraw] */
	double **multimeas,		/* Array of [nummeas][-1 nraw] value to average */
	int nummeas,			/* number of readings to be averaged */
	double *poallavg,		/* If not NULL, return overall average of bands and measurements */
	double darkthresh		/* Dark threshold (used for consistency check scaling) */
);

/* Recognise the required number of ref/trans patch locations, */
/* and average the measurements within each patch. */
/* Return flags zero if readings are consistent. */
/* Return flags nz if the readings are not consistent */
munki_code munki_extract_patches_multimeas(
	munki *p,
	int *flags,             /* return flags */
	double **pavg,			/* return patch average [naptch][-1 nraw] */
	int npatch,				/* number of patches to recognise */
	double **multimeas,		/* Array of [nummeas][-1 nraw] value to extract from */
	int nummeas,			/* number of readings to recognise them from */
	double inttime			/* Integration time (used to adjust consistency threshold) */
);

/* Recognise any flashes in the readings, and */
/* and average their values together as well as summing their duration. */
/* Return nz on an error */
munki_code munki_extract_patches_flash(
	munki *p,
	int *flags,				/* return flags */
	double *duration,		/* return duration */
	double *pavg,			/* return patch average [-1 nraw] */
	double **multimeas,		/* Array of [nummeas][-1 nraw] value to extract from */
	int nummeas,			/* number of readings made */
	double inttime			/* Integration time (used to compute duration) */
);

/* Convert an absraw array from raw wavelengths to output wavelenths */
/* for the current resolution */
void munki_absraw_to_abswav(
	munki *p,
	int nummeas,			/* Return number of readings measured */
	double **abswav,		/* Desination array [nwav] */
	double **absraw		/* Source array [-1 nraw] */
);

/* Convert an absraw array from raw wavelengths to output wavelenths */
/* for the standard resolution */
void munki_absraw_to_abswav1(
	munki *p,
	int nummeas,			/* Return number of readings measured */
	double **abswav,		/* Desination array [nwav1] */
	double **absraw		/* Source array [-1 nraw] */
);

/* Convert an absraw array from raw wavelengths to output wavelenths */
/* for the high resolution */
void munki_absraw_to_abswav2(
	munki *p,
	int nummeas,			/* Return number of readings measured */
	double **abswav,		/* Desination array [nwav2] */
	double **absraw		/* Source array [-1 nraw] */
);

/* Convert an abswav array of output wavelengths to scaled output readings. */
void munki_scale_specrd(
	munki *p,
	double **outspecrd,		/* Destination */
	int numpatches,			/* Number of readings/patches */
	double **inspecrd		/* Source */
);

/* Convert from spectral to XYZ, and transfer to the ipatch array */
munki_code munki_conv2XYZ(
	munki *p,
	ipatch *vals,		/* Values to return */
	int nvals,			/* Number of values */
	double **specrd,	/* Spectral readings */
	instClamping clamp	/* Clamp XYZ/Lab to be +ve */
);

/* Compute a calibration factor given the reading of the white reference. */
/* Return nz if any of the transmission wavelengths are low */
int munki_compute_white_cal(
	munki *p,
	double *cal_factor1,	/* [nwav1] Calibration factor to compute */
	double *white_ref1,		/* [nwav1] White reference to aim for, NULL for 1.0 */
	double *white_read1,	/* [nwav1] The white that was read */
	double *cal_factor2,	/* [nwav2] Calibration factor to compute */
	double *white_ref2,		/* [nwav2] White reference to aim for, NULL for 1.0 */
	double *white_read2		/* [nwav2] The white that was read */
);

/* For adaptive mode, compute a new integration time and gain mode */
/* in order to optimise the sensor values. */
munki_code munki_optimise_sensor(
	munki *p,
	double *pnew_int_time,
	int    *pnew_gain_mode,
	double cur_int_time,
	int    cur_gain_mode,
	int    permithg,		/* nz to permit switching to high gain mode */
	int    permitclip,		/* nz to permit clipping out of range int_time, else error */
	double *targoscale,		/* Optimising target scale ( <= 1.0) */
							/* (May be altered if integration time isn't possible) */
	double scale,			/* scale needed of current int time to reach optimum */
	double deadtime			/* Dead integration time (if any) */
);

/* Compute the number of measurements needed, given the target */
/* time and integration time. Will return 0 if target time is 0 */
int munki_comp_nummeas(
	munki *p,
	double meas_time,
	double int_time
);

/* Compute the rounded up number of measurements needed, */
/* given the target time and integration time. */
/* Will return 0 if target time is 0 */
int munki_comp_ru_nummeas(
	munki *p,
	double meas_time,
	double int_time
);

/* Convert the dark interpolation data to a useful state */
void munki_prepare_idark(munki *p);

/* Create the dark reference for the given integration time and gain */
/* by interpolating from the 4 readings taken earlier. */
munki_code munki_interp_dark(
	munki *p,
	double *result,		/* Put result of interpolation here */
	double inttime,
	int gainmode
);

/* Create high resolution mode references. */
/* Create Reflective if ref nz, else create Emissive */
munki_code munki_create_hr(munki *p, int ref);

/* Set the noinitcalib mode */
void munki_set_noinitcalib(munki *p, int v, int losecs);

/* Set the nocalibask mode */
void munki_set_nocalibask(munki *p, int v);

/* Set the trigger config */
void munki_set_trig(munki *p, inst_opt_type trig);

/* Return the trigger config */
inst_opt_type munki_get_trig(munki *p);

/* Set the trigger return */
void munki_set_trigret(munki *p, int val);

#ifdef USE_THREAD
/* Switch thread handler */
static int munki_switch_thread(void *pp);
#endif

#ifdef FILTER_SPOS_EVENTS
static int munki_spos_thread(void *pp);
#endif

/* ============================================================ */
/* Low level commands */

/* USB Commands */

/* Read from the EEProm */
munki_code
munki_readEEProm(
	struct _munki *p,
	unsigned char *buf,		/* Where to read it to */
	int addr,				/* Address in EEprom to read from */
	int size				/* Number of bytes to read (max 65535) */
);


/* Get the firmware parameters */
/* return pointers may be NULL if not needed. */
munki_code
munki_getfirm(
	munki *p,
	int *fwrev,			/* Return the formware version number as 8.8 */
	int *tickdur,		/* Tick duration */
	int *minintcount,	/* Minimum integration tick count */
	int *noeeblocks,	/* Number of EEPROM blocks */
	int *eeblocksize	/* Size of each block */
);

/* Get the Chip ID */
munki_code
munki_getchipid(
	munki *p,
	unsigned char chipid[8]
);

/* Get the Version String */
munki_code
munki_getversionstring(
    munki *p,
    char vstring[37]
);

/* Get the measurement state */
/* return pointers may be NULL if not needed. */
munki_code
munki_getmeasstate(
    munki *p,
    int *ledtrange,     /* LED temperature range */
    int *ledtemp,       /* LED temperature */
    int *dutycycle,     /* Duty Cycle */
    int *ADfeedback     /* A/D converter feedback */
);

/* Munki sensor positions */
typedef enum {
	mk_spos_proj  = 0x00,	/* Projector/Between detents */
	mk_spos_surf  = 0x01,	/* Surface */
	mk_spos_calib = 0x02,	/* Calibration tile */
	mk_spos_amb   = 0x03	/* Ambient */
} mk_spos;

/* Munki switch state */
typedef enum {
	mk_but_switch_release = 0x00,	/* Button is released */
	mk_but_switch_press   = 0x01	/* Button is pressed */
} mk_but;

/* Get the device status */
/* return pointers may be NULL if not needed. */
munki_code
munki_getstatus(
	munki *p,
	mk_spos *spos,		/* Return the sensor position */
	mk_but *but			/* Return Button state */
);

/* Set the indicator LED state */
munki_code
munki_setindled(
    munki *p,
    int ontime,			/* On time (msec) */
    int offtrime,		/* Off time (msec) */
    int transtime,		/* Transition time (msec) */
    int nopulses,		/* Number of pulses, -1 = max */
    int p5				/* Ignored ? */
);

/* Measuremend mode flags */
#define MUNKI_MMF_LAMP		0x01	/* Lamp mode, else no illumination of sample */
#define MUNKI_MMF_SCAN		0x02	/* Scan mode bit, else spot mode */
#define MUNKI_MMF_HIGHGAIN	0x04	/* High gain, else normal gain. */

/* Trigger a measurement with the given measurement parameters */
munki_code
munki_triggermeasure(
	munki *p,
	int intclocks,		/* Number of integration clocks */
	int nummeas,		/* Number of measurements to make */
	int measmodeflags,	/* Measurement mode flags */
	int holdtempduty	/* Hold temperature duty cycle */
);

/* Read a measurements results */
static munki_code
munki_readmeasurement(
	munki *p,
	int inummeas,			/* Initial number of measurements to expect */
	int scanflag,			/* NZ if in scan mode to continue reading */
	unsigned char *buf,		/* Where to read it to */
	int bsize,				/* Bytes available in buffer */
	int *nummeas,			/* Return number of readings measured */
	int calib_measure,		/* flag - nz if this is a calibration measurement */
	int dark_measure		/* flag - nz if this is a dark measurement */
);

/* Set the measurement clock mode */
/* Version >= 301 only */
munki_code
munki_setmcmode(
	munki *p,
	int mcmode	/* Measurement clock mode, 1..mxmcmode */
);

/* Munki event values, returned by event pipe, or */
/* parameter to simulate event */
typedef enum {
	mk_eve_none           = 0x0000,	/* No event */
	mk_eve_switch_press   = 0x0001,	/* Button has been pressed */
	mk_eve_switch_release = 0x0002,	/* Button has been released */
	mk_eve_spos_change    = 0x0100	/* Sensor position is being changed */
} mk_eve;

/* Simulating an event (use to terminate event thread) */
/* timestamp is msec since munki power up */
munki_code munki_simulate_event(munki *p, mk_eve ecode, int timestamp);

/* Wait for a reply triggered by a key press */
munki_code munki_waitfor_switch(munki *p, mk_eve *ecode, int *timest, double top);

/* Wait for a reply triggered by a key press (thread version) */
munki_code munki_waitfor_switch_th(munki *p, mk_eve *ecode, int *timest, double top);

/* -------------------------------------------------- */
/* EEProm parsing support. */

/* Initialise the calibration from the EEProm contents. */
/* (We're handed a buffer that's been rounded up to an even 32 bits by */
/* padding with zero's) */
munki_code munki_parse_eeprom(munki *p, unsigned char *buf, unsigned int len);

struct _mkdata {
  /* private: */
	munki *p;

	a1log *log;
	unsigned char *buf;		/* Buffer to parse */
	int len;				/* Length of buffer */
	
  /* public: */

	/* Return a pointer to an array of chars containing data from 8 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	unsigned char *(*get_8_char)(struct _mkdata *d, unsigned char *rv, int offset, int count);

	/* Return a pointer to an nul terminated string containing data from 8 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	/* An extra space and a nul terminator will be added to the eeprom data */
	char *(*get_8_asciiz)(struct _mkdata *d, char *rv, int offset, int count);


	/* Return a pointer to an array of ints containing data from 8 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	int *(*get_8_ints)(struct _mkdata *d, int *rv, int offset, int count);

	/* Return a pointer to an array of ints containing data from unsigned 8 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	int *(*get_u8_ints)(struct _mkdata *d, int *rv, int offset, int count);


	/* Return a pointer to an array of ints containing data from 16 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	int *(*get_16_ints)(struct _mkdata *d, int *rv, int offset, int count);

	/* Return a pointer to an array of ints containing data from unsigned 16 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	int *(*get_u16_ints)(struct _mkdata *d, int *rv, int offset, int count);


	/* Return a pointer to an array of ints containing data from 32 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	int *(*get_32_ints)(struct _mkdata *d, int *rv, int offset, int count);

	/* Return a pointer to an array of unsigned ints containing data from 32 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	unsigned int *(*get_u32_uints)(struct _mkdata *d, unsigned int *rv, int offset, int count);


	/* Return a pointer to an array of doubles containing data from 32 bits. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	double *(*get_32_doubles)(struct _mkdata *d, double *rv, int offset, int count);

	/* Return a pointer to an array of doubles containing data from 32 bits, */
	/* with the array filled in reverse order. */
	/* If rv is NULL, the returned value will have been allocated, othewise */
	/* the rv will be returned. Return NULL if out of range. */
	double *(*rget_32_doubles)(struct _mkdata *d, double *rv, int offset, int count);

	/* Destroy ourselves */
	void (*del)(struct _mkdata *d);

}; typedef struct _mkdata mkdata;

/* Constructor. Construct from the EEprom calibration contents */
extern mkdata *new_mkdata(munki *p, unsigned char *buf, int len);

#ifdef __cplusplus
	}
#endif

#define MUNKI_IMP
#endif /* MUNKI_IMP */