From 3db384424bd7398ffbb7a355cab8f15f3add009f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 2 Oct 2016 19:24:58 +0200 Subject: New upstream version 1.9.1+repack --- spectro/specbos.c | 1000 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 794 insertions(+), 206 deletions(-) (limited to 'spectro/specbos.c') diff --git a/spectro/specbos.c b/spectro/specbos.c index 491fe97..4c5e4ba 100644 --- a/spectro/specbos.c +++ b/spectro/specbos.c @@ -2,7 +2,7 @@ /* * Argyll Color Correction System * - * JETI specbos 1211/1201 related functions + * JETI specbos & spectraval related functions * * Author: Graeme W. Gill * Date: 13/3/2013 @@ -38,9 +38,15 @@ TTBD: - Should add a reflective and transmissive modes, + Should add a reflective mode, by doing a white calibration and dividing the measurement. + Should check transmissive white spectral quality + + Should save transmissive white cal. into file, and restore it on startup. + + Should time transmissive white cal out. + */ #include @@ -78,6 +84,14 @@ static int icoms2specbos_err(int se) { return SPECBOS_OK; } +/* Type of reply terminator expected */ +typedef enum { + tnorm = 0, /* Normal terminators */ + tmeas = 1, /* Measurement command */ + trefr = 2, /* Refresh measurement */ + tspec = 3 /* Spectraval spectral read */ +} spterm; + /* Do a full command/response echange with the specbos */ /* (This level is not multi-thread safe) */ /* Return the specbos error code. */ @@ -89,26 +103,28 @@ char *out, /* Out string buffer */ int bsize, /* Out buffer size */ double to, /* Timeout in seconds */ int ntc, /* Number or termination chars */ -int ctype, /* 0 = normal, 1 = *init, 2 = refr reading */ +spterm ctype, /* Exected reply terminator type */ int nd /* nz to disable debug messages */ ) { int se; int bread = 0; char *cp, *tc = "", *dp; - if (ctype == 0) + if (ctype == tnorm) tc = "\r\006\025"; /* Return, Ack or Nak */ - else if (ctype == 1) + else if (ctype == tmeas) tc = "\007\025"; /* Bell or Nak */ - else if (ctype == 2) + else if (ctype == trefr) tc = "\r\025"; /* Return or Nak */ + else if (ctype == tspec) + tc = "\003\025"; /* Atx or Nak */ - se = p->icom->write_read(p->icom, in, 0, out, bsize, &bread, tc, ntc, to); + se = p->icom->write_read_ex(p->icom, in, 0, out, bsize, &bread, tc, ntc, to, 1); /* Because we are sometimes waiting for 3 x \r characters to terminate the read, */ - /* we will instead time out on getting a single NAK (\025), so convert timout */ - /* with bytes to non-timeout, so that we can process the error. */ - if (se == ICOM_TO && bread > 0) + /* we will instead time out on getting a single NAK (\025), so ignore timout */ + /* if we got a NAK. */ + if (se == ICOM_TO && bread > 0 && out[0] == '\025') se = ICOM_OK; if (se != 0) { @@ -116,6 +132,14 @@ int nd /* nz to disable debug messages */ return icoms2specbos_err(se); } + /* Over Bluetooth, we get an erronious string "AT+JSCR\r\n" mixed in our output. */ + /* This would appear to be from the eBMU Bluetooth adapter AT command set. */ + if (bread > 9 && strncmp(out, "AT+JSCR\r\n", 9) == 0) { + a1logd(p->log, 8, "specbos: ignored 'AT+JSCR\\r\\n' response\n"); + memmove(out, out+9, bsize-9); + bread -= 9; + } + /* See if there was an error, and remove any enquire codes */ for (dp = cp = out; *cp != '\000' && (dp - out) < bsize; cp++) { if (*cp == '\025') { /* Got a NAK */ @@ -125,9 +149,16 @@ int nd /* nz to disable debug messages */ if (!nd) a1logd(p->log, 1, "specbos_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in)); return icoms2specbos_err(se);; } - if (sscanf(buf, "Error Code: %d ",&se) != 1) { - if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf)); - return SPECBOS_DATA_PARSE_ERROR; + if (p->model == 1501 || p->model == 1511) { + if (sscanf(buf, "%d ",&se) != 1) { + if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf)); + return SPECBOS_DATA_PARSE_ERROR; + } + } else { + if (sscanf(buf, "Error Code: %d ",&se) != 1) { + if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf)); + return SPECBOS_DATA_PARSE_ERROR; + } } if (!nd) a1logd(p->log, 1, "Got specbos error code %d\n",se); @@ -155,7 +186,7 @@ char *in, /* In string */ char *out, /* Out string buffer */ int bsize, /* Out buffer size */ double to) { /* Timout in seconds */ - int rv = specbos_fcommand(p, in, out, bsize, to, 1, 0, 0); + int rv = specbos_fcommand(p, in, out, bsize, to, 1, tnorm, 0); return specbos_interp_code((inst *)p, rv); } @@ -186,8 +217,10 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { specbos *p = (specbos *) pp; char buf[MAX_MES_SIZE]; baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_nc }; +// spectraval 38400, 115200, 230400, 921600, 3000000 + unsigned int etime; - unsigned int i; + unsigned int len, i; instType itype = pp->itype; int se; @@ -195,64 +228,104 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { a1logd(p->log, 2, "specbos_init_coms: About to init Serial I/O\n"); - amutex_lock(p->lock); - if (p->icom->port_type(p->icom) != icomt_serial - && p->icom->port_type(p->icom) != icomt_usbserial) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "specbos_init_coms: wrong communications type for device!\n"); + if (!(p->icom->dctype & icomt_serial) + && !(p->icom->dctype & icomt_fastserial)) { + a1logd(p->log, 1, "specbos_init_coms: wrong communications type for device! (dctype 0x%x)\n",p->icom->dctype); return inst_coms_fail; } - /* The tick to give up on */ - etime = msec_time() + (long)(1500.0 + 0.5); + /* Communications has already been established over BlueTooth serial */ + if (p->bt) { - a1logd(p->log, 1, "specbos_init_coms: Trying different baud rates (%u msec to go)\n",etime - msec_time()); + amutex_lock(p->lock); - /* Until we time out, find the correct baud rate */ - for (i = 0; msec_time() < etime; i++) { - if (brt[i] == baud_nc) { - i = 0; - } - a1logd(p->log, 5, "specbos_init_coms: trying baud ix %d\n",brt[i]); - if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none, - stop_1, length_8)) != ICOM_OK) { + /* Let instrument get its act together */ + msec_sleep(600); + + /* Get the instrument identification */ + if ((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok) { amutex_unlock(p->lock); - a1logd(p->log, 5, "specbos_init_coms: set_ser_port failed with 0x%x\n",se); - return specbos_interp_code((inst *)p, icoms2specbos_err(se));; /* Give up */ + a1logd(p->log, 2, "specbos_init_coms: idn didn't return\n"); + return ev; } + /* We need to setup communications */ + } else { + int delayms = 0; + amutex_lock(p->lock); - /* Check instrument is responding */ - if (((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask) - != inst_coms_fail) { - break; /* We've got coms or user abort */ - } + /* The tick to give up on */ + etime = msec_time() + (long)(1500.0 + 0.5); - /* Check for user abort */ - if (p->uicallback != NULL) { - inst_code ev; - if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) { + a1logd(p->log, 1, "specbos_init_coms: Trying different baud rates (%u msec to go)\n",etime - msec_time()); + + /* Spectraval Bluetooth serial doesn't seem to actuall function */ + /* until 600msec after it is opened. We get arroneos "AT+JSCR\r\n" reply */ + /* within that time, and it won't re-open after closing. */ + if (p->icom->dctype & icomt_btserial) + delayms = 600; + + /* Until we time out, find the correct baud rate */ + for (i = 0; msec_time() < etime; i++) { + if (brt[i] == baud_nc) { + i = 0; + } + + /* Only connect at 115200 if bluetooth */ + if ((p->icom->dctype & icomt_btserial) != 0 && brt[i] != baud_115200) + continue; + + a1logd(p->log, 5, "specbos_init_coms: Trying %s baud, %d msec to go\n", + baud_rate_to_str(brt[i]), etime- msec_time()); + if ((se = p->icom->set_ser_port_ex(p->icom, fc_None, brt[i], parity_none, + stop_1, length_8, delayms)) != ICOM_OK) { amutex_unlock(p->lock); - a1logd(p->log, 1, "specbos_init_coms: user aborted\n"); - return inst_user_abort; + a1logd(p->log, 5, "specbos_init_coms: set_ser_port failed with 0x%x\n",se); + return specbos_interp_code((inst *)p, icoms2specbos_err(se));; /* Give up */ + } + +// if ((p->icom->sattr & icom_bt) != 0) +// specbos_command(p, "\r", buf, MAX_MES_SIZE, 0.5); + + /* Check instrument is responding */ + if (((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask) + != inst_coms_fail) { + goto got_coms; /* We've got coms or user abort */ + } + + /* Check for user abort */ + if (p->uicallback != NULL) { + inst_code ev; + if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) { + amutex_unlock(p->lock); + a1logd(p->log, 1, "specbos_init_coms: user aborted\n"); + return inst_user_abort; + } } } - } - if (msec_time() >= etime) { /* We haven't established comms */ + /* We haven't established comms */ amutex_unlock(p->lock); a1logd(p->log, 2, "specbos_init_coms: failed to establish coms\n"); return inst_coms_fail; + + got_coms:; } /* Check the response */ + len = strlen(buf); p->model = 0; - if (strncmp (buf, "SB05", 4) == 0) /* Special case */ + if (len >= 4 && strncmp(buf, "SB05", 4) == 0) { p->model = 1201; - else { - if (strlen(buf) < 11 + } else if ((len >= 10 && strncmp(buf, "JETI_SDCM3", 10) == 0) + || (len >= 9 && strncmp(buf, "DCM3_JETI", 9) == 0) + || (len >= 17 && strncmp(buf, "PECFIRM_JETI_1501", 18) == 0) + || (len >= 18 && strncmp(buf, "SPECFIRM_JETI_1501", 17) == 0)) { + p->model = 1501; + } else { + if (len < 11 || sscanf(buf, "JETI_SB%d\r", &p->model) != 1) { amutex_unlock(p->lock); a1logd(p->log, 2, "specbos_init_coms: unrecognised ident string '%s'\n",icoms_fix(buf)); @@ -260,7 +333,9 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { } } - if (p->model != 1201 && p->model != 1211) { + if (p->model != 1201 + && p->model != 1211 + && p->model != 1501) { amutex_unlock(p->lock); a1logd(p->log, 2, "specbos_init_coms: unrecognised model %04d\n",p->model); return inst_unknown_model; @@ -269,6 +344,40 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { p->gotcoms = 1; + /* See if it's a 1501 or 1511 */ + if (p->model == 1501) { + int dispen = 0; + + if ((ev = specbos_command(p, "*conf:dispen?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "specbos_init_coms: failed to get display status\n"); + return inst_protocol_error; + } + if (sscanf(buf, "%d ",&dispen) != 1) { + amutex_unlock(p->lock); + a1loge(p->log, 1, "specbos_init_inst: failed to parse display status\n"); + return ev; + } + a1logd(p->log, 1, " spectraval %s display\n",dispen ? "has" : "doesn't have"); + if (dispen) { + p->model = 1511; + + /* Set remote mode */ + if ((ev = specbos_command(p, "*REMOTE 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "specbos_init_coms: failed to set remote mode\n"); + return inst_protocol_error; + } + } + + /* Check Bluetooth status */ + if ((ev = specbos_command(p, "*conf:bten?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "specbos_init_coms: failed to get Bluetooth status\n"); + return inst_protocol_error; + } + } + #ifdef NEVER /* Test a change in baud rate on next plug in */ a1logd(p->log, 2, "specbos_init_coms: changing baudrate\n"); // if ((ev = specbos_command(p, "*para:baud 384\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) @@ -285,12 +394,11 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { #endif amutex_unlock(p->lock); - return inst_ok; } /* - Notes on commands + Notes on commands for 1201: *conf is temporary, *para can be saved to instrument Since we set the instrument up every time, use *conf ? @@ -378,7 +486,8 @@ int specbos_diff_thread(void *pp) { int pos; amutex_lock(p->lock); - rv1 = specbos_get_diffpos(p, &pos, 1); + if (p->model != 1501 && p->model != 1511) + rv1 = specbos_get_diffpos(p, &pos, 1); rv2 = specbos_get_target_laser(p, &p->laser, 1); amutex_unlock(p->lock); @@ -419,9 +528,11 @@ specbos_init_inst(inst *pp) { amutex_lock(p->lock); - /* Restore the instrument to it's default settings */ - if ((ev = specbos_command(p, "*conf:default\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) - return ev; + if (p->model != 1501 && p->model != 1511) { + /* Restore the instrument to it's default settings */ + if ((ev = specbos_command(p, "*conf:default\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) + return ev; + } /* Set calibration type to auto on ambient cap */ if ((ev = specbos_command(p, "*para:calibn 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { @@ -429,78 +540,177 @@ specbos_init_inst(inst *pp) { return ev; } - /* Set auto exposure/integration time */ - /* Set calibration type to auto on ambient cap */ - if ((ev = specbos_command(p, "*para:expo 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok - || (ev = specbos_command(p, "*para:adapt 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + if (p->model == 1501 || p->model == 1511) { + /* Set auto exposure/integration time */ + if ((ev = specbos_command(p, "*para:tint 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + } else { + /* Set auto exposure/integration time */ + if ((ev = specbos_command(p, "*para:expo 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok +// || (ev = specbos_command(p, "*para:adapt 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok + ) { + amutex_unlock(p->lock); + return ev; + } } - p->measto = 20.0; /* default */ + p->measto = 20.0; /* Set default. Specbos default is 60.0 */ if (p->model == 1211) - p->measto = 5.0; /* Same overall time as i1d3 ?? */ + p->measto = 6.0; /* Same overall time as i1d3 ?? */ else if (p->model == 1201) - p->measto = 15.0; + p->measto = 16.0; + else if (p->model == 1501 || p->model == 1511) + p->measto = 6.0; - /* Set maximum integration time to speed up display measurement */ - sprintf(mes, "*conf:maxtin %d\r", (int)(p->measto * 1000.0+0.5)); - if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } + /* Implement max auto int. time, to speed up display measurement */ + if (p->model == 1501 || p->model == 1511) { + int maxaver = 2; /* Maximum averages for auto int time */ + double dmaxtint; + int maxtint; - /* Set the measurement function to be Radiometric spectrum */ - if ((ev = specbos_command(p, "*conf:func 6\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } + /* Actual time taken depends on maxtint, autoavc & fudge factor. */ + dmaxtint = p->measto/(maxaver + 3.5); - /* Set the measurement format to ASCII */ - if ((ev = specbos_command(p, "*conf:form 4\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } + maxtint = (int)(dmaxtint * 1000.0+0.5); - if ((ev = specbos_command(p, "*para:wavbeg?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - if (sscanf(buf, "Predefined start wave: %lf ",&p->wl_short) != 1) { - amutex_unlock(p->lock); - a1loge(p->log, 1, "specbos_init_inst: failed to parse start wave\n"); - return ev; - } - a1logd(p->log, 1, " Short wl range %f\n",p->wl_short); + if (maxtint < 1000 || maxtint > 64999) + error("specbos: assert, maxtint %d out of range",maxtint); - if ((ev = specbos_command(p, "*para:wavend?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - if (sscanf(buf, "Predefined end wave: %lf ",&p->wl_long) != 1) { - amutex_unlock(p->lock); - a1loge(p->log, 1, "specbos_init_inst: failed to parse end wave\n"); - return ev; - } - if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */ - p->wl_long = 830.0; /* Limit it to useful visual range */ + /* Set maximum integration time */ + sprintf(mes, "*para:maxtint %d\r", maxtint); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } - a1logd(p->log, 1, " Long wl range %f\n",p->wl_long); + /* Set maximum number of auto averages. Min value is 2 */ + sprintf(mes, "*para:maxaver %d\r", maxaver); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } - p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5); + /* spectraval doesn't support *fetch:XYZ command */ + p->noXYZ = 1; - /* Set the wavelength range and resolution */ - sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5)); - if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + } else { + double dmaxtin; + int maxtin; + + dmaxtin = p->measto/2.5; /* Fudge factor */ + maxtin = (int)(dmaxtin * 1000.0+0.5); + + if (maxtin < 1000 || maxtin > 64999) + error("specbos: assert, maxtin %d out of range",maxtin); + + /* Set maximum integration time */ + sprintf(mes, "*para:maxtint %d\r", maxtin); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } } - /* Set to average just 1 reading */ - if ((ev = specbos_command(p, "*conf:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + if (p->model == 1501 || p->model == 1511) { + int wstart, wend, wstep; + + /* Set the measurement format to None. We will read measurement manually. */ + /* (0 = None, 1 = Binary, 2 = ASCII) */ + if ((ev = specbos_command(p, "*para:form 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + + if ((ev = specbos_command(p, "*para:wran?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + if (sscanf(buf, "%d %d %d",&wstart,&wend,&wstep) != 3) { + amutex_unlock(p->lock); + a1loge(p->log, 1, "specbos_init_inst: failed to parse wavelength range\n"); + return ev; + } + + p->wl_short = (double)wstart; + p->wl_long = (double)wend; + + a1logd(p->log, 1, " Short wl range %f\n",p->wl_short); + + if (p->wl_long > 830.0) + p->wl_long = 830.0; /* Limit it to useful visual range */ + + a1logd(p->log, 1, " Long wl range %f\n",p->wl_long); + + p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5); + + /* Set the wavelength range and resolution */ + sprintf(mes, "*para:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5)); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + + /* Set to average just 1 reading */ + if ((ev = specbos_command(p, "*para:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + } else { + + /* Set the measurement function to be Radiometric spectrum */ + if ((ev = specbos_command(p, "*conf:func 6\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + + /* Set the measurement format to ASCII */ + if ((ev = specbos_command(p, "*conf:form 4\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + + if ((ev = specbos_command(p, "*para:wavbeg?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + if (sscanf(buf, "Predefined start wave: %lf ",&p->wl_short) != 1) { + amutex_unlock(p->lock); + a1loge(p->log, 1, "specbos_init_inst: failed to parse start wave\n"); + return ev; + } + a1logd(p->log, 1, " Short wl range %f\n",p->wl_short); + + if ((ev = specbos_command(p, "*para:wavend?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + if (sscanf(buf, "Predefined end wave: %lf ",&p->wl_long) != 1) { + amutex_unlock(p->lock); + a1loge(p->log, 1, "specbos_init_inst: failed to parse end wave\n"); + return ev; + } + if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */ + p->wl_long = 830.0; /* Limit it to useful visual range */ + + a1logd(p->log, 1, " Long wl range %f\n",p->wl_long); + + p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5); + + /* Set the wavelength range and resolution */ + sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5)); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + + /* Set to average just 1 reading */ + if ((ev = specbos_command(p, "*conf:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } } if (p->log->verb) { @@ -558,6 +768,7 @@ static inst_code specbos_imp_measure_set_refresh(specbos *p); static inst_code specbos_imp_set_refresh(specbos *p); /* Get the ambient diffuser position */ +/* (Not valid for 1501 or 1511) */ /* (This is not multithread safe) */ static inst_code specbos_get_diffpos( @@ -569,7 +780,7 @@ specbos_get_diffpos( int ec; /* See if we're in emissive or ambient mode */ - if ((ec = specbos_fcommand(p, "*contr:mhead?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) { + if ((ec = specbos_fcommand(p, "*contr:mhead?\r", buf, MAX_MES_SIZE, 1.0, 1, tnorm, nd)) != inst_ok) { return specbos_interp_code((inst *)p, ec); } if (sscanf(buf, "mhead: %d ",pos) != 1) { @@ -591,17 +802,61 @@ specbos_get_target_laser( int ec; int lstate; - if ((ec = specbos_fcommand(p, "*contr:laser?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) { + if ((ec = specbos_fcommand(p, "*contr:laser?\r", buf, MAX_MES_SIZE, 1.0, 1, tnorm, nd)) != inst_ok) { return specbos_interp_code((inst *)p, ec); } - if (sscanf(buf, "laser: %d ",&lstate) != 1) { - a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n"); - return inst_protocol_error; + if (p->model == 1501 || p->model == 1511) { + if (sscanf(buf, "%d ",&lstate) != 1) { + a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n"); + return inst_protocol_error; + } + } else { + if (sscanf(buf, "laser: %d ",&lstate) != 1) { + a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n"); + return inst_protocol_error; + } } *laser = lstate; return inst_ok; } +/* Configure for averaging */ +static inst_code set_average(specbos *p, int nav, int lock) { + char mes[100]; + char buf[MAX_MES_SIZE]; + inst_code ev; + + if (lock) amutex_lock(p->lock); + + if (p->model == 1501 || p->model == 1511) { + /* Set number to average */ + sprintf(mes, "*para:aver %d\r", nav); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + if (lock) amutex_unlock(p->lock); + return ev; + } + } else { + /* Set number to average */ + sprintf(mes, "*conf:aver %d\r", nav); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + if (lock) amutex_unlock(p->lock); + return ev; + } + } + +#ifdef NEVER /* Doesn't seem to make any difference ? */ + /* Only dark average at start of batch */ + sprintf(mes, "*conf:darkm %d\r", nav == 1 ? 0 : 1); + if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + if (lock) amutex_unlock(p->lock); + return ev; + } +#endif + + if (lock) amutex_unlock(p->lock); + return inst_ok; +} + /* Read a single sample */ /* Return the dtp error code */ static inst_code @@ -622,9 +877,15 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ if (!p->inited) return inst_no_init; + /* Request calibration if it is needed */ + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission + && p->trans_white.spec_n == 0) { + return inst_needs_cal; + } + amutex_lock(p->lock); - if (p->trig == inst_opt_trig_user) { + if (!p->doing_cal && p->trig == inst_opt_trig_user) { amutex_unlock(p->lock); if (p->uicallback == NULL) { @@ -650,7 +911,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ amutex_lock(p->lock); /* Progromatic Trigger */ - } else { + } else if (!p->doing_cal) { /* Check for abort */ if (p->uicallback != NULL && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) { @@ -659,21 +920,23 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ } } - /* See if we're in emissive or ambient mode */ - if ((rv = specbos_get_diffpos(p, &pos, 0) ) != inst_ok) { - amutex_unlock(p->lock); - return rv; - } - - if (p->mode & inst_mode_ambient) { - if (pos != 1) { + if (p->model != 1501 && p->model != 1511) { + /* See if we're in emissive or ambient mode */ + if ((rv = specbos_get_diffpos(p, &pos, 0) ) != inst_ok) { amutex_unlock(p->lock); - return specbos_interp_code((inst *)p, SPECBOS_SPOS_AMB); + return rv; } - } else { - if (pos != 0) { - amutex_unlock(p->lock); - return specbos_interp_code((inst *)p, SPECBOS_SPOS_EMIS); + + if (p->mode & inst_mode_ambient) { + if (pos != 1) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, SPECBOS_SPOS_AMB); + } + } else { + if (pos != 0) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, SPECBOS_SPOS_EMIS); + } } } @@ -693,9 +956,26 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ } } + /* Set to average 10 readings for transmission */ + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) { + if ((rv = set_average(p, 10, 0)) != inst_ok) + return rv; + } + + if (p->model == 1501 || p->model == 1511) { + /* Set the measurement format to None. We will read measurement manually. */ + if ((rv = specbos_command(p, "*para:form 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return rv; + } + } + /* Trigger a measurement */ /* (Note that ESC will abort it) */ - ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0); + if (p->model == 1501 || p->model == 1511) + ec = specbos_fcommand(p, "*meas:refer\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0); + else + ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0); // Test out bug workaround // if (!p->badCal) ec = SPECBOS_EXCEED_CAL_WL; @@ -719,15 +999,24 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ /* Re-set the wavelength range and resolution */ sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5)); if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) + set_average(p, 1, 0); amutex_unlock(p->lock); return ev; } p->badCal = 1; /* Try command again */ - ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0); + if (p->model == 1501 || p->model == 1511) + ec = specbos_fcommand(p, "*meas:refer\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0); + else + ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0); } + /* Restore single reading if transmission */ + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) + set_average(p, 1, 0); + if (ec != SPECBOS_OK) { amutex_unlock(p->lock); return specbos_interp_code((inst *)p, ec); @@ -738,7 +1027,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ ec = SPECBOS_COMMAND; } else { /* Read the XYZ */ - ec = specbos_fcommand(p, "*fetch:XYZ\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0); + ec = specbos_fcommand(p, "*fetch:XYZ\r", buf, MAX_RD_SIZE, 0.5, 3, tnorm, 0); } @@ -758,26 +1047,52 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ p->noXYZ = 1; - if ((ec = specbos_fcommand(p, "*fetch:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0)) - != SPECBOS_OK) { - amutex_unlock(p->lock); - return specbos_interp_code((inst *)p, ec); - } - if (sscanf(buf, "Luminance[cd/m^2]: %lf ", &Yxy[0]) != 1) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); - return inst_protocol_error; + if (p->model == 1501 || p->model == 1511) { + if ((ec = specbos_fcommand(p, "*calc:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0)) + != SPECBOS_OK) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, ec); + } + if (sscanf(buf, "%lf ", &Yxy[0]) != 1) { + amutex_unlock(p->lock); + a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); + return inst_protocol_error; + } + } else { + if ((ec = specbos_fcommand(p, "*fetch:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0)) + != SPECBOS_OK) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, ec); + } + if (sscanf(buf, "Luminance[cd/m^2]: %lf ", &Yxy[0]) != 1) { + amutex_unlock(p->lock); + a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); + return inst_protocol_error; + } } - if ((ec = specbos_fcommand(p, "*fetch:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0)) - != SPECBOS_OK) { - amutex_unlock(p->lock); - return specbos_interp_code((inst *)p, ec); - } - if (sscanf(buf, "Chrom_x: %lf Chrom_y: %lf ", &Yxy[1], &Yxy[2]) != 2) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); - return inst_protocol_error; + if (p->model == 1501 || p->model == 1511) { + if ((ec = specbos_fcommand(p, "*calc:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0)) + != SPECBOS_OK) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, ec); + } + if (sscanf(buf, " %lf %lf ", &Yxy[1], &Yxy[2]) != 2) { + amutex_unlock(p->lock); + a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); + return inst_protocol_error; + } + } else { + if ((ec = specbos_fcommand(p, "*fetch:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0)) + != SPECBOS_OK) { + amutex_unlock(p->lock); + return specbos_interp_code((inst *)p, ec); + } + if (sscanf(buf, "Chrom_x: %lf Chrom_y: %lf ", &Yxy[1], &Yxy[2]) != 2) { + amutex_unlock(p->lock); + a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf); + return inst_protocol_error; + } } icmYxy2XYZ(val->XYZ, Yxy); @@ -790,9 +1105,10 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ if (clamp) icmClamp3(val->XYZ, val->XYZ); val->loc[0] = '\000'; + /* Ambient or Trans 90/diffuse */ if (p->mode & inst_mode_ambient) { val->mtype = inst_mrt_ambient; - } else + } else /* Emis or Trans diffuse/90 */ val->mtype = inst_mrt_emission; val->XYZ_v = 1; /* These are absolute XYZ readings */ val->sp.spec_n = 0; @@ -800,32 +1116,45 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ rv = inst_ok; - /* spectrum data is returned only if requested */ - if (p->mode & inst_mode_spectral) { + /* spectrum data is returned only if requested, */ + /* or if we are emulating transmission mode */ + if (p->mode & inst_mode_spectral + || (p->mode & inst_mode_illum_mask) == inst_mode_transmission) { int tries, maxtries = 5; - int i, xsize; + int ii,i, xsize; char *cp, *ncp; - /* (Format 12 doesn't seem to work on the 1211) */ - /* (Format 9 reportedly doesn't work on the 1201) */ - /* The folling works on the 1211 and is reported to work on the 1201 */ + if (p->model == 1501 || p->model == 1511) { + /* Turn on spetrum output */ + if ((ec = specbos_command(p, "*para:form 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + amutex_unlock(p->lock); + return ec; + } + ii = 0; /* Spectrum from the start */ + } else { + ii = -2; /* Skip first two tokens */ + + /* (Format 12 doesn't seem to work on the 1211) */ + /* (Format 9 reportedly doesn't work on the 1201) */ + /* The folling works on the 1211 and is reported to work on the 1201 */ + } /* Because the specbos doesn't use flow control in its */ /* internal serial communications, it may overrun */ /* the FT232R buffer, so retry fetching the spectra if */ /* we get a comm error or parsing error. */ - for (tries = 0;;) { + for (tries = 0; tries < maxtries; tries++) { /* Fetch the spectral readings */ - ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 4.0, 2+p->nbands+1, 0, 0); - tries++; + if (p->model == 1501 || p->model == 1511) + ec = specbos_fcommand(p, "*calc:sprad\r", buf, MAX_RD_SIZE, 4.0, + 1, tspec, 0); + else + ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 4.0, + 2+p->nbands+1, tnorm, 0); if (ec != SPECBOS_OK) { - if (tries > maxtries) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "specbos_fcommand: failed with 0x%x\n",ec); - return specbos_interp_code((inst *)p, ec); - } - continue; /* Retry the fetch */ + a1logd(p->log, 1, "specbos_fcommand: failed with 0x%x\n",ec); + goto try_again; /* Retry the fetch */ } val->sp.spec_n = p->nbands; @@ -835,19 +1164,27 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ /* Spectral data is in W/nm/m^2 */ val->sp.norm = 1.0; cp = buf; - for (i = -2; i < val->sp.spec_n; i++) { + for (i = ii; i < val->sp.spec_n; i++) { if ((ncp = strchr(cp, '\r')) == NULL) { - a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra at %d/%d\n",i+1,val->sp.spec_n); - if (tries > maxtries) { - amutex_unlock(p->lock); - return inst_protocol_error; - } - continue; /* Retry the fetch and parse */ + a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra '%s' at %d/%d\n",cp,i+1,val->sp.spec_n); + goto try_again; /* Retry the fetch and parse */ } *ncp = '\000'; if (i >= 0) { - a1logd(p->log, 6, "sample %d/%d got %f from '%s'\n",i+1,val->sp.spec_n,atof(cp),cp); - val->sp.spec[i] = 1000.0 * atof(cp); /* Convert to mW/m^2/nm */ + double wl, sp = -1e6; + if (p->model == 1501 || p->model == 1511) { + if (sscanf(cp, "%lf %lf", &wl, &sp) != 2) + sp = -1e6; + } else { + if (sscanf(cp, "%lf", &sp) != 1) + sp = -1e6; + } + if (sp == -1e6) { + a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra '%s' at %d/%d\n",cp,i+1,val->sp.spec_n); + goto try_again; /* Retry the fetch and parse */ + } + a1logd(p->log, 6, "sample %d/%d got %f from '%s'\n",i+1,val->sp.spec_n,sp,cp); + val->sp.spec[i] = 1000.0 * sp; /* Convert to mW/m^2/nm */ if (p->mode & inst_mode_ambient) val->mtype = inst_mrt_ambient; } @@ -855,11 +1192,127 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ } /* We've parsed correctly, so don't retry */ break; + + try_again:; + } + if (tries >= maxtries) { + a1logd(p->log, 1, "specbos_fcommand: ran out of retries\n"); + amutex_unlock(p->lock); + return inst_protocol_error; } a1logd(p->log, 1, "specbos_read_sample: got total %d samples/%d expected in %d tries\n",i,val->sp.spec_n, tries); + } amutex_unlock(p->lock); + /* Emulate transmission mode */ + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) { + int i; + + if (p->trans_white.spec_n != val->sp.spec_n + || p->trans_white.spec_wl_short != val->sp.spec_wl_short + || p->trans_white.spec_wl_long != val->sp.spec_wl_long) { + a1logd(p->log, 1, "specbos_read_sample: Emulated transmission mode got mismatched white ref. !"); + return specbos_interp_code((inst *)p, SPECBOS_INTERNAL_ERROR); + } + + for (i = 0; i < p->trans_white.spec_n; i++) { + double vv; + + if ((p->trans_white.spec[i] * 3.0) < val->sp.spec[i]) { + val->sp.spec[i] = 0.0; + } else { + val->sp.spec[i] = 100.0 * val->sp.spec[i]/p->trans_white.spec[i]; + } + } + val->sp.norm = 100.0; + + /* Do some filtering of the short wavelengths. */ + /* (This is really compensating for lower instrument sensitivity */ + /* and an assumed 'A' type illuminant source.) */ + { + int i, ii, j, k; + double w, ifw, fw, nn; + double wl, we, vv; + xspect ts = val->sp; /* Structure copy */ + double refl; + + /* Do a linear regression to establish and end reflection value */ + { + double s = 0.0, sxx = 0.0, sy = 0.0, sx = 0.0, sxy = 0.0; + + ii = XSPECT_XIX(&val->sp, 400.0); /* End index */ + for (i = 0; i < ii; i++) { + s++; + sxx += i * i; + sx += i; + sy += ts.spec[i]; + sxy += i * ts.spec[i]; + } + refl = (sxx * sy - sx * sxy)/(s * sxx - sx * sx); +//printf("~1 [0] = %f, linear regression = %f\n",ts.spec[0],refl); + } + + ii = XSPECT_XIX(&val->sp, 500.0); /* End index */ + ifw = 5.0; /* Initial +/-width */ + for (i = 0; i < ii; i++) { + wl = XSPECT_XWL(&val->sp, i); + vv = (ii - i)/(double)ii; /* Reduce width as we increase center wl */ + fw = pow(vv, 1.7) * ifw; + w = nn = vv = 0.0; + + /* Scan down */ + for (j = 0; ; j++) { + w = wl - XSPECT_XWL(&val->sp, i - j); /* Offset we're at */ + if (w >= fw) + break; + + we = fw - w; + we = sqrt(we); + nn += we; + + if ((i - j) < 0) { /* Reflect */ + vv += we * (2.0 * refl - ts.spec[i + j]); + } else { + vv += we * ts.spec[i - j]; + } + } + + /* Scan up */ + for (j = 0; ; j++) { + w = XSPECT_XWL(&val->sp, i + j) - wl; /* Offset we're at */ + if (w >= fw) + break; + we = fw - w; + we = sqrt(we); + nn += we; + vv += we * ts.spec[i + j]; + } + vv /= nn; + val->sp.spec[i] = vv; + } + } + + /* Convert to XYZ */ + if (p->conv == NULL) { + p->conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, + icxNoClamp); + if (p->conv == NULL) { + a1logd(p->log, 1, "specbos_read_sample: Emulated transmission new_xsp2cie() failed"); + return specbos_interp_code((inst *)p, SPECBOS_INTERNAL_ERROR); + } + } + p->conv->convert(p->conv, val->XYZ, &val->sp); + if (clamp) + icmClamp3(val->XYZ, val->XYZ); + val->XYZ_v = 1; + val->XYZ[0] *= 100.0; + val->XYZ[1] *= 100.0; + val->XYZ[2] *= 100.0; + + val->mtype = inst_mrt_transmissive; + } + if (user_trig) return inst_user_trig; @@ -879,17 +1332,36 @@ specbos_imp_set_refresh(specbos *p) { /* Set synchronised read if we should do so */ if (p->refrmode != 0 && p->refrvalid) { char mes[100]; - if ((rv = specbos_command(p, "*conf:cycmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; + if (p->model == 1501 || p->model == 1511) { + if ((rv = specbos_command(p, "*para:syncmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } + } else { + if ((rv = specbos_command(p, "*conf:cycmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } } - sprintf(mes,"*conf:cyctim %f\r",p->refperiod * 1e6); - if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; + if (p->model == 1501 || p->model == 1511) { + sprintf(mes,"*para:syncfreq %f\r",1.0/p->refperiod); + if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } + } else { + sprintf(mes,"*conf:cyctim %f\r",p->refperiod * 1e6); + if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } } a1logd(p->log,5,"specbos_imp_set_refresh set refresh rate to %f Hz\n",1.0/p->refperiod); } else { - if ((rv = specbos_command(p, "*conf:cycmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; + if (p->model == 1501 || p->model == 1511) { + if ((rv = specbos_command(p, "*para:syncmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } + } else { + if ((rv = specbos_command(p, "*conf:cycmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { + return rv; + } } a1logd(p->log,5,"specbos_imp_set_refresh set non-refresh mode\n"); } @@ -920,16 +1392,32 @@ double *ref_rate return rv; } - if ((ec = specbos_fcommand(p, "*contr:cyctim 200 4000\r", buf, MAX_MES_SIZE, 5.0, 1, 2, 0)) != SPECBOS_OK) { - return specbos_interp_code((inst *)p, ec); + if (p->model == 1501 || p->model == 1511) { + if ((ec = specbos_fcommand(p, "*meas:flic\r", buf, MAX_MES_SIZE, 30.0, 1, trefr, 0)) != SPECBOS_OK) { + return specbos_interp_code((inst *)p, ec); + } + } else { + if ((ec = specbos_fcommand(p, "*contr:cyctim 200 4000\r", buf, MAX_MES_SIZE, 5.0, 1, trefr, 0)) != SPECBOS_OK) { + return specbos_interp_code((inst *)p, ec); + } } - if ((cp = strchr(buf, 'c')) == NULL) - cp = buf; - if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) { - a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf)); - *ref_rate = 0.0; - return inst_misread; + if (p->model == 1501 || p->model == 1511) { + double ffreq; + if (sscanf(buf+1, "%lf ", &ffreq) != 1) { + a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf)); + *ref_rate = 0.0; + return inst_misread; + } + refperiod = 1000.0/ffreq; + } else { + if ((cp = strchr(buf, 'c')) == NULL) + cp = buf; + if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) { + a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf)); + *ref_rate = 0.0; + return inst_misread; + } } if (refperiod == 0.0) @@ -1033,6 +1521,12 @@ static inst_code specbos_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal a_cals |= inst_calt_ref_freq; } + if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) { + if (p->trans_white.spec_n == 0) + n_cals |= inst_calt_trans_vwhite; + a_cals |= inst_calt_trans_vwhite; + } + if (pn_cals != NULL) *pn_cals = n_cals; @@ -1047,6 +1541,7 @@ inst_code specbos_calibrate( inst *pp, inst_cal_type *calt, /* Calibration type to do/remaining */ inst_cal_cond *calc, /* Current condition/desired condition */ +inst_calc_id_type *idtype, /* Condition identifier type */ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ ) { specbos *p = (specbos *)pp; @@ -1058,11 +1553,14 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (!p->inited) return inst_no_init; + *idtype = inst_calc_id_none; id[0] = '\000'; if ((ev = specbos_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok) return ev; + a1logd(p->log,4,"specbos_calibrate: needed 0x%x, avaialble 0x%x\n",needed, available); + /* Translate inst_calt_all/needed into something specific */ if (*calt == inst_calt_all || *calt == inst_calt_needed @@ -1082,6 +1580,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ /* See if it's a calibration we understand */ if (*calt & ~available & inst_calt_all_mask) { + a1logd(p->log,4,"specbos_calibrate: not a calibration we understand\n"); return inst_unsupported; } @@ -1100,6 +1599,65 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ *calt &= ~inst_calt_ref_freq; } + + /* If we are doing a transmission white reference calibrate */ + if ((*calt & inst_calt_trans_vwhite) != 0 + && (*calc & inst_calc_cond_mask) == inst_calc_man_trans_white + && (p->mode & inst_mode_illum_mask) == inst_mode_transmission) { + inst_mode cmode = p->mode; + int i; + ipatch val; + + a1logd(p->log,4,"specbos_calibrate: doing transmission white calib\n"); + + if (p->mode & inst_mode_ambient) + p->mode = inst_mode_emis_ambient | inst_mode_spectral; + else + p->mode = inst_mode_emis_tele | inst_mode_spectral; + p->doing_cal = 1; + + /* Set to average 50 readings */ + if ((ev = set_average(p, 50, 1)) != inst_ok) + return ev; + + if ((ev = specbos_read_sample(pp, "Transmission White", &val, 0)) != inst_ok) { + a1logd(p->log,1,"specbos_calibrate: Transmission white cal failed with 0x%x\n",ev); + p->mode = cmode; + p->doing_cal = 0; + set_average(p, 1, 1); + return ev; + } + p->trans_white = val.sp; /* Struct copy */ + + /* Restore average */ + if ((ev = set_average(p, 1, 1)) != inst_ok) + return ev; + + // ~~~~9999 check white quality + + *calt &= ~inst_calt_trans_vwhite; + + p->mode = cmode; + p->doing_cal = 0; + } + + /* Make sure there's the right condition for any remaining calibrations. */ + if (*calt & inst_calt_trans_vwhite) {/* Transmissvice white for emulated transmission */ + *idtype = inst_calc_id_none; + id[0] = '\000'; + if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_white) { + *calc = inst_calc_man_trans_white; + a1logd(p->log,4,"specbos_calibrate: needs calc 0x%x\n",*calc); + return inst_cal_setup; + } + } + + /* Go around again if we've still got calibrations to do */ + if (*calt & inst_calt_all_mask) { + a1logd(p->log,4,"specbos_calibrate: more calibrations to do\n"); + return inst_cal_setup; + } + return inst_ok; } @@ -1361,6 +1919,7 @@ specbos_interp_code(inst *pp, int ec) { case SPECBOS_OVEREXPOSED: case SPECBOS_UNDEREXPOSED: + case SPECBOS_ADAPT_INT_TIME: return inst_misread | ec; case SPECBOS_PASSWORD: @@ -1368,7 +1927,6 @@ specbos_interp_code(inst *pp, int ec) { case SPECBOS_USERFILE_CHSUM: case SPECBOS_USERFILE2_CHSUM: case SPECBOS_USERFILE2_ARG: - case SPECBOS_ADAPT_INT_TIME: case SPECBOS_NO_SHUTTER: case SPECBOS_NO_DARK_MEAS: case SPECBOS_NO_REF_MEAS: @@ -1434,6 +1992,8 @@ specbos_del(inst *pp) { if (p->icom != NULL) p->icom->del(p->icom); amutex_del(p->lock); + if (p->conv != NULL) + p->conv->del(p->conv); p->vdel(pp); free(p); } @@ -1449,13 +2009,18 @@ inst3_capability *pcap3) { inst2_capability cap2 = 0; cap1 |= inst_mode_emis_tele - | inst_mode_ambient + | inst_mode_trans_spot /* Emulated transmission mode diffuse/90 */ + | inst_mode_trans_spot_a /* Emulated transmission mode 90/diffuse */ | inst_mode_colorimeter | inst_mode_spectral | inst_mode_emis_refresh_ovd | inst_mode_emis_norefresh_ovd ; + if (p->model != 1501 && p->model != 1511) { + cap1 |= inst_mode_ambient; + } + /* can inst2_has_sensmode, but not report it asynchronously */ cap2 |= inst2_prog_trig | inst2_user_trig @@ -1500,9 +2065,13 @@ int *conf_ix || *conf_ix > 1) { /* Return current configuration measrement modes */ amutex_lock(p->lock); - if ((ev = specbos_get_diffpos(p, &pos, 0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + if (p->model != 1501 && p->model != 1511) { + if ((ev = specbos_get_diffpos(p, &pos, 0)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + } else { + pos = 0; /* 1501 & 1511 only have emssion */ } amutex_unlock(p->lock); } else { @@ -1534,6 +2103,7 @@ int *conf_ix /* Check device measurement mode */ static inst_code specbos_check_mode(inst *pp, inst_mode m) { + specbos *p = (specbos *)pp; inst_mode cap; if (!pp->gotcoms) @@ -1547,9 +2117,17 @@ static inst_code specbos_check_mode(inst *pp, inst_mode m) { if (m & ~cap) return inst_unsupported; - /* Only tele emission mode supported */ + /* 1501 doesn't support ambient */ + if ((p->model == 1501 || p->model == 1511) + && IMODETST(m, inst_mode_emis_ambient)) { + return inst_unsupported; + } + + /* Only tele emission, ambient and (emulated) transmision modes supported */ if (!IMODETST(m, inst_mode_emis_tele) - && !IMODETST(m, inst_mode_emis_ambient)) { + && !IMODETST(m, inst_mode_trans_spot) + && !IMODETST(m, inst_mode_trans_spot_a) + && !IMODETST(m, inst_mode_emis_ambient)) { return inst_unsupported; } @@ -1562,12 +2140,13 @@ static inst_code specbos_set_mode(inst *pp, inst_mode m) { int refrmode; inst_code ev; - if ((ev = specbos_check_mode(pp, m)) != inst_ok) + if ((ev = specbos_check_mode(pp, m)) != inst_ok) { + a1logd(p->log,1,"specbos_set_mode 0x%x invalid\n",m); return ev; + } p->mode = m; - if (p->model != 1201) { /* Can't set refresh mode on 1201 */ /* Effective refresh mode may change */ @@ -1714,8 +2293,7 @@ static inst_code specbos_set_disptype(inst *pp, int ix) { * error if it hasn't been initialised. */ static inst_code -specbos_get_set_opt(inst *pp, inst_opt_type m, ...) -{ +specbos_get_set_opt(inst *pp, inst_opt_type m, ...) { specbos *p = (specbos *)pp; char buf[MAX_MES_SIZE]; inst_code ev = inst_ok; @@ -1790,7 +2368,17 @@ specbos_get_set_opt(inst *pp, inst_opt_type m, ...) if (!p->inited) return inst_no_init; - return inst_unsupported; + /* Use default implementation of other inst_opt_type's */ + { + inst_code rv; + va_list args; + + va_start(args, m); + rv = inst_get_set_opt_def(pp, m, args); + va_end(args); + + return rv; + } } /* Constructor */ -- cgit v1.2.3