diff options
Diffstat (limited to 'spectro/i1d3.c')
-rw-r--r-- | spectro/i1d3.c | 732 |
1 files changed, 508 insertions, 224 deletions
diff --git a/spectro/i1d3.c b/spectro/i1d3.c index 53b2f0c..cf0fc08 100644 --- a/spectro/i1d3.c +++ b/spectro/i1d3.c @@ -7,7 +7,7 @@ * Author: Graeme W. Gill * Date: 28/7/2011 * - * Copyright 2006 - 2013, Graeme W. Gill + * Copyright 2006 - 2014, Graeme W. Gill * All rights reserved. * * (Based on huey.c) @@ -58,6 +58,14 @@ #undef PLOT_SPECTRA /* Plot the sensor senitivity spectra */ #undef SAVE_SPECTRA /* Save the sensor senitivity spectra to "sensors.cmf" */ #undef PLOT_REFRESH /* Plot data used to determine refresh rate */ +#undef PLOT_UPDELAY /* Plot data used to determine display update delay */ + +#undef DEBUG_TWEAKS /* Allow environment variable tweaks to int time etc. */ +/* I1D3_MIN_REF_QUANT_TIME in seconds. Default 0.05 */ +/* I1D3_MIN_INT_TIME in seconds. Default 0.4 for refresh displays */ + +#define I1D3_MEAS_TIMEOUT 40.0 /* Longest reading timeout in seconds */ + /* Typically 20.0 is the maximum needed. */ static inst_code i1d3_interp_code(inst *pp, int ec); static inst_code i1d3_check_unlock(i1d3 *p); @@ -145,7 +153,7 @@ static char *inst_desc(i1Disp3CC cc) { case i1d3_rd_sensor: return "ReadAnalogSensor"; case i1d3_get_diff: - return "GetDiffuserPositio"; + return "GetDiffuserPosition"; case i1d3_lockchal: return "GetLockChallenge"; case i1d3_lockresp: @@ -186,8 +194,14 @@ i1d3_command( if (cmd == 0x00) send[1] = (cc & 0xff); /* Minor command */ - if (!nd) a1logd(p->log, 4, "i1d3_command: Sending cmd '%s' args '%s'\n", - inst_desc(cc), icoms_tohex(send, 8)); + if (!nd) { + if (cc == i1d3_lockresp) + a1logd(p->log, 4, "i1d3_command: Sending cmd '%s' args '%s'\n", + inst_desc(cc), icoms_tohex(send, 64)); + else + a1logd(p->log, 4, "i1d3_command: Sending cmd '%s' args '%s'\n", + inst_desc(cc), icoms_tohex(send, 8)); + } if (p->icom->port_type(p->icom) == icomt_hid) { se = p->icom->hid_write(p->icom, send, 64, &wbytes, to); @@ -196,6 +210,12 @@ i1d3_command( } if (se != 0) { if (!nd) a1logd(p->log, 1, "i1d3_command: Command send failed with ICOM err 0x%x\n",se); + /* Flush any response */ + if (ishid) { + p->icom->hid_read(p->icom, recv, 64, &rbytes, to); + } else { + p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, to); + } amutex_unlock(p->lock); return i1d3_interp_code((inst *)p, I1D3_COMS_FAIL); } @@ -213,7 +233,7 @@ i1d3_command( p->icom->hid_read(p->icom, recv, 64, &rbytes, to); } else { p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, to); - } + } amutex_unlock(p->lock); return rv; } @@ -228,6 +248,12 @@ i1d3_command( } if (se != 0) { if (!nd) a1logd(p->log, 1, "i1d3_command: response read failed with ICOM err 0x%x\n",se); + /* Flush any extra response, in case responses are out of sync */ + if (ishid) { + p->icom->hid_read(p->icom, recv, 64, &rbytes, 0.2); + } else { + p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, 0.2); + } amutex_unlock(p->lock); return i1d3_interp_code((inst *)p, I1D3_COMS_FAIL); } @@ -237,12 +263,13 @@ i1d3_command( } /* The first byte returned seems to be a command result error code. */ - /* The second byte is usually the command code being echo'd back, but not always. */ if (rv == inst_ok && recv[0] != 0x00) { if (!nd) a1logd(p->log, 1, "i1d3_command: status byte != 00 = 0x%x\n",recv[0]); rv = i1d3_interp_code((inst *)p, I1D3_BAD_RET_STAT); } + /* The second byte is usually the command code being echo'd back, but not always. */ + /* ie., get i1d3_get_diff returns the status instead. */ if (rv == inst_ok) { if (cc != i1d3_get_diff) { if (recv[1] != cmd) { @@ -250,31 +277,35 @@ i1d3_command( cmd,recv[1]); rv = i1d3_interp_code((inst *)p, I1D3_BAD_RET_CMD); } + } else { /* i1d3_get_diff as special case */ + int i; + for (i = 2; i < 64; i++) { + if (recv[i] != 0x00) { + if (!nd) a1logd(p->log, 1, "i1d3_command: i1d3_get_diff not zero filled\n"); + rv = i1d3_interp_code((inst *)p, I1D3_BAD_RET_CMD); + break; + } + } } } - if (!nd) a1logd(p->log, 4, "i1d3_command: got '%s' ICOM err 0x%x\n",icoms_tohex(recv, 14),ua); - - amutex_unlock(p->lock); - return rv; -} - -/* Read a packet and time out or throw it away */ -static inst_code -i1d3_dummy_read( - i1d3 *p /* i1d3 object */ -) { - unsigned char buf[64]; - int rbytes; /* bytes read from ep */ - int se, rv = inst_ok; - int ishid = p->icom->port_type(p->icom) == icomt_hid; + if (!nd) { + if (cc == i1d3_lockchal) + a1logd(p->log, 4, "i1d3_command: got '%s' ICOM err 0x%x\n",icoms_tohex(recv, 64),ua); + else + a1logd(p->log, 4, "i1d3_command: got '%s' ICOM err 0x%x\n",icoms_tohex(recv, 14),ua); + } - if (ishid) { - se = p->icom->hid_read(p->icom, buf, 64, &rbytes, 0.1); - } else { - se = p->icom->usb_read(p->icom, NULL, 0x81, buf, 64, &rbytes, 0.1); - } + if (rv != inst_ok) { + /* Flush any extra response, in case responses are out of sync */ + if (ishid) { + p->icom->hid_read(p->icom, recv, 64, &rbytes, 0.2); + } else { + p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, 0.2); + } + } + amutex_unlock(p->lock); return rv; } @@ -534,19 +565,26 @@ i1d3_unlock( { "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 }, { NULL } }; inst_code ev; - int ix; + int ix, nix; a1logd(p->log, 2, "i1d3_unlock: called\n"); + /* Count the keys */ + for (nix = 0;;nix++) { + if (codes[nix].pname == NULL) + break; + } + /* Until we give up */ for (ix = 0;;ix++) { /* If we've run out of unlock keys */ if (codes[ix].pname == NULL) { - a1logd(p->log, 1, "i1d3: Unknown lock code. Please contact ArgyllCMS for help\n"); + a1logw(p->log, "i1d3: Unknown lock code. Please contact ArgyllCMS for help\n"); return i1d3_interp_code((inst *)p, I1D3_UNKNOWN_UNLOCK); } @@ -559,6 +597,7 @@ i1d3_unlock( // a1logd(p->log, 3, "i1d3_unlock: Trying unlock key 0x%08x 0x%08x\n", // codes[ix].key[0], codes[ix].key[1]); + a1logd(p->log, 3, "i1d3_unlock: Trying unlock key %d/%d\n", ix+1, nix); p->dtype = codes[ix].dtype; p->stype = codes[ix].stype; @@ -734,7 +773,7 @@ i1d3_freq_measure( todev[23] = 0; /* Unknown parameter, always 0 */ - if ((ev = i1d3_command(p, i1d3_measure1, todev, fromdev, 20.0, 0)) != inst_ok) + if ((ev = i1d3_command(p, i1d3_measure1, todev, fromdev, I1D3_MEAS_TIMEOUT, 0)) != inst_ok) return ev; rgb[0] = (double)buf2uint(fromdev + 2); @@ -771,7 +810,7 @@ i1d3_period_measure( todev[7] = (unsigned char)mask; todev[8] = 0; /* Unknown parameter, always 0 */ - if ((ev = i1d3_command(p, i1d3_measure2, todev, fromdev, 20.0, 0)) != inst_ok) + if ((ev = i1d3_command(p, i1d3_measure2, todev, fromdev, I1D3_MEAS_TIMEOUT, 0)) != inst_ok) return ev; rgb[0] = (double)buf2uint(fromdev + 2); @@ -911,6 +950,7 @@ i1d3_imp_measure_refresh( int npeaks = 0; /* Number of peaks */ double pval; /* Period value */ int isdeb; + int isth; if (prefrate != NULL) *prefrate = 0.0; @@ -922,14 +962,17 @@ i1d3_imp_measure_refresh( return inst_internal_error; } - /* Turn debug off so that it doesn't intefere with measurement timing */ + /* Turn debug and thread off so that they doesn't intefere with measurement timing */ isdeb = p->log->debug; p->icom->log->debug = 0; + isth = p->th_en; + p->th_en = 0; /* Do some measurement and throw them away, to make sure the code is in cache. */ for (i = 0; i < 5; i++) { if ((ev = i1d3_freq_measure(p, &inttimeh, samp[i].rgb)) != inst_ok) { p->log->debug = isdeb; + p->th_en = isth; return ev; } } @@ -945,6 +988,7 @@ i1d3_imp_measure_refresh( if ((ev = i1d3_freq_measure(p, &inttime1, samp[0].rgb)) != inst_ok) { p->log->debug = isdeb; + p->th_en = isth; return ev; } @@ -952,6 +996,7 @@ i1d3_imp_measure_refresh( if ((ev = i1d3_freq_measure(p, &inttime2, samp[0].rgb)) != inst_ok) { p->log->debug = isdeb; + p->th_en = isth; return ev; } @@ -977,10 +1022,10 @@ i1d3_imp_measure_refresh( if ((ev = i1d3_freq_measure(p, &samp[i].itime, samp[i].rgb)) != inst_ok) { p->log->debug = isdeb; + p->th_en = isth; return ev; } cutime = (usec_time() - sutime) / 1000000.0; -// ~~999 samp[i].sec = 0.5 * (putime + cutime); /* Mean of before and after stamp */ //samp[i].sec *= 85.0/20.0; /* Test 20 Hz */ //samp[i].sec *= 85.0/100.0; /* Test 100 Hz */ @@ -988,7 +1033,9 @@ i1d3_imp_measure_refresh( if (cutime > NFMXTIME) break; } + /* Restore debug & thread */ p->log->debug = isdeb; + p->th_en = isth; nfsamps = i; if (nfsamps < 100) { @@ -1354,6 +1401,7 @@ i1d3_imp_measure_refresh( } else { int mul; double refrate; + double pval; pval = avg/ano; pval /= 1000.0; /* Convert to seconds */ @@ -1365,10 +1413,25 @@ i1d3_imp_measure_refresh( /* Error against my 85Hz CRT - GWG */ // a1logd(p->log, 1, "Refresh rate error = %.4f%%\n",100.0 * fabs(refrate - 85.0)/(85.0)); - /* Scale to just above 20 Hz */ - mul = floor((1.0/20) / pval); - if (mul > 1) + /* Scale to just above 20 Hz, but make it multiple of 2 or 4 */ +#ifdef DEBUG_TWEAKS + { + double quanttime = 1.0/20.0; + char *cp; + if ((cp = getenv("I1D3_MIN_REF_QUANT_TIME")) != NULL) + quanttime = atof(cp); + mul = (int)floor(quanttime / pval); + } +#else + mul = (int)floor((1.0/20.0) / pval); +#endif + if (mul > 1) { + if (mul >= 8) + mul = (mul + 3) & ~3; /* Round up to mult of 4 */ + else + mul = (mul + 1) & ~1; /* Round up to mult of 2 */ pval *= mul; + } a1logd(p->log, 1, "Refresh rate = %f Hz, quantizing to %f msec\n",refrate,pval); a1logv(p->log, 1, "Refresh rate = %f Hz, quantizing to %f msec\n",refrate,pval); @@ -1411,6 +1474,8 @@ i1d3_measure_set_refresh( /* - - - - - - - - - - - - - - - - - - - - - - */ +#ifdef NEVER /* No longer used - use general measurement instead */ + /* Take an ambient measurement and return the cooked reading */ /* The cooked reading is the frequency of the L2V */ static inst_code @@ -1451,11 +1516,11 @@ i1d3_take_amb_measurement( return inst_ok; } - +#endif /* - - - - - - - - - - - - - - - - - - - - - - */ -/* Take an display measurement and return the cooked reading */ +/* Take a general measurement and return the cooked reading */ /* The cooked reading is the frequency of the L2V */ static inst_code i1d3_take_emis_measurement( @@ -1464,26 +1529,22 @@ i1d3_take_emis_measurement( double *rgb /* Return the cooked emsissive RGB values */ ) { int i, k; - int pos; inst_code ev; double rmeas[3] = { -1.0, -1.0, -1.0 }; /* raw measurement */ int edgec[3] = {2,2,2}; /* Measurement edge count for each channel (not counting start edge) */ int mask = 0x7; /* Period measure mask */ int msecstart = msec_time(); /* Debug */ double rgb2[3] = { 0.0, 0.0, 0.0 }; /* Trial measurement RGB values */ + int isth; if (p->inited == 0) return i1d3_interp_code((inst *)p, I1D3_NOT_INITED); a1logd(p->log,3,"\ntake_emis_measurement called\n"); - /* Check that the ambient filter is not in place */ - if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok) - return ev; - - if (pos != 0) - return i1d3_interp_code((inst *)p, I1D3_SPOS_EMIS); - + /* Suspend thread so that it doesn't intefere with measurement timing */ + isth = p->th_en; + p->th_en = 0; /* If we should take a frequency measurement first */ if (mode == i1d3_adaptive || mode == i1d3_frequency) { @@ -1492,8 +1553,10 @@ i1d3_take_emis_measurement( a1logd(p->log,3,"Doing fixed period frequency measurement over %f secs\n",p->inttime); /* Take a frequency measurement over a fixed period */ - if ((ev = i1d3_freq_measure(p, &p->inttime, rmeas)) != inst_ok) + if ((ev = i1d3_freq_measure(p, &p->inttime, rmeas)) != inst_ok) { + p->th_en = isth; return ev; + } /* Convert to frequency (assume raw meas is both edges count over integration time) */ for (i = 0; i < 3; i++) { @@ -1555,8 +1618,10 @@ i1d3_take_emis_measurement( a1logd(p->log,3,"Doing 1st period pre-measurement mask 0x%x, edgec %d %d %d\n",mask2,edgec[0],edgec[1],edgec[2]); /* Take an initial period pre-measurement over 2 edges */ - if ((ev = i1d3_period_measure(p, edgec, mask2, rmeas2)) != inst_ok) + if ((ev = i1d3_period_measure(p, edgec, mask2, rmeas2)) != inst_ok) { + p->th_en = isth; return ev; + } a1logd(p->log,3,"Got %f %f %f raw %f %f %f Hz\n",rmeas2[0],rmeas2[1],rmeas2[2], 0.5 * edgec[0] * p->clk_freq/rmeas2[0], @@ -1627,8 +1692,10 @@ i1d3_take_emis_measurement( a1logd(p->log,3,"Doing 2nd initial period measurement mask 0x%x, edgec %d %d %d\n",mask2,edgec[0],edgec[1],edgec[2]); /* Take a 2nd initial period measurement */ - if ((ev = i1d3_period_measure(p, edgec, mask3, rmeas2)) != inst_ok) + if ((ev = i1d3_period_measure(p, edgec, mask3, rmeas2)) != inst_ok) { + p->th_en = isth; return ev; + } a1logd(p->log,3,"Got %f %f %f raw %f %f %f Hz\n",rmeas2[0],rmeas2[1],rmeas2[2], 0.5 * edgec[0] * p->clk_freq/rmeas2[0], @@ -1659,7 +1726,7 @@ i1d3_take_emis_measurement( continue; /* Compute number of edges needed for a clock count */ - /* of p->inttime (0.2 secs) */ + /* of p->inttime (0.2/0.4 secs) */ nedgec = edgec[i] * p->inttime * p->clk_freq/rmeas[i]; /* If we will get less than 200 edges, raise the target integration */ @@ -1780,8 +1847,10 @@ i1d3_take_emis_measurement( a1logd(p->log,3,"Doing freq re-measure inttime %f\n",tinttime); /* Take a frequency measurement over a fixed period */ - if ((ev = i1d3_freq_measure(p, &tinttime, rmeas)) != inst_ok) + if ((ev = i1d3_freq_measure(p, &tinttime, rmeas)) != inst_ok) { + p->th_en = isth; return ev; + } /* Convert raw measurement to frequency */ for (i = 0; i < 3; i++) { @@ -1799,8 +1868,10 @@ i1d3_take_emis_measurement( a1logd(p->log,3,"Doing period re-measure mask 0x%x, edgec %d %d %d\n",mask,edgec[0],edgec[1],edgec[2]); /* Measure again with desired precision, taking up to 0.4/0.8 secs */ - if ((ev = i1d3_period_measure(p, edgec, mask, rmeas)) != inst_ok) + if ((ev = i1d3_period_measure(p, edgec, mask, rmeas)) != inst_ok) { + p->th_en = isth; return ev; + } for (i = 0; i < 3; i++) { double tt; @@ -1820,6 +1891,7 @@ i1d3_take_emis_measurement( } } } + p->th_en = isth; a1logd(p->log,3,"Took %d msec to measure\n", msec_time() - msecstart); @@ -1843,27 +1915,35 @@ i1d3_take_XYZ_measurement( i1d3 *p, /* Object */ double XYZ[3] /* Return the XYZ values */ ) { + int pos; inst_code ev; if (IMODETST(p->mode, inst_mode_emis_ambient)) { - if ((ev = i1d3_take_amb_measurement(p, XYZ)) != inst_ok) + + /* Check that the ambient filter is in place */ + if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok) + return ev; + + if (pos != 1) + 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) return ev; /* Multiply by ambient calibration matrix */ - icmMulBy3x3(XYZ, p->ambi_cal, XYZ); - icmScale3(XYZ, XYZ, 1/3.141592654); /* Convert from Lux to cd/m^2 */ + icmMulBy3x3(XYZ, p->ambi_cal, XYZ); /* Values in Lux */ } else { - /* Constant fast speed, poor accuracy for black */ -// if ((ev = i1d3_take_emis_measurement(p, i1d3_frequency, XYZ)) != inst_ok) -// return ev; - - /* Most accurate ? */ -// if ((ev = i1d3_take_emis_measurement(p, i1d3_period, XYZ)) != inst_ok) -// return ev; + /* Check that the ambient filter is not in place */ + if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok) + return ev; + + if (pos != 0) + return i1d3_interp_code((inst *)p, I1D3_SPOS_EMIS); - /* Best combination */ + /* Best type of reading, including refresh support */ if ((ev = i1d3_take_emis_measurement(p, i1d3_adaptive, XYZ)) != inst_ok) return ev; @@ -1892,6 +1972,9 @@ static inst_code i1d3_decode_intEE( strncpy(p->serial_no, (char *)buf + 0x10, 20); p->serial_no[20] = '\000'; + strncpy(p->vers_no, (char *)buf + 0x2C, 10); + p->serial_no[10] = '\000'; + /* Read the black level offset */ for (i = 0; i < 3; i++) { t1 = buf2uint(buf + 0x0004 + 4 * i); @@ -1915,16 +1998,22 @@ static inst_code i1d3_decode_extEE( unsigned int chsum, rchsum; xspect tmp; - for (chsum = 0, i = 4; i < 6042; i++) - chsum += buf[i]; + rchsum = buf2short(buf + 2); - chsum &= 0xffff; /* 16 bit sum */ + /* For the "A-01" revsions the checksum is from 4 to 0x179a */ + /* The "A-02" seems to have abandoned reliable checksums ?? */ + for (chsum = 0, i = 4; i < 0x179a; i++) { + chsum += buf[i]; + } - rchsum = buf2short(buf + 2); + chsum &= 0xffff; if (rchsum != chsum) { - a1logd(p->log, 3, "i1d3_decode_extEE: checksum failed\n"); - return i1d3_interp_code((inst *)p, I1D3_BAD_EX_CHSUM); + a1logd(p->log, 3, "i1d3_decode_extEE: checksum failed, is 0x%x, should be 0x%x\n",chsum,rchsum); + if (strcmp(p->vers_no, "A-01") == 0) + return i1d3_interp_code((inst *)p, I1D3_BAD_EX_CHSUM); + + /* Else ignore checksum error */ } /* Read 3 x sensor spectral sensitivits */ @@ -2116,6 +2205,108 @@ i1d3_comp_calmat( return inst_ok; } +/* Preset the calibration to a spectral sample type. */ +/* ccmat[][] is set to unity */ +static inst_code +i1d3_set_speccal( + i1d3 *p, + xspect *samples, /* Array of nsamp spectral samples, or RGBcmfs for MIbLSr */ + int nsamp /* Number of samples */ +) { + int i; + + /* Save a the spectral samples to the current state */ + if (p->samples != NULL) + free(p->samples); + p->nsamp = 0; + if ((p->samples = (xspect *)calloc(sizeof(xspect), nsamp)) == NULL) { + a1loge(p->log, inst_internal_error, "i1d3_set_speccal: malloc failed\n"); + return inst_internal_error; + } + for (i = 0; i < nsamp; i++ ) + p->samples[i] = samples[i]; /* Struct copy */ + p->nsamp = nsamp; + + icmSetUnity3x3(p->ccmat); /* No matrix */ + + 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 (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; + } + icmCpy3x3(p->ccmat, mtx); + } + return inst_ok; +} + + +/* Set the calibration to the currently preset type */ +static inst_code +i1d3_set_cal(i1d3 *p) { + inst_code ev = inst_ok; + + if (p->samples != NULL && p->nsamp > 0) { + + /* Create matrix for specified samples */ + if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver, + p->sens, p->samples, p->nsamp)) != inst_ok) { + a1logd(p->log, 1, "i1d3_set_cal: comp_calmat ccss 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; + + icmSetUnity3x3(p->ccmat); /* to be sure to be sure... */ + + } else { /* Assume 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); + 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; + } + + 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]); + 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,"\n"); + } + + return inst_ok; +} /* ------------------------------------------------------------------------ */ @@ -2175,15 +2366,10 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { } } else { - a1logd(p->log, 1, "i1d3_init_coms: wrong sort of coms!\n"); - return i1d3_interp_code((inst *)p, I1D3_UNKNOWN_MODEL); + a1logd(p->log, 1, "i1d3_init_coms: wrong communications type for device!\n"); + return inst_coms_fail; } -#if defined(__APPLE__) - /* We seem to have to clear any pending messages for OS X HID */ - i1d3_dummy_read(p); -#endif - /* Check instrument is responding */ if ((ev = i1d3_check_status(p,&stat)) != inst_ok) { a1logd(p->log, 1, "i1d3_init_coms: failed with rv = 0x%x\n",ev); @@ -2214,7 +2400,7 @@ static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int len) { bp += sprintf(bp,"."); } bp += sprintf(bp,"\n"); - a1logd(log,0,oline); + a1logd(log,0, "%s", oline); bp = oline; } } @@ -2230,20 +2416,25 @@ int i1d3_diff_thread(void *pp) { for (nfailed = 0; nfailed < 5;) { int pos; - rv = i1d3_get_diffpos(p, &pos, 1); - if (p->th_term) { - p->th_termed = 1; - break; - } - if (rv != inst_ok) { - nfailed++; - a1logd(p->log,3,"Diffuser thread failed with 0x%x\n",rv); - continue; - } - if (pos != p->dpos) { - p->dpos = pos; - if (p->eventcallback != NULL) { - p->eventcallback(p->event_cntx, inst_event_mconf); + /* Don't get diffpos if we're doing something else that */ + /* is timing critical */ + if (p->th_en) { +//a1logd(p->log,3,"Diffuser thread loop debug = %d\n",p->log->debug); + rv = i1d3_get_diffpos(p, &pos, p->log->debug < 8 ? 1 : 0); + if (p->th_term) { + p->th_termed = 1; + break; + } + if (rv != inst_ok) { + nfailed++; + a1logd(p->log,3,"Diffuser thread failed with 0x%x\n",rv); + continue; + } + if (pos != p->dpos) { + p->dpos = pos; + if (p->eventcallback != NULL) { + p->eventcallback(p->event_cntx, inst_event_mconf); + } } } msec_sleep(100); @@ -2262,7 +2453,7 @@ i1d3_init_inst(inst *pp) { int i, stat; unsigned char buf[8192]; - a1logd(p->log, 2, "i1d3_init_inst: called\n"); + a1logd(p->log, 2, "i1d3_init_inst: called, debug = %d\n",p->log->debug); p->rrset = 0; @@ -2329,9 +2520,11 @@ i1d3_init_inst(inst *pp) { return ev; /* Set known constants */ - p->clk_freq = 12e6; /* 12 Mhz */ - p->dinttime = 0.2; /* 0.2 second integration time default */ - p->inttime = p->dinttime; /* Start in non-refresh mode */ + p->clk_freq = 12e6; /* 12 Mhz */ + p->omininttime = 0.0; /* No override */ + p->dinttime = 0.2; /* 0.2 second integration time default */ + p->inttime = p->dinttime; /* Start in non-refresh mode */ + p->mininttime = p->inttime; /* Current value */ /* Create the default calibrations */ @@ -2353,29 +2546,32 @@ i1d3_init_inst(inst *pp) { if (p->log->debug >= 4) { a1logd(p->log,4,"Default calibration:\n"); - 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]); 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", 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]); a1logd(p->log,4,"\n"); } /* Start the diffuser monitoring thread */ + p->th_en = 1; if ((p->th = new_athread(i1d3_diff_thread, (void *)p)) == NULL) - return I1D3_INT_THREADFAILED; + return i1d3_interp_code((inst *)p, I1D3_INT_THREADFAILED); /* Flash the LED, just cos we can! */ if ((ev = i1d3_set_LEDs(p, i1d3_flash, 0.2, 0.05, 2)) != inst_ok) return ev; + a1logd(p->log, 2, "i1d3_init_inst: done\n"); + return ev; } @@ -2422,26 +2618,40 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ } else { /* Check for abort */ if (p->uicallback != NULL - && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) + && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) { return rv; /* Abort */ + } } /* Attempt a refresh display frame rate calibration if needed */ if (p->dtype != i1d3_munkdisp && p->refrmode != 0 && p->rrset == 0) { inst_code ev = inst_ok; + p->mininttime = 2.0 * p->dinttime; + + if (p->omininttime != 0.0) + p->mininttime = p->omininttime; /* Override */ + +#ifdef DEBUG_TWEAKS + { + char *cp; + if ((cp = getenv("I1D3_MIN_INT_TIME")) != NULL) + p->mininttime = atof(cp); + } +#endif + if ((ev = i1d3_measure_set_refresh(p)) != inst_ok) return ev; /* Quantize the sample time */ if (p->refperiod > 0.0) { /* If we have a refresh period */ int n; - n = (int)ceil(p->dinttime/p->refperiod); - p->inttime = 2.0 * n * p->refperiod; + n = (int)ceil(p->mininttime/p->refperiod); + p->inttime = n * p->refperiod; a1logd(p->log, 3, "i1d3: integration time quantize to %f secs\n",p->inttime); - } else { /* We don't have a period, so simply double the default */ - p->inttime = 2.0 * p->dinttime; + } else { /* We don't have a period, so simply use the double default */ + p->inttime = p->mininttime; a1logd(p->log, 3, "i1d3: integration time integration time doubled to %f secs\n",p->inttime); } } @@ -2463,6 +2673,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ val->sp.spec_n = 0; val->duration = 0.0; + if (user_trig) return inst_user_trig; @@ -2491,6 +2702,7 @@ double *ref_rate) { if (*ref_rate == 0.0) return inst_misread; + return inst_ok; } @@ -2502,23 +2714,19 @@ inst *pp, double mtx[3][3] ) { i1d3 *p = (i1d3 *)pp; + inst_code ev = inst_ok; + + a1logd(p->log, 4, "i1d3_col_cor_mat%s\n",mtx == NULL ? " (noop)": ""); if (!p->gotcoms) return inst_no_coms; if (!p->inited) return inst_no_init; - 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"); - inst_wrong_setup; - } - icmCpy3x3(p->ccmat, mtx); - } - - return inst_ok; + if ((ev = i1d3_set_matcal(p, mtx)) != inst_ok) + return ev; + + return i1d3_set_cal(p); } /* Use a Colorimeter Calibration Spectral Set to set the */ @@ -2533,6 +2741,8 @@ int no_sets i1d3 *p = (i1d3 *)pp; inst_code ev = inst_ok; + a1logd(p->log, 4, "i1d3_col_cal_spec_set%s\n",sets == NULL ? " (default)": ""); + if (!p->gotcoms) return inst_no_coms; if (!p->inited) @@ -2543,31 +2753,12 @@ int no_sets return ev; } } else { - /* Use given spectral samples */ - if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver, p->sens, - sets, no_sets)) != inst_ok) - return ev; - /* Use MIbLSr */ - if ((ev = i1d3_comp_calmat(p, p->ambi_cal, p->obType, p->custObserver, p->ambi, - p->ambi, 3)) != inst_ok) - return ev; - } - if (p->log->debug >= 4) { - a1logd(p->log,4,"CCSS update calibration:\n"); - 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]); - 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", - p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]); - a1logd(p->log,4,"\n"); + if ((ev = i1d3_set_speccal(p, sets, no_sets)) != inst_ok) + return ev; + + ev = i1d3_set_cal(p); } + return ev; } @@ -2638,11 +2829,24 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if ((*calt & inst_calt_ref_freq) && p->dtype != i1d3_munkdisp && p->refrmode != 0) { inst_code ev = inst_ok; - if (*calc != inst_calc_emis_white) { - *calc = inst_calc_emis_white; + p->mininttime = 2.0 * p->dinttime; + + if (*calc != inst_calc_emis_80pc) { + *calc = inst_calc_emis_80pc; return inst_cal_setup; } + if (p->omininttime != 0.0) + p->mininttime = p->omininttime; /* Override */ + +#ifdef DEBUG_TWEAKS + { + char *cp; + if ((cp = getenv("I1D3_MIN_INT_TIME")) != NULL) + p->mininttime = atof(cp); + } +#endif + /* Do refresh display rate calibration */ if ((ev = i1d3_measure_set_refresh(p)) != inst_ok) return ev; @@ -2650,11 +2854,11 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ /* Quantize the sample time */ if (p->refperiod > 0.0) { int n; - n = (int)ceil(p->dinttime/p->refperiod); - p->inttime = 2.0 * n * p->refperiod; + n = (int)ceil(p->mininttime/p->refperiod); + p->inttime = n * p->refperiod; a1logd(p->log, 3, "i1d3: integration time quantize to %f secs\n",p->inttime); } else { - p->inttime = 2.0 * p->dinttime; /* Double default integration time */ + p->inttime = p->mininttime; /* Double default integration time */ a1logd(p->log, 3, "i1d3: integration time integration time doubled to %f secs\n",p->inttime); } *calt &= ~inst_calt_ref_freq; @@ -2665,11 +2869,11 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ /* Measure a display update delay. It is assumed that a */ /* white to black 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.5 seconds. */ +/* be noticed by the instrument, up to 0.6 seconds. */ /* inst_misread will be returned on failure to find a transition to black. */ -#define NDSAMPS 60 -#define DINTT 0.010 -#define NDMXTIME 0.6 /* Maximum time to take */ +#define NDSAMPS 200 +#define DINTT 0.005 /* Too short hits blanking */ +#define NDMXTIME 1.0 /* Maximum time to take */ inst_code i1d3_meas_delay( inst *pp, @@ -2681,21 +2885,25 @@ int *msecdelay) { /* Return the number of msec */ struct { double sec; double rgb[3]; + double tot; } samp[NDSAMPS]; int ndsamps; double inttime = DINTT; - double rgb[3]; + double stot, etot, del, thr; double etime; int isdeb; + int isth; if (usec_time() < 0.0) { a1loge(p->log, inst_internal_error, "i1d3_meas_delay: No high resolution timers\n"); return inst_internal_error; } - /* Turn debug off so that it doesn't intefere with measurement timing */ + /* Turn debug and thread off so that they doesn't intefere with measurement timing */ isdeb = p->log->debug; p->icom->log->debug = 0; + isth = p->th_en; + p->th_en = 0; /* Read the samples */ sutime = usec_time(); @@ -2704,71 +2912,85 @@ int *msecdelay) { /* Return the number of msec */ if ((ev = i1d3_freq_measure(p, &inttime, samp[i].rgb)) != inst_ok) { a1logd(p->log, 1, "i1d3_meas_delay: measurement failed\n"); p->log->debug = isdeb; + p->th_en = isth; return ev; } cutime = (usec_time() - sutime) / 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]; if (cutime > NDMXTIME) break; } ndsamps = i; - /* Restore debugging */ + /* Restore debugging & thread */ p->log->debug = isdeb; + p->th_en = isth; if (ndsamps == 0) { a1logd(p->log, 1, "i1d3_meas_delay: No measurement samples returned in time\n"); return inst_internal_error; } -#ifdef NEVER +#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]; - //printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].rgb[0]); + 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, NULL, NULL, NULL, ndsamps); + do_plot6(xx, y1, y2, y3, y4, NULL, NULL, ndsamps); } #endif + /* Over the first 100msec, locate the maximum value */ + etime = samp[ndsamps-1].sec; + stot = -1e9; + for (i = 0; i < ndsamps; i++) { + if (samp[i].tot > stot) + stot = samp[i].tot; + if (samp[i].sec > 0.1) + break; + } + /* Over the last 100msec, locate the maximum value */ etime = samp[ndsamps-1].sec; - for (j = 0; j < 3; j++) - rgb[j] = 0.0; + etot = -1e9; for (i = ndsamps-1; i >= 0; i--) { - for (j = 0; j < 3; j++) { - if (samp[i].rgb[j] > rgb[j]) - rgb[j] = samp[i].rgb[j]; - } + if (samp[i].tot > etot) + etot = samp[i].tot; if ((etime - samp[i].sec) > 0.1) break; } -// a1logd(p->log, 3, "i1d3_meas_delay: end rgb = %f %f %f stopped at %d\n", rgb[0], rgb[1], rgb[2], i); + del = stot - etot; + thr = etot + 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 - if (rgb[0] > 10.0 || rgb[1] > 10.0 || rgb[2] > 10.0) { - a1logd(p->log, 1, "i1d3_meas_delay: measurement delay doesn't seem to be black\n"); + /* 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"); return inst_misread; } - /* Locate the time at which the values are above this */ + /* Working from the end, locate the time at which the level was above the threshold */ for (i = ndsamps-1; i >= 0; i--) { - for (j = 0; j < 3; j++) { - if (samp[i].rgb[j] > (1.5 * rgb[j])) - break; - } - if (j < 3) + if (samp[i].tot > thr) break; } if (i < 0) /* Assume the update was so fast that we missed it */ @@ -2778,6 +3000,10 @@ int *msecdelay) { /* Return the number of msec */ *msecdelay = (int)(samp[i].sec * 1000.0 + 0.5); +#ifdef PLOT_UPDELAY + a1logd(p->log, 0, "i1d3_meas_delay: returning %d msec\n",*msecdelay); +#endif + return inst_ok; } #undef NDSAMPS @@ -2819,13 +3045,27 @@ double ref_rate int mul; double pval; - /* Scale to just above 20 Hz */ + /* Scale to just above 20 Hz, but make it multiple of 2 or 4 */ pval = 1.0/ref_rate; - mul = floor((1.0/20) / pval); - if (mul > 1) +#ifdef DEBUG_TWEAKS + { + double quanttime = 1.0/20.0; + char *cp; + if ((cp = getenv("I1D3_MIN_REF_QUANT_TIME")) != NULL) + quanttime = atof(cp); + mul = (int)floor(quanttime / pval); + } +#else + mul = (int)floor((1.0/20.0) / pval); +#endif + if (mul > 1) { + if (mul >= 8) + mul = (mul + 3) & ~3; /* Round up to mult of 4 */ + else + mul = (mul + 1) & ~1; /* Round up to mult of 2 */ pval *= mul; + } p->refperiod = pval; - p->refrvalid = 1; } p->rrset = 1; @@ -2994,6 +3234,8 @@ i1d3_del(inst *pp) { if (p->icom != NULL) p->icom->del(p->icom); inst_del_disptype_list(p->dtlist, p->ndtlist); + if (p->samples != NULL) + free(p->samples); amutex_del(p->lock); free(p); } @@ -3011,7 +3253,7 @@ inst3_capability *pcap3) { cap1 |= inst_mode_emis_spot | inst_mode_emis_tele | inst_mode_emis_ambient - | inst_mode_emis_refresh_ovd + | inst_mode_emis_refresh_ovd /* (allow override ccmx & ccss mode) */ | inst_mode_emis_norefresh_ovd | inst_mode_colorimeter ; @@ -3023,11 +3265,14 @@ inst3_capability *pcap3) { | inst2_disptype | inst2_ccmx | inst2_ccss + | inst2_get_min_int_time + | inst2_set_min_int_time ; if (p->dtype != i1d3_munkdisp) { cap2 |= inst2_meas_disp_update; - cap2 |= inst2_refresh_rate; + cap2 |= inst2_get_refresh_rate; + cap2 |= inst2_set_refresh_rate; cap2 |= inst2_emis_refr_meas; } if (pcap1 != NULL) @@ -3075,8 +3320,8 @@ int *conf_ix /* Add the extra dependent and independent modes */ mval |= inst_mode_emis_refresh_ovd - | inst_mode_emis_norefresh_ovd - | inst_mode_colorimeter; + | inst_mode_emis_norefresh_ovd + | inst_mode_colorimeter; if (mmodes != NULL) *mmodes = mval; @@ -3139,11 +3384,15 @@ inst_code i1d3_set_mode(inst *pp, inst_mode m) { } 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 */ return inst_ok; } @@ -3152,7 +3401,7 @@ inst_disptypesel i1d3_disptypesel[3] = { { inst_dtflags_default, 1, - "n", + "nl", "Non-Refresh display", 0, 0 @@ -3160,7 +3409,7 @@ inst_disptypesel i1d3_disptypesel[3] = { { inst_dtflags_none, /* flags */ 2, /* cbid */ - "r", /* sel */ + "rc", /* sel */ "Refresh display", /* desc */ 1, /* refr */ 1 /* ix */ @@ -3186,7 +3435,7 @@ int recreate /* nz to re-check for new ccmx & ccss files */ i1d3 *p = (i1d3 *)pp; inst_code rv = inst_ok; - if (!allconfig && p->dpos) { /* If set to Ambient */ + if (!allconfig && p->dpos) { /* If set to Ambient, there are no display types ? */ if (pnsels != NULL) *pnsels = 0; @@ -3233,59 +3482,31 @@ static inst_code set_disp_type(i1d3 *p, inst_disptypesel *dentry) { p->rrset = 0; /* This is a hint we may have swapped displays */ p->refrmode = refrmode; -// if (p->refrmode && p->dtype == i1d3_munkdisp) { 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 */ - if (dentry->flags & inst_dtflags_ccss) { + if (dentry->flags & inst_dtflags_ccss) { /* Spectral sample */ - if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver, - p->sens, dentry->sets, dentry->no_sets)) != inst_ok) { - a1logd(p->log, 1, "i1d3_set_disp_type: comp_calmat ccss failed with rv = 0x%x\n",ev); + if ((ev = i1d3_set_speccal(p, dentry->sets, dentry->no_sets)) != inst_ok) 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; - - icmSetUnity3x3(p->ccmat); - if (p->log->debug >= 4) { - a1logd(p->log,4,"Display type set CCSS:\n"); - 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", - p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]); - a1logd(p->log,4,"\n"); - } - - } else { /* Assume matrix */ - - /* Create the default 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); - 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; + } else { /* Matrix */ if (dentry->flags & inst_dtflags_ccmx) { - icmCpy3x3(p->ccmat, dentry->mat); + if ((ev = i1d3_set_matcal(p, dentry->mat)) != inst_ok) + return ev; } else { - icmSetUnity3x3(p->ccmat); + if ((ev = i1d3_set_matcal(p, NULL)) != inst_ok) /* Noop */ + return ev; } } - - return inst_ok; + return i1d3_set_cal(p); } /* Setup the default display type */ @@ -3386,6 +3607,66 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) return inst_ok; } + /* Get the current minimum integration time */ + if (m == inst_opt_get_min_int_time) { + va_list args; + double *dpoint; + + va_start(args, m); + dpoint = va_arg(args, double *); + va_end(args); + + if (dpoint != NULL) + *dpoint = p->mininttime; + + return inst_ok; + } + + /* Set the minimum integration time */ + if (m == inst_opt_set_min_int_time) { + va_list args; + double dval; + + va_start(args, m); + dval = va_arg(args, double); + va_end(args); + + p->omininttime = dval; + + /* Hmm. This code is duplicated a lot.. */ + if (p->dtype != i1d3_munkdisp && p->refrmode != 0) { + inst_code ev = inst_ok; + + p->mininttime = 2.0 * p->dinttime; + + if (p->omininttime != 0.0) + p->mininttime = p->omininttime; /* Override */ + +#ifdef DEBUG_TWEAKS + { + char *cp; + if ((cp = getenv("I1D3_MIN_INT_TIME")) != NULL) + p->mininttime = atof(cp); + } +#endif + + /* Quantize the sample time if we have a refresh rate */ + if (p->rrset && p->refperiod > 0.0) { /* If we have a refresh period */ + int n; + n = (int)ceil(p->mininttime/p->refperiod); + p->inttime = n * p->refperiod; + a1logd(p->log, 3, "i1d3: integration time quantize to %f secs\n",p->inttime); + + } else { /* We don't have a period, so simply use the double default */ + p->inttime = p->mininttime; + a1logd(p->log, 3, "i1d3: integration time integration time doubled to %f secs\n",p->inttime); + } + } + + return inst_ok; + } + + /* Set the ccss observer type */ if (m == inst_opt_set_ccss_obs) { va_list args; @@ -3406,7 +3687,9 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) p->custObserver[2] = custObserver[2]; } - return inst_ok; + a1logd(p->log, 4, "inst_opt_set_ccss_obs\n"); + + return i1d3_set_cal(p); /* Recompute calibration */ } /* Operate the LEDS */ @@ -3436,6 +3719,7 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) mask = va_arg(args, int); va_end(args); + p->led_state = mask; if (p->led_state & 0x1) return i1d3_set_LEDs(p, i1d3_flash, 0.0, 100.0, 0x80); else @@ -3595,9 +3879,9 @@ static void create_unlock_response(unsigned int *k, unsigned char *c, unsigned c /* Minus the two key values as bytes */ sum += (0xff & -k[0]) + (0xff & (-k[0] >> 8)) - + (0xff & (-k[0] >> 16)) + (0xff & (-k[0] >> 24)); + + (0xff & (-k[0] >> 16)) + (0xff & (-k[0] >> 24)); sum += (0xff & -k[1]) + (0xff & (-k[1] >> 8)) - + (0xff & (-k[1] >> 16)) + (0xff & (-k[1] >> 24)); + + (0xff & (-k[1] >> 16)) + (0xff & (-k[1] >> 24)); /* Convert sum to bytes. Only need 2, because sum of 16 bytes can't exceed 16 bits. */ s0 = sum & 0xff; |