summaryrefslogtreecommitdiff
path: root/spectro/specbos.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/specbos.c')
-rwxr-xr-x[-rw-r--r--]spectro/specbos.c260
1 files changed, 197 insertions, 63 deletions
diff --git a/spectro/specbos.c b/spectro/specbos.c
index 4c5e4ba..136fb34 100644..100755
--- a/spectro/specbos.c
+++ b/spectro/specbos.c
@@ -63,6 +63,7 @@
#include "sa_config.h"
#include "numsup.h"
#endif /* !SALONEINSTLIB */
+#include "cgats.h"
#include "xspect.h"
#include "insttypes.h"
#include "conv.h"
@@ -74,6 +75,9 @@ static inst_code specbos_interp_code(inst *pp, int ec);
#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
#define MAX_RD_SIZE 8000 /* Maximum reading message reply size */
+#define DEFAULT_TRANS_NAV 10 /* Default transmission mode number of averages */
+#define DEFAULT_NAV 1 /* Default other mode number of averages */
+
/* Interpret an icoms error into a SPECBOS error */
static int icoms2specbos_err(int se) {
if (se != ICOM_OK) {
@@ -132,13 +136,18 @@ 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. */
+ /* Over Bluetooth, we get an erroneous 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;
}
+ if (bread > 8 && strncmp(out, "AT+JSCR\r", 8) == 0) {
+ a1logd(p->log, 8, "specbos: ignored 'AT+JSCR\\r' response\n");
+ memmove(out, out+8, bsize-8);
+ bread -= 8;
+ }
/* See if there was an error, and remove any enquire codes */
for (dp = cp = out; *cp != '\000' && (dp - out) < bsize; cp++) {
@@ -221,7 +230,7 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
unsigned int etime;
unsigned int len, i;
- instType itype = pp->itype;
+ instType dtype = pp->dtype;
int se;
inst_code ev = inst_ok;
@@ -250,6 +259,8 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
return ev;
}
+ msec_sleep(600);
+
/* We need to setup communications */
} else {
int delayms = 0;
@@ -261,7 +272,7 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
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 */
+ /* until 600msec after it is opened. We get an erroneous "AT+JSCR\r\n" reply */
/* within that time, and it won't re-open after closing. */
if (p->icom->dctype & icomt_btserial)
delayms = 600;
@@ -321,8 +332,8 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
p->model = 1201;
} 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)) {
+ || (len >= 17 && strncmp(buf, "PECFIRM_JETI_1501", 17) == 0)
+ || (len >= 18 && strncmp(buf, "SPECFIRM_JETI_1501", 18) == 0)) {
p->model = 1501;
} else {
if (len < 11
@@ -342,22 +353,32 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
a1logd(p->log, 2, "specbos_init_coms: init coms has suceeded\n");
- p->gotcoms = 1;
-
/* See if it's a 1501 or 1511 */
if (p->model == 1501) {
+ int i;
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;
+ /* Try a few times because of BT misbehaviour */
+ for (i = 0; i < 3; i++) {
+ if ((ev = specbos_command(p, "*conf:dispen?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if (i < 3)
+ continue;
+ 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) {
+ if (i < 3)
+ continue;
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse display status\n");
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
+ } else {
+ break;
+ }
}
+
a1logd(p->log, 1, " spectraval %s display\n",dispen ? "has" : "doesn't have");
if (dispen) {
p->model = 1511;
@@ -393,6 +414,8 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
#endif
+ p->gotcoms = 1;
+
amutex_unlock(p->lock);
return inst_ok;
}
@@ -559,25 +582,33 @@ specbos_init_inst(inst *pp) {
p->measto = 20.0; /* Set default. Specbos default is 60.0 */
if (p->model == 1211)
- p->measto = 6.0; /* Same overall time as i1d3 ?? */
+ p->measto = 6.0 + 3.6; /* Aprox. Same overall time as i1d3 ?? */
else if (p->model == 1201)
- p->measto = 16.0;
+ p->measto = 16.0 + 3.6;
else if (p->model == 1501 || p->model == 1511)
- p->measto = 6.0;
+ p->measto = 6.0 + 3.6;
/* Implement max auto int. time, to speed up display measurement */
if (p->model == 1501 || p->model == 1511) {
+#ifdef NEVER /* Bound auto by integration time (worse for inttime > 1.0) */
int maxaver = 2; /* Maximum averages for auto int time */
double dmaxtint;
int maxtint;
/* Actual time taken depends on maxtint, autoavc & fudge factor. */
- dmaxtint = p->measto/(maxaver + 3.5);
+ dmaxtint = (p->measto - 3.6)/(2.0 * maxaver);
+
+ //printf("dmaxtint %f\n",dmaxtint);
maxtint = (int)(dmaxtint * 1000.0+0.5);
- if (maxtint < 1000 || maxtint > 64999)
- error("specbos: assert, maxtint %d out of range",maxtint);
+ if (maxtint < 1000 || maxtint > 64999) {
+ warning("specbos: assert, maxtint %d out of range",maxtint);
+ if (maxtint < 1000)
+ maxtint = 1000;
+ else if (maxtint > 64999)
+ maxtint = 64999;
+ }
/* Set maximum integration time */
sprintf(mes, "*para:maxtint %d\r", maxtint);
@@ -592,6 +623,45 @@ specbos_init_inst(inst *pp) {
amutex_unlock(p->lock);
return ev;
}
+#else /* Bound auto by no. averages (better - limit maxint to 1.0) */
+ double dmaxtint = 1.0; /* Recommended maximum */
+ int maxtint;
+ int maxaver; /* Maximum averages for auto int time */
+
+ maxtint = (int)(dmaxtint * 1000.0+0.5);
+
+ if (maxtint < 1000 || maxtint > 64999) {
+ warning("specbos: assert, maxtint %d out of range",maxtint);
+ if (maxtint < 1000)
+ maxtint = 1000;
+ else if (maxtint > 64999)
+ maxtint = 64999;
+ }
+
+ /* 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;
+ }
+
+ /* Total time = overhead + initial sample + 2 * int time per measure */
+ maxaver = (int)ceil((p->measto - 3.6)/(2.0 * dmaxtint));
+
+ //printf("maxaver %d\n",maxaver);
+
+ if (maxaver < 2) {
+ warning("specbos: assert, maxaver %d out of range",maxaver);
+ maxaver = 2;
+ }
+
+ /* 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;
+ }
+#endif
/* spectraval doesn't support *fetch:XYZ command */
p->noXYZ = 1;
@@ -600,38 +670,69 @@ specbos_init_inst(inst *pp) {
double dmaxtin;
int maxtin;
- dmaxtin = p->measto/2.5; /* Fudge factor */
+ /* Total time = overhead + initial sample + 2 * int time per measure */
+ dmaxtin = (p->measto - 3.6)/2.0; /* Fudge factor */
+
maxtin = (int)(dmaxtin * 1000.0+0.5);
- if (maxtin < 1000 || maxtin > 64999)
- error("specbos: assert, maxtin %d out of range",maxtin);
+ if (maxtin < 1000 || maxtin > 64999) {
+ warning("specbos: assert, maxtint %d out of range",maxtin);
+ if (maxtin < 1000)
+ maxtin = 1000;
+ else if (maxtin > 64999)
+ maxtin = 64999;
+ }
/* Set maximum integration time */
- sprintf(mes, "*para:maxtint %d\r", maxtin);
+ /* (1201 *para:maxtint doesn't work !!) */
+ sprintf(mes, "*conf:maxtin %d\r", maxtin);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+#ifdef NEVER /* Use default */
+ /* Set split time to limit dark current error for long integration times */
+ sprintf(mes, "*para:splitt %d\r", 1000);
if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
amutex_unlock(p->lock);
return ev;
}
+#endif
+
}
if (p->model == 1501 || p->model == 1511) {
+ int i;
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;
- }
+ /* Try several times due to BT problems */
+ for (i = 0; i < 3; i++) {
+ /* 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) {
+ if (i < 3)
+ continue;
+ 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;
+ if ((ev = specbos_command(p, "*para:wran?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if (i < 3)
+ continue;
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ if (sscanf(buf, "%d %d %d",&wstart,&wend,&wstep) != 3) {
+ if (i < 3)
+ continue;
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse wavelength range\n");
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
+
+ } else {
+ break;
+ }
}
p->wl_short = (double)wstart;
@@ -679,7 +780,7 @@ specbos_init_inst(inst *pp) {
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;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
a1logd(p->log, 1, " Short wl range %f\n",p->wl_short);
@@ -690,7 +791,7 @@ specbos_init_inst(inst *pp) {
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;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */
p->wl_long = 830.0; /* Limit it to useful visual range */
@@ -807,13 +908,13 @@ specbos_get_target_laser(
}
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;
+ a1logd(p->log, 1, "specbos_get_target_laser: failed to parse laser state\n");
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_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;
+ a1logd(p->log, 1, "specbos_get_target_laser: failed to parse laser state\n");
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
}
*laser = lstate;
@@ -956,9 +1057,18 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
+ /* If we have a requested number of averages */
+ if (p->noaverage != 0) {
+ if ((rv = set_average(p, p->noaverage, 0)) != inst_ok)
+ return rv;
+
/* 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)
+ } else if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if ((rv = set_average(p, DEFAULT_TRANS_NAV, 0)) != inst_ok)
+ return rv;
+ /* Or default 1 otherwise */
+ } else {
+ if ((rv = set_average(p, DEFAULT_NAV, 0)) != inst_ok)
return rv;
}
@@ -1037,7 +1147,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
&val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) != 3) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
- return inst_protocol_error;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
/* Hmm. Some older firmware versions are reported to not support the */
@@ -1048,7 +1158,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
p->noXYZ = 1;
if (p->model == 1501 || p->model == 1511) {
- if ((ec = specbos_fcommand(p, "*calc:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
+ if ((ec = specbos_fcommand(p, "*calc:PHOTOmetric\r", buf, MAX_RD_SIZE, 1.0, 1, tnorm, 0))
!= SPECBOS_OK) {
amutex_unlock(p->lock);
return specbos_interp_code((inst *)p, ec);
@@ -1056,7 +1166,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
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;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
} else {
if ((ec = specbos_fcommand(p, "*fetch:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
@@ -1067,7 +1177,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
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;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
}
@@ -1080,7 +1190,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
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;
+ return specbos_interp_code((inst *)p, SPECBOS_DATA_PARSE_ERROR);
}
} else {
if ((ec = specbos_fcommand(p, "*fetch:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
@@ -1147,10 +1257,10 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
/* Fetch the spectral readings */
if (p->model == 1501 || p->model == 1511)
- ec = specbos_fcommand(p, "*calc:sprad\r", buf, MAX_RD_SIZE, 4.0,
+ ec = specbos_fcommand(p, "*calc:sprad\r", buf, MAX_RD_SIZE, 6.0,
1, tspec, 0);
else
- ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 4.0,
+ ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 6.0,
2+p->nbands+1, tnorm, 0);
if (ec != SPECBOS_OK) {
a1logd(p->log, 1, "specbos_fcommand: failed with 0x%x\n",ec);
@@ -1196,7 +1306,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
try_again:;
}
if (tries >= maxtries) {
- a1logd(p->log, 1, "specbos_fcommand: ran out of retries\n");
+ a1logd(p->log, 1, "specbos_fcommand: ran out of retries - parsing error ?\n");
amutex_unlock(p->lock);
return inst_protocol_error;
}
@@ -1616,7 +1726,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
p->mode = inst_mode_emis_tele | inst_mode_spectral;
p->doing_cal = 1;
- /* Set to average 50 readings */
+ /* Set to average 50 readings for calibration */
if ((ev = set_average(p, 50, 1)) != inst_ok)
return ev;
@@ -1982,9 +2092,9 @@ specbos_del(inst *pp) {
if (p->th != NULL) { /* Terminate diffuser monitor thread */
int i;
p->th_term = 1; /* Tell thread to exit on error */
- for (i = 0; p->th_termed == 0 && i < 5; i++)
+ for (i = 0; p->th_termed == 0 && i < 50; i++)
msec_sleep(100); /* Wait for thread to terminate */
- if (i >= 5) {
+ if (i >= 50) {
a1logd(p->log,3,"specbos diffuser thread termination failed\n");
}
p->th->del(p->th);
@@ -2007,6 +2117,7 @@ inst3_capability *pcap3) {
specbos *p = (specbos *)pp;
inst_mode cap1 = 0;
inst2_capability cap2 = 0;
+ inst3_capability cap3 = 0;
cap1 |= inst_mode_emis_tele
| inst_mode_trans_spot /* Emulated transmission mode diffuse/90 */
@@ -2034,12 +2145,15 @@ inst3_capability *pcap3) {
cap2 |= inst2_get_refresh_rate;
}
+ /* Can average multiple measurements */
+ cap3 |= inst3_average;
+
if (pcap1 != NULL)
*pcap1 = cap1;
if (pcap2 != NULL)
*pcap2 = cap2;
if (pcap3 != NULL)
- *pcap3 = inst3_none;
+ *pcap3 = cap3;
}
/* Return current or given configuration available measurement modes. */
@@ -2368,6 +2482,24 @@ specbos_get_set_opt(inst *pp, inst_opt_type m, ...) {
if (!p->inited)
return inst_no_init;
+ if (m == inst_opt_set_averages) {
+ va_list args;
+ int nav = 1;
+
+ va_start(args, m);
+ nav = va_arg(args, int);
+ va_end(args);
+
+ if (nav < 0)
+ return inst_bad_parameter;
+
+ p->noaverage = nav;
+
+ /* Averages will get set before each measurement */
+
+ return inst_ok;
+ }
+
/* Use default implementation of other inst_opt_type's */
{
inst_code rv;
@@ -2382,7 +2514,7 @@ specbos_get_set_opt(inst *pp, inst_opt_type m, ...) {
}
/* Constructor */
-extern specbos *new_specbos(icoms *icom, instType itype) {
+extern specbos *new_specbos(icoms *icom, instType dtype) {
specbos *p;
if ((p = (specbos *)calloc(sizeof(specbos),1)) == NULL) {
a1loge(icom->log, 1, "new_specbos: malloc failed!\n");
@@ -2410,12 +2542,14 @@ extern specbos *new_specbos(icoms *icom, instType itype) {
p->del = specbos_del;
p->icom = icom;
- p->itype = itype;
- if (p->itype == instSpecbos1201)
+ p->dtype = dtype;
+ if (p->dtype == instSpecbos1201)
p->model = 1201;
amutex_init(p->lock);
+ p->noaverage = 1;
+
return p;
}