From 094535c010320967639e8e86f974d878e80baa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Fri, 1 May 2015 16:13:57 +0200 Subject: Imported Upstream version 1.7.0 --- spectro/i1d3.c | 563 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 372 insertions(+), 191 deletions(-) (limited to 'spectro/i1d3.c') diff --git a/spectro/i1d3.c b/spectro/i1d3.c index cf0fc08..b088728 100644 --- a/spectro/i1d3.c +++ b/spectro/i1d3.c @@ -56,7 +56,10 @@ #include "i1d3.h" #undef PLOT_SPECTRA /* Plot the sensor senitivity spectra */ +#undef PLOT_XYZSPECTRA /* Plot the calibrated sensor senitivity spectra */ #undef SAVE_SPECTRA /* Save the sensor senitivity spectra to "sensors.cmf" */ +#undef SAVE_XYZSPECTRA /* Save the XYZ senitivity spectra to "sensorsxyz.cmf" (scale 1.4) */ +#undef SAVE_STDXYZ /* save 1931 2 degree to stdobsxyz.cmf */ #undef PLOT_REFRESH /* Plot data used to determine refresh rate */ #undef PLOT_UPDELAY /* Plot data used to determine display update delay */ @@ -560,12 +563,13 @@ i1d3_unlock( i1d3_dtype dtype; /* Base type enumerator */ i1d3_dtype stype; /* Sub type enumerator */ } codes[] = { - { "i1Display3 ", { 0xe9622e9f, 0x8d63e133 }, i1d3_disppro, i1d3_disppro }, + { "i1Display3 ", { 0xe9622e9f, 0x8d63e133 }, i1d3_disppro, i1d3_disppro }, { "Colormunki Display ", { 0xe01e6e0a, 0x257462de }, i1d3_munkdisp, i1d3_munkdisp }, - { "i1Display3 ", { 0xcaa62b2c, 0x30815b61 }, i1d3_disppro, i1d3_oem }, - { "i1Display3 ", { 0xa9119479, 0x5b168761 }, i1d3_disppro, i1d3_nec_ssp }, - { "i1Display3 ", { 0x160eb6ae, 0x14440e70 }, i1d3_disppro, i1d3_quato_sh3 }, - { "i1Display3 ", { 0x291e41d7, 0x51937bdd }, i1d3_disppro, i1d3_hp_dreamc }, + { "i1Display3 ", { 0xcaa62b2c, 0x30815b61 }, i1d3_disppro, i1d3_oem }, + { "i1Display3 ", { 0xa9119479, 0x5b168761 }, i1d3_disppro, i1d3_nec_ssp }, + { "i1Display3 ", { 0x160eb6ae, 0x14440e70 }, i1d3_disppro, i1d3_quato_sh3 }, + { "i1Display3 ", { 0x291e41d7, 0x51937bdd }, i1d3_disppro, i1d3_hp_dreamc }, + { "i1Display3 ", { 0xc9bfafe0, 0x02871166 }, i1d3_disppro, i1d3_sc_c6 }, { NULL } }; inst_code ev; @@ -1918,6 +1922,12 @@ i1d3_take_XYZ_measurement( int pos; inst_code ev; + i1d3_mmode mmode = i1d3_adaptive; + + if (IMODETST(p->mode, inst_mode_emis_nonadaptive)) { + mmode = i1d3_frequency; + } + if (IMODETST(p->mode, inst_mode_emis_ambient)) { /* Check that the ambient filter is in place */ @@ -1928,7 +1938,7 @@ i1d3_take_XYZ_measurement( return i1d3_interp_code((inst *)p, I1D3_SPOS_EMIS); /* Best type of reading, including refresh support */ - if ((ev = i1d3_take_emis_measurement(p, i1d3_adaptive, XYZ)) != inst_ok) + if ((ev = i1d3_take_emis_measurement(p, mmode, XYZ)) != inst_ok) return ev; /* Multiply by ambient calibration matrix */ @@ -1944,7 +1954,7 @@ i1d3_take_XYZ_measurement( return i1d3_interp_code((inst *)p, I1D3_SPOS_EMIS); /* Best type of reading, including refresh support */ - if ((ev = i1d3_take_emis_measurement(p, i1d3_adaptive, XYZ)) != inst_ok) + if ((ev = i1d3_take_emis_measurement(p, mmode, XYZ)) != inst_ok) return ev; /* Multiply by current emissive calibration matrix */ @@ -2173,6 +2183,7 @@ i1d3_comp_calmat( icmTranspose3x3(mat, mat); /* Otherwise we compute the least squares calibration matrix. */ + /* (Another possibility is to use a minimization algorithm) */ } else { /* Multiply the [3 x nsamp] XYZ matrix by the [nsamp x 3] RGB */ /* matrix to produce the [3 x 3] design matrix. */ @@ -2202,6 +2213,73 @@ i1d3_comp_calmat( free_dmatrix(sampXYZ, 0, nsamp-1, 0, 3-1); free_dmatrix(sampRGB, 0, nsamp-1, 0, 3-1); +#if defined(PLOT_XYZSPECTRA) || defined(SAVE_XYZSPECTRA) + + /* Compute the calibrated sensor spectra */ + { + int i, j, k; + xspect calcmfs[3]; + double scale; + xspect *xyz[3]; + standardObserver(xyz, icxOT_CIE_1931_2); + + for (j = 0; j < 3; j++) { + XSPECT_COPY_INFO(&calcmfs[j], &RGBcmfs[j]); + } + + /* For each wavelength */ + for (i = 0; i < RGBcmfs[0].spec_n; i++) { + /* Do matrix multiply */ + for (j = 0; j < 3; j++) { + calcmfs[j].spec[i] = 0.0; + for (k = 0; k < 3; k++) { + calcmfs[j].spec[i] += mat[j][k] * RGBcmfs[k].spec[i]; + } + } + } + + /* Scale the X to be 1.0 */ + scale = value_xspect(xyz[1], 555.0)/value_xspect(&calcmfs[1], 555.0); + for (i = 0; i < RGBcmfs[0].spec_n; i++) { + for (j = 0; j < 3; j++) { + calcmfs[j].spec[i] *= scale; + } + } + + +#ifdef PLOT_XYZSPECTRA + { + double xx[XSPECT_MAX_BANDS]; + double y1[XSPECT_MAX_BANDS]; + double y2[XSPECT_MAX_BANDS]; + double y3[XSPECT_MAX_BANDS]; + + for (i = 0; i < calcmfs[0].spec_n; i++) { + xx[i] = XSPECT_XWL(&calcmfs[0], i); + y1[i] = calcmfs[0].spec[i]; + y2[i] = calcmfs[1].spec[i]; + y3[i] = calcmfs[2].spec[i]; + } + printf("The calibrated sensor sensitivities\n"); + do_plot(xx, y1, y2, y3, calcmfs[0].spec_n); + } +#endif /* PLOT_XYZSPECTRA */ +#ifdef SAVE_XYZSPECTRA /* Save the default XYZ senitivity spectra to "sensorsxyz.cmf" */ + write_nxspect("sensorsxyz.cmf", calcmfs, 3, 0); +#endif + } +#endif /* PLOT_XYZSPECTRA || SAVE_XYZSPECTRA */ +#ifdef SAVE_STDXYZ + { + xspect *xyz[3], xyzl[3]; + standardObserver(xyz, icxOT_CIE_1931_2); + xyzl[0] = *xyz[0]; + xyzl[1] = *xyz[1]; + xyzl[2] = *xyz[2]; + write_nxspect("stdobsxyz.cmf", xyzl, 3, 0); + } +#endif /* SAVE_STDXYZ */ + return inst_ok; } @@ -2232,23 +2310,23 @@ i1d3_set_speccal( return inst_ok; } - /* Preset the calibration to a matrix. The spectral type is set to none */ static inst_code i1d3_set_matcal(i1d3 *p, double mtx[3][3]) { + + if (p->samples != NULL) + free(p->samples); + p->samples = NULL; + p->nsamp = 0; + if (mtx == NULL) icmSetUnity3x3(p->ccmat); - else { - if (p->cbid == 0) { - a1loge(p->log, 1, "i1d3: can't set col_cor_mat over non-base display type\n"); - return inst_wrong_setup; - } + else icmCpy3x3(p->ccmat, mtx); - } + return inst_ok; } - /* Set the calibration to the currently preset type */ static inst_code i1d3_set_cal(i1d3 *p) { @@ -2269,39 +2347,45 @@ i1d3_set_cal(i1d3 *p) { icmSetUnity3x3(p->ccmat); /* to be sure to be sure... */ - } else { /* Assume matrix */ + } else { /* Assume default spectral samples, + possible matrix */ /* Create the default MIbLSr calibration matrix */ if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver, p->sens, p->sens, 3)) != inst_ok) { - a1logd(p->log, 1, "i1d3_set_disp_type: comp_calmat dflt failed with rv = 0x%x\n",ev); + a1logd(p->log, 1, "i1d3_set_cal: comp_calmat dflt failed with rv = 0x%x\n",ev); return ev; } /* Use MIbLSr for ambient */ if ((ev = i1d3_comp_calmat(p, p->ambi_cal, p->obType, p->custObserver, p->ambi, p->ambi, 3)) != inst_ok) return ev; + + /* We assume any ccmat has/will be set by caller */ } if (p->log->debug >= 4) { - a1logd(p->log,4,"Emissive matrix = %f %f %f\n", - p->emis_cal[0][0], p->emis_cal[0][1], p->emis_cal[0][2]); - a1logd(p->log,4," %f %f %f\n", - p->emis_cal[1][0], p->emis_cal[1][1], p->emis_cal[1][2]); - a1logd(p->log,4," %f %f %f\n\n", - p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]); - a1logd(p->log,4,"Ambient matrix = %f %f %f\n", - p->ambi_cal[0][0], p->ambi_cal[0][1], p->ambi_cal[0][2]); - a1logd(p->log,4," %f %f %f\n", - p->ambi_cal[1][0], p->ambi_cal[1][1], p->ambi_cal[1][2]); - a1logd(p->log,4," %f %f %f\n\n", - p->ambi_cal[2][0], p->ambi_cal[2][1], p->ambi_cal[2][2]); + if (IMODETST(p->mode, inst_mode_emis_ambient)) { + a1logd(p->log,4,"Ambient matrix = %f %f %f\n", + p->ambi_cal[0][0], p->ambi_cal[0][1], p->ambi_cal[0][2]); + a1logd(p->log,4," %f %f %f\n", + p->ambi_cal[1][0], p->ambi_cal[1][1], p->ambi_cal[1][2]); + a1logd(p->log,4," %f %f %f\n\n", + p->ambi_cal[2][0], p->ambi_cal[2][1], p->ambi_cal[2][2]); + } else { + a1logd(p->log,4,"Emissive matrix = %f %f %f\n", + p->emis_cal[0][0], p->emis_cal[0][1], p->emis_cal[0][2]); + a1logd(p->log,4," %f %f %f\n", + p->emis_cal[1][0], p->emis_cal[1][1], p->emis_cal[1][2]); + a1logd(p->log,4," %f %f %f\n\n", + p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]); + } a1logd(p->log,4,"ccmat = %f %f %f\n", p->ccmat[0][0], p->ccmat[0][1], p->ccmat[0][2]); a1logd(p->log,4," %f %f %f\n", p->ccmat[1][0], p->ccmat[1][1], p->ccmat[1][2]); a1logd(p->log,4," %f %f %f\n\n", p->ccmat[2][0], p->ccmat[2][1], p->ccmat[2][2]); + a1logd(p->log,4,"ucbid = %d, cbid = %d\n",p->ucbid, p->cbid); a1logd(p->log,4,"\n"); } @@ -2381,39 +2465,16 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { return inst_ok; } -// Print bytes as hex to debug log */ -static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int len) { - int i, j, ii; - char oline[200] = { '\000' }, *bp = oline; - for (i = j = 0; i < len; i++) { - if ((i % 16) == 0) - bp += sprintf(bp,"%s%04x:",pfx,i); - bp += sprintf(bp," %02x",buf[i]); - if ((i+1) >= len || ((i+1) % 16) == 0) { - for (ii = i; ((ii+1) % 16) != 0; ii++) - bp += sprintf(bp," "); - bp += sprintf(bp," "); - for (; j <= i; j++) { - if (!(buf[j] & 0x80) && isprint(buf[j])) - bp += sprintf(bp,"%c",buf[j]); - else - bp += sprintf(bp,"."); - } - bp += sprintf(bp,"\n"); - a1logd(log,0, "%s", oline); - bp = oline; - } - } -} - /* Diffuser position thread. */ /* Poll the instrument at 100msec intervals */ -int i1d3_diff_thread(void *pp) { +static int i1d3_diff_thread(void *pp) { int nfailed = 0; i1d3 *p = (i1d3 *)pp; inst_code rv = inst_ok; a1logd(p->log,3,"Diffuser thread started\n"); - for (nfailed = 0; nfailed < 5;) { +// for (nfailed = 0; nfailed < 5;) + /* Try indefinitely, in case instrument is put to sleep */ + for (;;) { int pos; /* Don't get diffpos if we're doing something else that */ @@ -2503,7 +2564,7 @@ i1d3_init_inst(inst *pp) { return ev; if (p->log->debug >= 8) { a1logd(p->log, 8, "Internal EEPROM:\n"); - dump_bytes(p->log, " ", buf, 256); + adump_bytes(p->log, " ", buf, 0, 256); } /* Decode the Internal EEPRom */ if ((ev = i1d3_decode_intEE(p, buf)) != inst_ok) @@ -2513,7 +2574,7 @@ i1d3_init_inst(inst *pp) { return ev; if (p->log->debug >= 8) { a1logd(p->log, 8, "External EEPROM:\n"); - dump_bytes(p->log, " ", buf, 8192); + adump_bytes(p->log, " ", buf, 0, 8192); } /* Decode the External EEPRom */ if ((ev = i1d3_decode_extEE(p, buf)) != inst_ok) @@ -2656,10 +2717,14 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ } } + /* Read the XYZ value */ - if ((rv = i1d3_take_XYZ_measurement(p, val->XYZ)) != inst_ok) + rv = i1d3_take_XYZ_measurement(p, val->XYZ); + + if (rv != inst_ok) return rv; + /* This may not change anything since instrument may clamp */ if (clamp) icmClamp3(val->XYZ, val->XYZ); @@ -2696,21 +2761,55 @@ double *ref_rate) { if (p->dtype == i1d3_munkdisp) return inst_unsupported; + if (ref_rate != NULL) + *ref_rate = 0.0; + if ((rv = i1d3_imp_measure_refresh(p, ref_rate, NULL)) != inst_ok) return rv; - if (*ref_rate == 0.0) + + if (ref_rate != NULL && *ref_rate == 0.0) return inst_misread; return inst_ok; } +/* Make a possible change of the refresh mode */ +static void update_refmode(i1d3 *p, int refrmode) { + + if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */ + refrmode = 0; + } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) { + refrmode = 1; + } + + if (p->refrmode != refrmode) { + p->rrset = 0; /* This is a hint we may have swapped displays */ + p->refrvalid = 0; + } + p->refrmode = refrmode; + + /* default before any refresh rate calibration */ + if (p->refrmode) { + p->inttime = 2.0 * p->dinttime; /* Double integration time */ + } else { + p->inttime = p->dinttime; /* Normal integration time */ + } + if (p->omininttime != 0.0) + p->inttime = p->omininttime; /* Override */ + p->mininttime = p->inttime; /* Current value */ +} + +static inst_code set_base_disp_type(i1d3 *p, int cbid); + /* Insert a colorimetric correction matrix in the instrument XYZ readings */ /* This is only valid for colorimetric instruments. */ /* To remove the matrix, pass NULL for the matrix. */ -inst_code i1d3_col_cor_mat( +static inst_code i1d3_col_cor_mat( inst *pp, +disptech dtech, /* Use disptech_unknown if not known */ \ +int cbid, /* Calibration display type base ID, 1 if unknown */\ double mtx[3][3] ) { i1d3 *p = (i1d3 *)pp; @@ -2723,9 +2822,18 @@ double mtx[3][3] if (!p->inited) return inst_no_init; + if ((ev = set_base_disp_type(p, cbid)) != inst_ok) + return ev; + if ((ev = i1d3_set_matcal(p, mtx)) != inst_ok) return ev; + p->dtech = dtech; + p->cbid = 0; + + /* Effective refresh mode may change */ + update_refmode(p, disptech_get_id(dtech)->refr); + return i1d3_set_cal(p); } @@ -2733,8 +2841,9 @@ double mtx[3][3] /* instrumen calibration. */ /* This is only valid for colorimetric instruments. */ /* To set calibration back to default, pass NULL for sets. */ -inst_code i1d3_col_cal_spec_set( +static inst_code i1d3_col_cal_spec_set( inst *pp, +disptech dtech, xspect *sets, int no_sets ) { @@ -2748,6 +2857,9 @@ int no_sets if (!p->inited) return inst_no_init; + p->dtech = dtech; + p->cbid = 0; + if (sets == NULL || no_sets <= 0) { if ((ev = set_default_disp_type(p)) != inst_ok) { return ev; @@ -2756,8 +2868,10 @@ int no_sets if ((ev = i1d3_set_speccal(p, sets, no_sets)) != inst_ok) return ev; + p->ucbid = 0; /* We're using external samples */ ev = i1d3_set_cal(p); } + update_refmode(p, disptech_get_id(dtech)->refr); return ev; } @@ -2784,7 +2898,7 @@ static inst_code i1d3_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_ty } /* Request an instrument calibration. */ -inst_code i1d3_calibrate( +static inst_code i1d3_calibrate( inst *pp, inst_cal_type *calt, /* Calibration type to do/remaining */ inst_cal_cond *calc, /* Current condition/desired condition */ @@ -2866,22 +2980,27 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ return inst_ok; } -/* Measure a display update delay. It is assumed that a */ -/* white to black change has been made to the displayed color, */ +/* Measure a display update delay. It is assumed that */ +/* white_stamp(init) has been called, and then a */ +/* black to white change has been made to the displayed color, */ /* and this will measure the time it took for the update to */ -/* be noticed by the instrument, up to 0.6 seconds. */ +/* be noticed by the instrument, up to 2.0 seconds. */ +/* (It is assumed that white_change() will be called at the time the patch */ +/* changes color.) */ /* inst_misread will be returned on failure to find a transition to black. */ -#define NDSAMPS 200 +#define NDSAMPS 400 #define DINTT 0.005 /* Too short hits blanking */ -#define NDMXTIME 1.0 /* Maximum time to take */ +#define NDMXTIME 2.0 /* Maximum time to take */ -inst_code i1d3_meas_delay( +static inst_code i1d3_meas_delay( inst *pp, -int *msecdelay) { /* Return the number of msec */ +int *pdispmsec, /* Return display update delay in msec */ +int *pinstmsec) { /* Return instrument reaction time in msec */ i1d3 *p = (i1d3 *)pp; inst_code ev; int i, j, k; - double sutime, putime, cutime, eutime; + double putime, cutime; + int mtachdel; struct { double sec; double rgb[3]; @@ -2890,9 +3009,19 @@ int *msecdelay) { /* Return the number of msec */ int ndsamps; double inttime = DINTT; double stot, etot, del, thr; - double etime; + double stime, etime; int isdeb; int isth; + int dispmsec, instmsec; + + if (pinstmsec != NULL) + *pinstmsec = 0; + + if (!p->gotcoms) + return inst_no_coms; + + if (!p->inited) + return inst_no_init; if (usec_time() < 0.0) { a1loge(p->log, inst_internal_error, "i1d3_meas_delay: No high resolution timers\n"); @@ -2906,8 +3035,7 @@ int *msecdelay) { /* Return the number of msec */ p->th_en = 0; /* Read the samples */ - sutime = usec_time(); - putime = (usec_time() - sutime) / 1000000.0; + putime = usec_time() / 1000000.0; for (i = 0; i < NDSAMPS; i++) { if ((ev = i1d3_freq_measure(p, &inttime, samp[i].rgb)) != inst_ok) { a1logd(p->log, 1, "i1d3_meas_delay: measurement failed\n"); @@ -2915,7 +3043,7 @@ int *msecdelay) { /* Return the number of msec */ p->th_en = isth; return ev; } - cutime = (usec_time() - sutime) / 1000000.0; + cutime = usec_time() / 1000000.0; samp[i].sec = 0.5 * (putime + cutime); /* Mean of before and after stamp */ putime = cutime; samp[i].tot = samp[i].rgb[0] + samp[i].rgb[1] + samp[i].rgb[2]; @@ -2932,36 +3060,23 @@ int *msecdelay) { /* Return the number of msec */ a1logd(p->log, 1, "i1d3_meas_delay: No measurement samples returned in time\n"); return inst_internal_error; } - -#ifdef PLOT_UPDELAY - /* Plot the raw sensor values */ - { - double xx[NDSAMPS]; - double y1[NDSAMPS]; - double y2[NDSAMPS]; - double y3[NDSAMPS]; - double y4[NDSAMPS]; - for (i = 0; i < ndsamps; i++) { - xx[i] = samp[i].sec; - y1[i] = samp[i].rgb[0]; - y2[i] = samp[i].rgb[1]; - y3[i] = samp[i].rgb[2]; - y4[i] = samp[i].tot; - //printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].tot); - } - printf("Display update delay measure sensor values and time (sec)\n"); - do_plot6(xx, y1, y2, y3, y4, NULL, NULL, ndsamps); + if (p->whitestamp < 0.0) { + a1logd(p->log, 1, "i1d3_meas_delay: White transition wasn't timestamped\n"); + return inst_internal_error; } -#endif + + /* Set the times to be white transition relative */ + for (i = 0; i < ndsamps; i++) + samp[i].sec -= p->whitestamp / 1000000.0; /* Over the first 100msec, locate the maximum value */ - etime = samp[ndsamps-1].sec; + stime = samp[0].sec; stot = -1e9; for (i = 0; i < ndsamps; i++) { if (samp[i].tot > stot) stot = samp[i].tot; - if (samp[i].sec > 0.1) + if ((samp[i].sec - stime) > 0.1) break; } @@ -2975,33 +3090,72 @@ int *msecdelay) { /* Return the number of msec */ break; } - del = stot - etot; - thr = etot + 0.2 * del; /* 20% of transition threshold */ + del = etot - stot; + thr = stot + 0.2 * del; /* 20% of transition threshold */ #ifdef PLOT_UPDELAY a1logd(p->log, 0, "i1d3_meas_delay: start tot %f end tot %f del %f, thr %f\n", stot, etot, del, thr); #endif +#ifdef PLOT_UPDELAY + /* Plot the raw sensor values */ + { + double xx[NDSAMPS]; + double y1[NDSAMPS]; + double y2[NDSAMPS]; + double y3[NDSAMPS]; + double y4[NDSAMPS]; + + for (i = 0; i < ndsamps; i++) { + xx[i] = samp[i].sec; + y1[i] = samp[i].rgb[0]; + y2[i] = samp[i].rgb[1]; + y3[i] = samp[i].rgb[2]; + y4[i] = samp[i].tot; + //printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].tot); + } + printf("Display update delay measure sensor values and time (sec)\n"); + do_plot6(xx, y1, y2, y3, y4, NULL, NULL, ndsamps); + } +#endif + /* Check that there has been a transition */ if (del < 10.0) { - a1logd(p->log, 1, "i1d3_meas_delay: can't detect change from white to black\n"); + a1logd(p->log, 1, "i1d3_meas_delay: can't detect change from black to white\n"); return inst_misread; } - /* Working from the end, locate the time at which the level was above the threshold */ - for (i = ndsamps-1; i >= 0; i--) { + /* Working from the start, locate the time at which the level was above the threshold */ + for (i = 0; i < (ndsamps-1); i++) { if (samp[i].tot > thr) break; } - if (i < 0) /* Assume the update was so fast that we missed it */ - i = 0; a1logd(p->log, 2, "i1d3_meas_delay: stoped at sample %d time %f\n",i,samp[i].sec); - *msecdelay = (int)(samp[i].sec * 1000.0 + 0.5); + /* Compute overall delay */ + dispmsec = (int)(samp[i].sec * 1000.0 + 0.5); + instmsec = 0; + +#ifdef PLOT_UPDELAY + a1logd(p->log, 0, "i1d3_meas_delay: disp %d, inst %d msec\n",dispmsec,instmsec); +#else + a1logd(p->log, 2, "i1d3_meas_delay: disp %d, inst %d msec\n",dispmsec,instmsec); +#endif + + if (dispmsec < 0) /* This can happen if the patch generator delays it's return */ + dispmsec = 0; + + if (pdispmsec != NULL) + *pdispmsec = dispmsec; + + if (pinstmsec != NULL) + *pinstmsec = instmsec; #ifdef PLOT_UPDELAY - a1logd(p->log, 0, "i1d3_meas_delay: returning %d msec\n",*msecdelay); + a1logd(p->log, 0, "i1d3_meas_delay: returning %d & %d msec\n",dispmsec,instmsec); +#else + a1logd(p->log, 2, "i1d3_meas_delay: returning %d & %d msec\n",dispmsec,instmsec); #endif return inst_ok; @@ -3010,6 +3164,23 @@ int *msecdelay) { /* Return the number of msec */ #undef DINTT #undef NDMXTIME +/* Timestamp the white patch change during meas_delay() */ +/* Initialise the whitestap to invalid if init nz */ +static inst_code i1d3_white_change( +inst *pp, int init) { + i1d3 *p = (i1d3 *)pp; + + if (init) + p->whitestamp = -1.0; + else { + if ((p->whitestamp = usec_time()) < 0.0) { + a1loge(p->log, inst_internal_error, "i1d3_wite_change: No high resolution timers\n"); + return inst_internal_error; + } + } + return inst_ok; +} + /* Return the last calibrated refresh rate in Hz. Returns: */ static inst_code i1d3_get_refr_rate(inst *pp, double *ref_rate @@ -3149,6 +3320,9 @@ i1d3_interp_code(inst *pp, int ec) { case I1D3_OK: return inst_ok; + + case I1D3_INTERNAL_ERROR: + return inst_internal_error | ec; case I1D3_BAD_MEM_ADDRESS: case I1D3_BAD_MEM_LENGTH: @@ -3242,7 +3416,7 @@ i1d3_del(inst *pp) { } /* Return the instrument capabilities */ -void i1d3_capabilities(inst *pp, +static void i1d3_capabilities(inst *pp, inst_mode *pcap1, inst2_capability *pcap2, inst3_capability *pcap3) { @@ -3255,6 +3429,7 @@ inst3_capability *pcap3) { | inst_mode_emis_ambient | inst_mode_emis_refresh_ovd /* (allow override ccmx & ccss mode) */ | inst_mode_emis_norefresh_ovd + | inst_mode_emis_nonadaptive | inst_mode_colorimeter ; @@ -3284,6 +3459,7 @@ inst3_capability *pcap3) { } /* Return current or given configuration available measurement modes. */ +/* NOTE that conf_ix values shoudn't be changed, as it is used as a persistent key */ static inst_code i1d3_meas_config( inst *pp, inst_mode *mmodes, @@ -3334,7 +3510,7 @@ int *conf_ix } /* Check device measurement mode */ -inst_code i1d3_check_mode(inst *pp, inst_mode m) { +static inst_code i1d3_check_mode(inst *pp, inst_mode m) { i1d3 *p = (i1d3 *)pp; inst_mode cap; @@ -3360,7 +3536,7 @@ inst_code i1d3_check_mode(inst *pp, inst_mode m) { } /* Set device measurement mode */ -inst_code i1d3_set_mode(inst *pp, inst_mode m) { +static inst_code i1d3_set_mode(inst *pp, inst_mode m) { i1d3 *p = (i1d3 *)pp; int refrmode; inst_code ev; @@ -3371,39 +3547,19 @@ inst_code i1d3_set_mode(inst *pp, inst_mode m) { p->mode = m; /* Effective refresh mode may change */ - refrmode = p->refrmode; - if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */ - refrmode = 0; - } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) { - refrmode = 1; - } - - if (p->refrmode != refrmode) { - p->rrset = 0; /* This is a hint we may have swapped displays */ - p->refrvalid = 0; - } - p->refrmode = refrmode; - - /* default before any refresh rate calibration */ - if (p->refrmode) { - p->inttime = 2.0 * p->dinttime; /* Double default integration time */ - } else { - p->inttime = p->dinttime; /* Normal integration time */ - } - if (p->omininttime != 0.0) - p->inttime = p->omininttime; /* Override */ - p->mininttime = p->inttime; /* Current value */ + update_refmode(p, p->refrmode); return inst_ok; } -inst_disptypesel i1d3_disptypesel[3] = { +static inst_disptypesel i1d3_disptypesel[3] = { { inst_dtflags_default, 1, "nl", "Non-Refresh display", 0, + disptech_lcd, 0 }, { @@ -3412,6 +3568,7 @@ inst_disptypesel i1d3_disptypesel[3] = { "rc", /* sel */ "Refresh display", /* desc */ 1, /* refr */ + disptech_crt, /* disptype */ 1 /* ix */ }, { @@ -3420,6 +3577,7 @@ inst_disptypesel i1d3_disptypesel[3] = { "", "", 0, + disptech_none, 0 } }; @@ -3469,44 +3627,62 @@ static inst_code set_disp_type(i1d3 *p, inst_disptypesel *dentry) { int refrmode; p->icx = dentry->ix; + p->dtech = dentry->dtech; p->cbid = dentry->cbid; - refrmode = dentry->refr; - if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */ - refrmode = 0; - } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) { - refrmode = 1; - } - - if (p->refrmode != refrmode) - p->rrset = 0; /* This is a hint we may have swapped displays */ - p->refrmode = refrmode; - - if (p->refrmode) { - p->inttime = 2.0 * p->dinttime; /* Double integration time */ - } else { - p->inttime = p->dinttime; /* Normal integration time */ - } - if (p->omininttime != 0.0) - p->inttime = p->omininttime; /* Override */ - p->mininttime = p->inttime; /* Current value */ + update_refmode(p, dentry->refr); if (dentry->flags & inst_dtflags_ccss) { /* Spectral sample */ if ((ev = i1d3_set_speccal(p, dentry->sets, dentry->no_sets)) != inst_ok) return ev; + p->ucbid = dentry->cbid; /* This is underying base if dentry is base selection */ - } else { /* Matrix */ + } else { - if (dentry->flags & inst_dtflags_ccmx) { + if (dentry->flags & inst_dtflags_ccmx) { /* Matrix */ + if ((ev = set_base_disp_type(p, dentry->cc_cbid)) != inst_ok) + return ev; if ((ev = i1d3_set_matcal(p, dentry->mat)) != inst_ok) return ev; - } else { + p->cbid = 0; /* Matrix will be an override of cbid set in i1d3_set_cal() */ + + } else { /* Native */ if ((ev = i1d3_set_matcal(p, NULL)) != inst_ok) /* Noop */ return ev; + p->ucbid = dentry->cbid; /* This is underying base if dentry is base selection */ } } - return i1d3_set_cal(p); + return i1d3_set_cal(p); /* Make it happen */ +} + +/* Set the display type */ +static inst_code i1d3_set_disptype(inst *pp, int ix) { + i1d3 *p = (i1d3 *)pp; + inst_code ev; + inst_disptypesel *dentry; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if (p->dtlist == NULL) { + if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist, + i1d3_disptypesel, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok) + return ev; + } + + if (ix < 0 || ix >= p->ndtlist) + return inst_unsupported; + + dentry = &p->dtlist[ix]; + + if ((ev = set_disp_type(p, dentry)) != inst_ok) { + return ev; + } + + return inst_ok; } /* Setup the default display type */ @@ -3535,35 +3711,55 @@ static inst_code set_default_disp_type(i1d3 *p) { return inst_ok; } -/* Set the display type */ -static inst_code i1d3_set_disptype(inst *pp, int ix) { - i1d3 *p = (i1d3 *)pp; +/* Setup the display type to the given base type */ +static inst_code set_base_disp_type(i1d3 *p, int cbid) { inst_code ev; - inst_disptypesel *dentry; - - if (!p->gotcoms) - return inst_no_coms; - if (!p->inited) - return inst_no_init; + int i; + if (cbid == 0) { + a1loge(p->log, 1, "i1d3 set_base_disp_type: can't set base display type of 0\n"); + return inst_wrong_setup; + } if (p->dtlist == NULL) { - if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist, - i1d3_disptypesel, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok) + if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist, + i1d3_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok) return ev; } - if (ix < 0 || ix >= p->ndtlist) - return inst_unsupported; - - dentry = &p->dtlist[ix]; - - if ((ev = set_disp_type(p, dentry)) != inst_ok) { + for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) { + if (!(p->dtlist[i].flags & inst_dtflags_ccmx) /* Prevent infinite recursion */ + && p->dtlist[i].cbid == cbid) + break; + } + if (p->dtlist[i].flags & inst_dtflags_end) { + a1loge(p->log, 1, "set_base_disp_type: failed to find cbid %d!\n",cbid); + return inst_wrong_setup; + } + if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) { return ev; } return inst_ok; } +/* Get the disptech and other corresponding info for the current */ +/* selected display type. Returns disptype_unknown by default. */ +/* Because refrmode can be overridden, it may not match the refrmode */ +/* of the dtech. (Pointers may be NULL if not needed) */ +static inst_code i1d3_get_disptechi( +inst *pp, +disptech *dtech, +int *refrmode, +int *cbid) { + i1d3 *p = (i1d3 *)pp; + if (dtech != NULL) + *dtech = p->dtech; + if (refrmode != NULL) + *refrmode = p->refrmode; + if (cbid != NULL) + *cbid = p->cbid; + return inst_ok; +} /* * set or reset an optional mode @@ -3589,24 +3785,6 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) if (!p->inited) return inst_no_init; - /* Get the display type information */ - if (m == inst_opt_get_dtinfo) { - va_list args; - int *refrmode, *cbid; - - va_start(args, m); - refrmode = va_arg(args, int *); - cbid = va_arg(args, int *); - va_end(args); - - if (refrmode != NULL) - *refrmode = p->refrmode; - if (cbid != NULL) - *cbid = p->cbid; - - return inst_ok; - } - /* Get the current minimum integration time */ if (m == inst_opt_get_min_int_time) { va_list args; @@ -3689,7 +3867,7 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) a1logd(p->log, 4, "inst_opt_set_ccss_obs\n"); - return i1d3_set_cal(p); /* Recompute calibration */ + return i1d3_set_cal(p); /* Recompute calibration if spectral sample */ } /* Operate the LEDS */ @@ -3814,6 +3992,7 @@ extern i1d3 *new_i1d3(icoms *icom, instType itype) { p->set_mode = i1d3_set_mode; p->get_disptypesel = i1d3_get_disptypesel; p->set_disptype = i1d3_set_disptype; + p->get_disptechi = i1d3_get_disptechi; p->get_set_opt = i1d3_get_set_opt; p->read_sample = i1d3_read_sample; p->read_refrate = i1d3_read_refrate; @@ -3822,6 +4001,7 @@ extern i1d3 *new_i1d3(icoms *icom, instType itype) { p->get_n_a_cals = i1d3_get_n_a_cals; p->calibrate = i1d3_calibrate; p->meas_delay = i1d3_meas_delay; + p->white_change = i1d3_white_change; p->get_refr_rate = i1d3_get_refr_rate; p->set_refr_rate = i1d3_set_refr_rate; p->interp_error = i1d3_interp_error; @@ -3833,6 +4013,7 @@ extern i1d3 *new_i1d3(icoms *icom, instType itype) { amutex_init(p->lock); icmSetUnity3x3(p->ccmat); + p->dtech = disptech_unknown; return p; } -- cgit v1.2.3