summaryrefslogtreecommitdiff
path: root/spectro
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2016-10-02 19:25:17 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2016-10-02 19:25:17 +0200
commitc2ca7be5a751879159f3cb591a64bb9568b79762 (patch)
tree04e38d4f4a2aad4d789bda0a65b7abb80a3439a2 /spectro
parent45c152c326d87478fbf41714b4b8e2f7b57a282b (diff)
parent3db384424bd7398ffbb7a355cab8f15f3add009f (diff)
Updated version 1.9.1+repack from 'upstream/1.9.1+repack'
with Debian dir 98a996367aa69ae41accf9c6d369f600bc94de80
Diffstat (limited to 'spectro')
-rw-r--r--spectro/IntsLib_Readme.txt11
-rw-r--r--spectro/Jamfile2
-rw-r--r--spectro/Makefile.SA21
-rw-r--r--spectro/afiles5
-rw-r--r--spectro/average.c438
-rw-r--r--spectro/base64.c3
-rw-r--r--spectro/base64.h14
-rw-r--r--spectro/ccwin.c15
-rw-r--r--spectro/ccxxmake.c7
-rw-r--r--spectro/chartread.c326
-rw-r--r--spectro/colorhug.c15
-rw-r--r--spectro/colorhug.h8
-rw-r--r--spectro/conv.c659
-rw-r--r--spectro/conv.h76
-rw-r--r--spectro/cubecal.h1
-rw-r--r--spectro/dev.h41
-rw-r--r--spectro/dispcal.c86
-rw-r--r--spectro/dispread.c9
-rw-r--r--spectro/dispsup.c39
-rw-r--r--spectro/dispsup.h3
-rw-r--r--spectro/disptechs.c3
-rw-r--r--spectro/dispwin.c795
-rw-r--r--spectro/dispwin.h46
-rw-r--r--spectro/dtp20.c43
-rw-r--r--spectro/dtp20.h11
-rw-r--r--spectro/dtp22.c131
-rw-r--r--spectro/dtp22.h10
-rw-r--r--spectro/dtp41.c128
-rw-r--r--spectro/dtp41.h11
-rw-r--r--spectro/dtp51.c84
-rw-r--r--spectro/dtp51.h12
-rw-r--r--spectro/dtp92.c93
-rw-r--r--spectro/dtp92.h7
-rw-r--r--spectro/ex1.c20
-rw-r--r--spectro/ex1.h7
-rw-r--r--spectro/hcfr.c14
-rw-r--r--spectro/hcfr.h8
-rw-r--r--spectro/hidio.c40
-rw-r--r--spectro/hidio.h9
-rw-r--r--spectro/huey.c23
-rw-r--r--spectro/huey.h7
-rw-r--r--spectro/i1d3.c24
-rw-r--r--spectro/i1d3.h9
-rw-r--r--spectro/i1disp.c128
-rw-r--r--spectro/i1disp.h30
-rw-r--r--spectro/i1pro.c122
-rw-r--r--spectro/i1pro.h12
-rw-r--r--spectro/i1pro_imp.c332
-rw-r--r--spectro/i1pro_imp.h32
-rw-r--r--spectro/icoms.c481
-rw-r--r--spectro/icoms.h277
-rw-r--r--spectro/icoms_nt.c341
-rw-r--r--spectro/icoms_ux.c350
-rw-r--r--spectro/illumread.c68
-rw-r--r--spectro/inst.c384
-rw-r--r--spectro/inst.h150
-rw-r--r--spectro/instappsup.c20
-rw-r--r--spectro/instlib.ksh22
-rw-r--r--spectro/insttypeinst.h4
-rw-r--r--spectro/insttypes.c71
-rw-r--r--spectro/insttypes.h34
-rw-r--r--spectro/iusb.h8
-rw-r--r--spectro/kleink10.c44
-rw-r--r--spectro/kleink10.h7
-rw-r--r--spectro/linear.cal272
-rw-r--r--spectro/madvrwin.c20
-rw-r--r--spectro/munki.c80
-rw-r--r--spectro/munki_imp.c55
-rw-r--r--spectro/munki_imp.h4
-rw-r--r--spectro/oemarch.c78
-rw-r--r--spectro/oeminst.c4
-rw-r--r--spectro/pollem.c2
-rw-r--r--spectro/pollem.h2
-rw-r--r--spectro/rspec.c22
-rw-r--r--spectro/sa_conv.c865
-rw-r--r--spectro/sa_conv.h233
-rw-r--r--spectro/smcube.c49
-rw-r--r--spectro/smcube.h9
-rw-r--r--spectro/spec2cie.c220
-rw-r--r--spectro/specbos.c1000
-rw-r--r--spectro/specbos.h17
-rw-r--r--spectro/spotread.c374
-rw-r--r--spectro/spyd2.c27
-rw-r--r--spectro/spyd2.h8
-rw-r--r--spectro/ss.c163
-rw-r--r--spectro/ss.h13
-rw-r--r--spectro/ss_imp.c19
-rw-r--r--spectro/ss_imp.h10
-rw-r--r--spectro/strange.cal272
-rw-r--r--spectro/synthcal.c15
-rw-r--r--spectro/usbio.c9
-rw-r--r--spectro/usbio.h4
-rw-r--r--spectro/usbio_bsd.c8
-rw-r--r--spectro/usbio_lx.c15
-rw-r--r--spectro/usbio_nt.c4
-rw-r--r--spectro/usbio_ox.c22
-rw-r--r--spectro/webwin.c33
-rw-r--r--spectro/xdg_bds.c30
-rw-r--r--spectro/xdg_bds.h2
-rw-r--r--spectro/xrga.c224
-rw-r--r--spectro/xrga.h86
101 files changed, 7929 insertions, 2572 deletions
diff --git a/spectro/IntsLib_Readme.txt b/spectro/IntsLib_Readme.txt
index 7d9fb0c..c8df3d3 100644
--- a/spectro/IntsLib_Readme.txt
+++ b/spectro/IntsLib_Readme.txt
@@ -3,17 +3,6 @@ create the instlib.zip archive.
To build it:
-If you are on Linux or OS X, you first need to
-build libusb 1.0A, ie::
-
- cd libusb1
- sh autogen.sh
- make
- cp libusb/libusb-1.0A.a .
- cd ..
-
-(The libraries are pre-built for MSWin)
-
To build the standalone instrument lib, you
need to edit the Makefile to #include the appropriate
Makefile.XXX for your operating system, and then
diff --git a/spectro/Jamfile b/spectro/Jamfile
index 9eb292f..94a2f70 100644
--- a/spectro/Jamfile
+++ b/spectro/Jamfile
@@ -127,7 +127,7 @@ if $(USE_DEMOINST) = true && [ GLOB [ NormPaths . ] : demoinst.c ] {
INST_SRCS += demoinst.c ;
}
-Library libinst : inst.c insttypes.c icoms.c disptechs.c rspec.c $(INST_SRCS) ;
+Library libinst : inst.c insttypes.c icoms.c disptechs.c rspec.c xrga.c $(INST_SRCS) ;
# Display access library
ObjectKeep mongoose.c ;
diff --git a/spectro/Makefile.SA b/spectro/Makefile.SA
index 2d57742..5913126 100644
--- a/spectro/Makefile.SA
+++ b/spectro/Makefile.SA
@@ -39,12 +39,12 @@ WIN_STDHDRS = $(INCFLAG)usb$(SLASH)driver
all:: libinst$(SUFLIB) libinstappsup$(SUFLIB) spotread$(SUFEXE) oeminst$(SUFEXE)
INSTHEADERS = dtp20.h dtp22.h dtp41.h dtp51.h dtp92.h ss.h ss_imp.h i1disp.h i1d3.h i1pro.h i1pro_imp.h munki.h munki_imp.h hcfr.h huey.h colorhug.h spyd2.h specbos.h kleink10.h
-INSOBJS = dtp20$(SUFOBJ) dtp22$(SUFOBJ) dtp41$(SUFOBJ) dtp51$(SUFOBJ) dtp92$(SUFOBJ) ss$(SUFOBJ) ss_imp$(SUFOBJ) i1disp$(SUFOBJ) i1d3$(SUFOBJ) i1pro$(SUFOBJ) i1pro_imp$(SUFOBJ) munki$(SUFOBJ) munki_imp$(SUFOBJ) hcfr$(SUFOBJ) huey$(SUFOBJ) colorhug$(SUFOBJ) spyd2$(SUFOBJ) specbos$(SUFOBJ) kleink10$(SUFOBJ)
+INSOBJS = dtp20$(SUFOBJ) dtp22$(SUFOBJ) dtp41$(SUFOBJ) dtp51$(SUFOBJ) dtp92$(SUFOBJ) ss$(SUFOBJ) ss_imp$(SUFOBJ) i1disp$(SUFOBJ) i1d3$(SUFOBJ) i1pro$(SUFOBJ) i1pro_imp$(SUFOBJ) munki$(SUFOBJ) munki_imp$(SUFOBJ) hcfr$(SUFOBJ) huey$(SUFOBJ) colorhug$(SUFOBJ) spyd2$(SUFOBJ) specbos$(SUFOBJ) kleink10$(SUFOBJ) ex1$(SUFOBJ) smcube$(SUFOBJ)
-HEADERS = pollem.h conv.h aglob.h hidio.h icoms.h inst.c inst.h insttypeinst.h insttypes.h disptechs.h $(INSTHEADERS) usbio.h xspect.h rspl1.h sort.h xdg_bds.h ccss.h ccmx.h pars.h cgats.h instappsup.h usb$(SLASH)driver$(SLASH)driver_api.h
+HEADERS = pollem.h conv.h sa_conv.h aglob.h hidio.h icoms.h inst.c inst.h insttypeinst.h insttypes.h disptechs.h rspec.h xrga.h $(INSTHEADERS) usbio.h xspect.h rspl1.h sort.h xdg_bds.h ccss.h ccmx.h pars.h cgats.h instappsup.h usb$(SLASH)driver$(SLASH)driver_api.h
# libinst objects
-OBJS = conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ) icoms$(SUFOBJ) usbio$(SUFOBJ) hidio$(SUFOBJ) insttypes$(SUFOBJ) disptechs$(SUFOBJ) pollem$(SUFOBJ) xspect$(SUFOBJ) xdg_bds$(SUFOBJ) ccss$(SUFOBJ) ccmx$(SUFOBJ) pars$(SUFOBJ) cgats$(SUFOBJ) $(INSOBJS)
+OBJS = conv$(SUFOBJ) sa_conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ) icoms$(SUFOBJ) usbio$(SUFOBJ) hidio$(SUFOBJ) insttypes$(SUFOBJ) disptechs$(SUFOBJ) rspec$(SUFOBJ) xrga$(SUFOBJ) pollem$(SUFOBJ) xspect$(SUFOBJ) xdg_bds$(SUFOBJ) ccss$(SUFOBJ) ccmx$(SUFOBJ) pars$(SUFOBJ) cgats$(SUFOBJ) $(INSOBJS)
# instrument library
@@ -52,6 +52,9 @@ OBJS = conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ)
conv$(SUFOBJ): conv.c $(HEADERS)
$(CC) conv.c
+sa_conv$(SUFOBJ): sa_conv.c $(HEADERS)
+ $(CC) sa_conv.c
+
aglob$(SUFOBJ): aglob.c $(HEADERS)
$(CC) aglob.c
@@ -76,6 +79,12 @@ hidio$(SUFOBJ): hidio.c $(HEADERS)
insttypes$(SUFOBJ): insttypes.c $(HEADERS)
$(CC) insttypes.c
+rspec$(SUFOBJ): rspec.c $(HEADERS)
+ $(CC) rspec.c
+
+xrga$(SUFOBJ): xrga.c $(HEADERS)
+ $(CC) xrga.c
+
disptechs$(SUFOBJ): disptechs.c $(HEADERS)
$(CC) disptechs.c
@@ -148,6 +157,12 @@ specbos$(SUFOBJ): specbos.c $(HEADERS)
kleink10$(SUFOBJ): kleink10.c $(HEADERS)
$(CC) kleink10.c
+ex1$(SUFOBJ): ex1.c $(HEADERS)
+ $(CC) ex1.c
+
+smcube$(SUFOBJ): smcube.c $(HEADERS)
+ $(CC) smcube.c
+
oemarch$(SUFOBJ): oemarch.c $(HEADERS)
$(CC) oemarch.c
diff --git a/spectro/afiles b/spectro/afiles
index 984bac5..8891ce7 100644
--- a/spectro/afiles
+++ b/spectro/afiles
@@ -26,6 +26,7 @@ mongoose.c
insttypes.h
insttypes.c
insttypeinst.h
+dev.h
inst.c
inst.h
disptechs.h
@@ -87,8 +88,12 @@ spec2cie.c
average.c
rspec.h
rspec.c
+xrga.h
+xrga.c
conv.h
conv.c
+sa_conv.h
+sa_conv.c
aglob.h
aglob.c
xdg_bds.h
diff --git a/spectro/average.c b/spectro/average.c
index 5a8fb3f..e961262 100644
--- a/spectro/average.c
+++ b/spectro/average.c
@@ -23,6 +23,7 @@
*/
+
#undef DEBUG
#define verbo stdout
@@ -34,10 +35,15 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
+#include "sort.h"
#include "cgats.h"
#include "xicc.h"
#include "insttypes.h"
+static double average(double *vals, int nvals);
+static double median(double *vals, int nvals);
+static void geommed(double res[3], double vals[][3], int nvals);
+
void usage(char *diag, ...) {
int i;
fprintf(stderr,"Average or merge values in .ti3 like files, Version %s\n",ARGYLL_VERSION_STR);
@@ -52,6 +58,10 @@ void usage(char *diag, ...) {
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: average [-options] input1.ti3 input2.ti3 ... output.ti3\n");
fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -e Median rather than average\n");
+ fprintf(stderr," -g Geometric Median of PCS in encoded space\n");
+ fprintf(stderr," -L Geometric Median of PCS in L*a*b* space\n");
+ fprintf(stderr," -X Geometric Median of PCS in XYZ space\n");
fprintf(stderr," -m Merge rather than average\n");
fprintf(stderr," input1.ti3 First input file\n");
fprintf(stderr," input2.ti3 Second input file\n");
@@ -69,6 +79,8 @@ struct _inpinfo {
int main(int argc, char *argv[]) {
int fa,nfa; /* current argument we're looking at */
int verb = 0;
+ int domedian = 0; /* Median rather than average */
+ int dogeom = 0; /* Do geometric median of PCS, 2 = Lab, 3 = PCS */
int domerge = 0; /* Merge rather than average */
int ninps = 0; /* Number of input files */
@@ -78,10 +90,12 @@ int main(int argc, char *argv[]) {
cgats_set_elem *setel; /* Array of set value elements */
int *flags; /* Point to destination of set */
- int nchan; /* Number of device channels */
+ int nchan = 0; /* Number of device channels */
int chix[ICX_MXINKS]; /* Device chanel indexes */
- int pcsix[3]; /* PCS chanel indexes */
- int isLab = 0;
+ int npcs = 0;
+
+ int haspcs[2] = { 0 }; /* Has Lab, XYZ */
+ int pcsix[3][3]; /* Lab, XYZ chanel indexes */
int i, j, n;
@@ -110,13 +124,33 @@ int main(int argc, char *argv[]) {
if (argv[fa][1] == '?')
usage("Usage requested");
+ /* Median */
+ else if (argv[fa][1] == 'e') {
+ domedian = 1;
+ }
+
+ /* Geometric Median of PCS */
+ else if (argv[fa][1] == 'g') {
+ dogeom = 1;
+ }
+
+ /* Geometric Median of PCS in L*a*b* */
+ else if (argv[fa][1] == 'L') {
+ dogeom = 2;
+ }
+
+ /* Geometric Median of PCS in XYZ */
+ else if (argv[fa][1] == 'X') {
+ dogeom = 3;
+ }
+
/* Merge */
- else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
+ else if (argv[fa][1] == 'm') {
domerge = 1;
}
/* Verbosity */
- else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ else if (argv[fa][1] == 'v') {
verb = 1;
}
@@ -192,8 +226,9 @@ int main(int argc, char *argv[]) {
ocg->add_field(ocg, n, inps[0].c->t[n].fsym[i], inps[0].c->t[n].ftype[i]);
}
+ /* If more than one file, must be merging or averaging between files */
if (ninps > 1) {
- /* Duplicate all of the data */
+ /* Duplicate all of the data or first file to output file */
if ((setel = (cgats_set_elem *)malloc(
sizeof(cgats_set_elem) * inps[0].c->t[n].nfields)) == NULL)
error("Malloc failed!");
@@ -207,11 +242,11 @@ int main(int argc, char *argv[]) {
}
/* Figure out the indexes of the device channels */
- {
+ if (inps[0].c->find_kword(inps[0].c, 0, "COLOR_REP") < 0) {
+ warning("Input file '%s' doesn't contain keyword COLOR_REP", inps[0].name);
+ } else {
int ti;
char *buf;
- char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
- char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
char *outc;
int nmask;
char *bident;
@@ -227,13 +262,6 @@ int main(int argc, char *argv[]) {
error("COLOR_REP '%s' invalid", inps[0].c->t[0].kdata[ti]);
*outc++ = '\000';
- if (strcmp(outc, "XYZ") == 0) {
- isLab = 0;
- } else if (strcmp(outc, "LAB") == 0) {
- isLab = 1;
- } else
- error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", inps[0].c->t[0].kdata[ti]);
-
if ((nmask = icx_char2inkmask(buf)) == 0) {
error ("File '%s' keyword COLOR_REP has unknown device value '%s'",inps[0].name,buf);
}
@@ -256,19 +284,32 @@ int main(int argc, char *argv[]) {
error ("Field %s is wrong type",fname);
chix[j] = ii;
}
-
- /* Find PCS fields */
- for (j = 0; j < 3; j++) {
- int ii;
-
- if ((ii = inps[0].c->find_field(inps[0].c, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
- error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
- if (inps[0].c->t[0].ftype[ii] != r_t)
- error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
- pcsix[j] = ii;
+ }
+
+ /* Figure out the indexes of the PCS channels, if any */
+ {
+ int npcs;
+ char *fname[2][3] = { { "LAB_L", "LAB_A", "LAB_B" },
+ { "XYZ_X", "XYZ_Y", "XYZ_Z" } };
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+ for (npcs = 0; npcs < 3; npcs++) {
+ int ii;
+
+ if ((ii = inps[0].c->find_field(inps[0].c, 0, fname[j][npcs])) < 0)
+ break; /* Try next or give up */
+
+ if (inps[0].c->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname[j][npcs]);
+ pcsix[j][npcs] = ii;
+ }
+ if (npcs == 3)
+ haspcs[j] = 1;
}
- free(bident);
}
+ if (!haspcs[0] && !haspcs[1])
+ warning("No PCS fields found - hope that's OK!");
if (!domerge && verb) {
printf("Averaging the following fields:");
@@ -294,7 +335,8 @@ int main(int argc, char *argv[]) {
printf("\n");
}
- /* Get ready to add more values to output */
+ /* Get ready to add more values to output, */
+ /* for merging or averaging within one file. */
if ((setel = (cgats_set_elem *)malloc(
sizeof(cgats_set_elem) * inps[0].c->t[0].nfields)) == NULL)
error("Malloc failed!");
@@ -302,13 +344,24 @@ int main(int argc, char *argv[]) {
/* If averaging values within the one file */
if (ninps == 1) {
int *valdone;
- double npatches;
- int k;
+ int npat;
+ double *vlist;
+ double (*v3list)[3] = NULL;
+ int k, e;
n = 0; /* Output set index */
if ((valdone = (int *)calloc(inps[0].c->t[0].nsets, sizeof(int))) == NULL)
error("Malloc failed!");
+ if ((vlist = (double *)calloc(inps[0].c->t[0].nsets, sizeof(double))) == NULL)
+ error("Malloc failed!");
+
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ if ((v3list = (double (*)[3])calloc(inps[0].c->t[0].nsets, 3 * sizeof(double))) == NULL)
+ error("Malloc failed!");
+ }
+
+ /* For each patch */
for (i = 0; i < inps[0].c->t[0].nsets; i++) {
if (valdone[i])
@@ -316,49 +369,8 @@ int main(int argc, char *argv[]) {
inps[0].c->get_setarr(inps[0].c, 0, i, setel);
ocg->add_setarr(ocg, 0, setel);
- npatches = 1.0;
-
- /* Locate and patches with matching device values */
- for (k = i+1; k < inps[0].c->t[0].nsets; k++) {
-
- /* Check if the device values match */
- for (j = 0; j < nchan; j++) {
- double diff;
-
- diff = *((double *)inps[0].c->t[0].fdata[i][chix[j]])
- - *((double *)inps[0].c->t[0].fdata[k][chix[j]]);
-
- if (fabs(diff) > 0.001) {
- break;
- }
- }
- if (j < nchan) {
- continue;
- }
- /* Add all the non-device real field values */
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
- }
- if (jj < nchan)
- continue;
-
- *((double *)ocg->t[0].fdata[n][j])
- += *((double *)inps[0].c->t[0].fdata[k][j]);
- }
- npatches++;
- valdone[k] = 1;
- }
- /* Average them out */
+ /* For each non-device real field values */
for (j = 0; j < inps[0].c->t[0].nfields; j++) {
int jj;
@@ -374,20 +386,102 @@ int main(int argc, char *argv[]) {
if (jj < nchan)
continue;
- *((double *)ocg->t[0].fdata[n][j]) /= npatches;
+ /* Locate any patches (including starting patch) with matching device values */
+ npat = 0;
+ for (k = i; k < inps[0].c->t[0].nsets; k++) {
+
+ /* Check if the device values match */
+ for (e = 0; e < nchan; e++) {
+ double diff;
+
+ diff = *((double *)inps[0].c->t[0].fdata[i][chix[e]])
+ - *((double *)inps[0].c->t[0].fdata[k][chix[e]]);
+
+ if (fabs(diff) > 0.001) {
+ break;
+ }
+ }
+ if (e < nchan) {
+ continue;
+ }
+
+ vlist[npat++] = *((double *)inps[0].c->t[0].fdata[k][j]);
+ valdone[k] = 1;
+ }
+ if (domedian)
+ *((double *)ocg->t[0].fdata[n][j]) = median(vlist, npat);
+ else
+ *((double *)ocg->t[0].fdata[n][j]) = average(vlist, npat);
+ }
+
+ /* Override per-component average/median if PCS Geometric Median */
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ double res[3];
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+
+ if (haspcs[j] == 0)
+ continue;
+
+ /* Locate any patches (including starting patch) with matching device values */
+ npat = 0;
+ for (k = i; k < inps[0].c->t[0].nsets; k++) {
+
+ /* Check if the device values match */
+ for (e = 0; e < nchan; e++) {
+ double diff;
+
+ diff = *((double *)inps[0].c->t[0].fdata[i][chix[e]])
+ - *((double *)inps[0].c->t[0].fdata[k][chix[e]]);
+
+ if (fabs(diff) > 0.001) {
+ break;
+ }
+ }
+ if (e < nchan) {
+ continue;
+ }
+
+ v3list[npat][0] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][0]]);
+ v3list[npat][1] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][1]]);
+ v3list[npat][2] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][2]]);
+
+ if (j == 0 && dogeom == 3) /* Lab and want XYZ */
+ icmLab2XYZ(&icmD50_100, v3list[npat], v3list[npat]);
+ else if (j == 1 && dogeom == 2) /* XYZ and want Lab */
+ icmXYZ2Lab(&icmD50_100, v3list[npat], v3list[npat]);
+
+ npat++;
+ }
+ geommed(res, v3list, npat);
+
+ if (j == 0 && dogeom == 3)
+ icmXYZ2Lab(&icmD50_100, res, res);
+ else if (j == 1 && dogeom == 2)
+ icmLab2XYZ(&icmD50_100, res, res);
+
+ *((double *)ocg->t[0].fdata[n][pcsix[j][0]]) = res[0];
+ *((double *)ocg->t[0].fdata[n][pcsix[j][1]]) = res[1];
+ *((double *)ocg->t[0].fdata[n][pcsix[j][2]]) = res[2];
+ }
}
n++; /* One more output set */
}
+ if (v3list != NULL)
+ free(v3list);
+ free(vlist);
free(valdone);
/* Averaging patches between identical files, */
/* or concatenating (merging) several files */
} else {
- /* Process all the other input files */
+
+ /* Check/process all the other input files */
for (n = 1; n < ninps; n++) {
- /* Check all the fields match */
+ /* Check all the fields match the first file */
if (inps[0].c->t[0].nfields != inps[n].c->t[0].nfields)
error ("File '%s' has %d fields, file '%s has %d",
inps[n].name, inps[n].c->t[0].nfields, inps[0].name, inps[0].c->t[0].nfields);
@@ -405,15 +499,15 @@ int main(int argc, char *argv[]) {
}
} else { /* Averaging */
- /* Check the number of values matches */
+
+ /* Check the number of patches matches the first file */
if (inps[0].c->t[0].nsets != inps[n].c->t[0].nsets)
error ("File '%s' has %d sets, file '%s has %d",
inps[n].name, inps[n].c->t[0].nsets, inps[0].name, inps[0].c->t[0].nsets);
-
- /* Add the numeric field values to corresponding output */
+ /* For all the patches: */
for (i = 0; i < inps[n].c->t[0].nsets; i++) {
- /* Check that the device values match */
+ /* Check that the device values match the first file */
for (j = 0; j < nchan; j++) {
double diff;
diff = *((double *)inps[0].c->t[0].fdata[i][chix[j]])
@@ -423,53 +517,100 @@ int main(int argc, char *argv[]) {
error ("File '%s' set %d has field '%s' value that differs from '%s'",
inps[n].name, i+1, inps[n].c->t[0].fsym[j], inps[0].name);
}
-
- /* Add all the non-device real field values */
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
- }
- if (jj < nchan)
- continue;
-
- *((double *)ocg->t[0].fdata[i][j])
- += *((double *)inps[n].c->t[0].fdata[i][j]);
- }
}
}
}
-
- /* If averaging, divide out the number of files */
+
+ /* If averaging */
if (!domerge) {
+ int npat;
+ double *vlist;
+ double (*v3list)[3] = NULL;
+
+ if ((vlist = (double *)calloc(ninps, sizeof(double))) == NULL)
+ error("Malloc failed!");
+
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ if ((v3list = (double (*)[3])calloc(inps[0].c->t[0].nsets, 3 * sizeof(double))) == NULL)
+ error("Malloc failed!");
+ }
+
+ /* For all the non-device real field values */
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ int jj;
+
+ /* Only real types */
+ if (inps[0].c->t[0].ftype[j] != r_t)
+ continue;
+
+ /* Not device channels */
+ for (jj = 0; jj < nchan; jj++) {
+ if (chix[jj] == j)
+ break;
+ }
+ if (jj < nchan)
+ continue;
- for (i = 0; i < inps[n].c->t[0].nsets; i++) {
-
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
+ /* For each patch */
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ /* For all input files */
+ npat = 0;
+ for (n = 0; n < ninps; n++) {
+ vlist[npat++] = *((double *)inps[n].c->t[0].fdata[i][j]);
}
- if (jj < nchan)
- continue;
+
+ if (domedian)
+ *((double *)ocg->t[0].fdata[i][j]) = median(vlist, npat);
+ else
+ *((double *)ocg->t[0].fdata[i][j]) = average(vlist, npat);
+ }
+ }
+
+ /* Override per-component average/median if PCS Geometric Median */
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ double res[3];
+
+ /* For each patch */
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+
+ if (haspcs[j] == 0)
+ continue;
- *((double *)ocg->t[0].fdata[i][j]) /= (double)ninps;
+ /* For all input files */
+ npat = 0;
+ for (n = 0; n < ninps; n++) {
+ v3list[npat][0] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][0]]);
+ v3list[npat][1] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][1]]);
+ v3list[npat][2] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][2]]);
+
+ if (j == 0 && dogeom == 3) /* Lab and want XYZ */
+ icmLab2XYZ(&icmD50_100, v3list[npat], v3list[npat]);
+ else if (j == 1 && dogeom == 2) /* XYZ and want Lab */
+ icmXYZ2Lab(&icmD50_100, v3list[npat], v3list[npat]);
+
+ npat++;
+ }
+ geommed(res, v3list, npat);
+
+ if (j == 0 && dogeom == 3)
+ icmXYZ2Lab(&icmD50_100, res, res);
+ else if (j == 1 && dogeom == 2)
+ icmLab2XYZ(&icmD50_100, res, res);
+
+ *((double *)ocg->t[0].fdata[i][pcsix[j][0]]) = res[0];
+ *((double *)ocg->t[0].fdata[i][pcsix[j][1]]) = res[1];
+ *((double *)ocg->t[0].fdata[i][pcsix[j][2]]) = res[2];
+ }
}
}
+
+ if (v3list != NULL)
+ free(v3list);
+ free(vlist);
}
}
@@ -490,6 +631,69 @@ int main(int argc, char *argv[]) {
}
+static double average(double *vals, int nvals) {
+ double rv;
+ int i;
+
+ for (rv = 0.0, i = 0; i < nvals; i++)
+ rv += vals[i];
+
+ if (nvals > 0)
+ rv /= (double)nvals;
+
+ return rv;
+}
+
+static double median(double *vals, int nvals) {
+ if (nvals < 3)
+ return average(vals, nvals);
+
+#define HEAP_COMPARE(A,B) (A < B)
+ HEAPSORT(double,vals,nvals);
+
+ if ((nvals & 1) != 0)
+ return vals[nvals/2];
+ else
+ return 0.5 * (vals[nvals/2] + vals[nvals/2-1]);
+}
+/* Compute Geometric Median of PCS values */
+/* using Weiszfeld's algorithm. */
+static void geommed(double res[3], double vals[][3], int nvals) {
+ int i, j;
+
+ /* Start with mean value */
+ icmSet3(res, 0.0);
+ for (i = 0; i < nvals; i++)
+ icmAdd3(res, res, vals[i]);
+ icmScale3(res, res, 1.0/(double)nvals);
+
+//printf("\n~1 average = %f %f %f\n", res[0], res[1], res[2]);
+
+ /* Itterate to approach Geometric Mean */
+ for (j = 0; j < 20; j++) {
+ double tv[3], tt;
+ int k;
+
+ icmSet3(tv, 0.0);
+ tt = 0.0;
+ for (k = i = 0; i < nvals; i++) {
+ double norm = icmNorm33(vals[i], res);
+ if (norm < 1e-6)
+ continue;
+ tv[0] += vals[i][0]/norm;
+ tv[1] += vals[i][1]/norm;
+ tv[2] += vals[i][2]/norm;
+ tt += 1.0/norm;
+ k++;
+//printf("Norm = %f, tv = %f %f %f, tt = %f\n",norm, tv[0], tv[1], tv[2], tt);
+ }
+ if (k > 0)
+ icmScale3(res, tv, 1.0/tt);
+//printf("~1 res = %f %f %f\n", res[0], res[1], res[2]);
+ }
+
+//printf("~1 geomm = %f %f %f\n", res[0], res[1], res[2]);
+}
diff --git a/spectro/base64.c b/spectro/base64.c
index 388d121..8e07967 100644
--- a/spectro/base64.c
+++ b/spectro/base64.c
@@ -4,6 +4,9 @@
*
* Very simple & concise base64 encoder/decoder
*
+ */
+
+/*
* Author: Graeme W. Gill
*
* Copyright 2014, Graeme W. Gill
diff --git a/spectro/base64.h b/spectro/base64.h
index 726f20a..29ca140 100644
--- a/spectro/base64.h
+++ b/spectro/base64.h
@@ -1,9 +1,13 @@
+#ifndef BASE64_H
+
/*
* Argyll Color Correction System
*
* Very simple & concise base64 encoder/decoder
- *
+ */
+
+/*
* Author: Graeme W. Gill
*
* Copyright 2014, Graeme W. Gill
@@ -13,6 +17,9 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
/* The maximum encoded length given decoded length */
#define EBASE64LEN(len) (((len) * 4 + 2)/3)
@@ -30,4 +37,9 @@ void ebase64(int *dlen, char *dst, unsigned char *src, int slen);
/* We assume that the destination buffer is long enough at DBASE64LEN */
void dbase64(int *dlen, unsigned char *dst, char *src);
+#ifdef __cplusplus
+ }
+#endif
+#define BASE64_H
+#endif /* BASE64_H */
diff --git a/spectro/ccwin.c b/spectro/ccwin.c
index 1e9a18d..a89bc65 100644
--- a/spectro/ccwin.c
+++ b/spectro/ccwin.c
@@ -454,7 +454,7 @@ icmFile *ccwin_get_profile(dispwin *p, char *name, int mxlen) {
/* Change the window color. */
/* Return 1 on error, 2 on window being closed */
-/* inst_license, inst_licensenc or inst_tamper on licening problem */
+/* inst_license, inst_licensenc, inst_tamper or inst_syscompat on licening problem */
static int ccwin_set_color(
dispwin *p,
double r, double g, double b /* Color values 0.0 - 1.0 */
@@ -487,9 +487,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
@@ -798,8 +798,11 @@ int ddebug /* >0 to print debug statements to stderr */
p->ncix = 1;
- p->pdepth = 8; /* Assume this by API */
- p->edepth = 8;
+ p->fdepth = 8; /* Assume this by API */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+ p->nent = 0; /* No ramdac */
+ p->edepth = 8; /* Assumed */
/* Basic object is initialised, so create connection to ChromeCast */
if ((ws = new_chws(cc_id, width, height, hoff, voff, verb, ddebug)) == NULL) {
diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c
index 418affc..740eb0a 100644
--- a/spectro/ccxxmake.c
+++ b/spectro/ccxxmake.c
@@ -500,7 +500,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Paramater expected following -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -1441,11 +1441,12 @@ int main(int argc, char *argv[]) {
strcat(colname, ")");
}
if (description == NULL) {
- if ((description = malloc(strlen(colname) + strlen(displayname) + 4)) == NULL)
+ char *disp = displayname != NULL ? displayname : dtinfo->desc;
+ if ((description = malloc(strlen(colname) + strlen(disp) + 4)) == NULL)
error("Malloc failed");
strcpy(description, colname);
strcat(description, " & ");
- strcat(description, displayname);
+ strcat(description, disp);
}
if (refrmode < 0)
diff --git a/spectro/chartread.c b/spectro/chartread.c
index 9cf6c22..e1624e1 100644
--- a/spectro/chartread.c
+++ b/spectro/chartread.c
@@ -1,7 +1,8 @@
+/* Spectrometer/Colorimeter target test chart reader */
+
/*
* Argyll Color Correction System
- * Spectrometer/Colorimeter target test chart reader
*
* Author: Graeme W. Gill
* Date: 4/10/96
@@ -58,6 +59,11 @@
#define COMPORT 1 /* Default com port 1..4 */
+#undef TEST_EVENT_CALLBACK /* Report async event callbacks, and implement beep prompt there. */
+
+#undef USESTRDELTA /* [Und] Use patch delat's for correlation rather than match DE */
+ /* Doesn't seem to work as well. Why ? */
+
#ifdef __MINGW32__
# define WINVER 0x0500
#endif
@@ -69,22 +75,36 @@
#include <time.h>
#include <ctype.h>
#include <string.h>
+#ifndef SALONEINSTLIB
#include "copyright.h"
#include "aconfig.h"
-#include "cgats.h"
#include "numlib.h"
-#include "icc.h"
#include "xicc.h"
-#include "insttypes.h"
#include "conv.h"
+#include "ui.h"
+#include "icc.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#include "cgats.h"
+#include "rspl1.h"
+#include "xspect.h"
+#include "xcolorants.h"
+#include "xcal.h"
+#include "conv.h"
+#include "sa_conv.h"
+#endif /* SALONEINSTLIB */
+#include "cgats.h"
+#include "insttypes.h"
#include "icoms.h"
#include "inst.h"
#include "ccmx.h"
#include "ccss.h"
+#ifndef SALONEINSTLIB
#include "dispwin.h"
-#include "ui.h"
#include "ccast.h"
#include "dispsup.h"
+#endif /* !SALONEINSTLIB */
#include "alphix.h"
#include "sort.h"
#include "instappsup.h"
@@ -132,6 +152,24 @@ static double xyzLabDE(double ynorm, double *pat, double *ref) {
return icmLabDE(Lab1, Lab2);
}
+#ifdef USESTRDELTA
+/* Return the -ve correlation of the delta E's between steps */
+static double xyzLabcorr(double *pat0, double *ref0,
+ double *pat1, double *ref1) {
+ double p0[3], p1[3], pd[3];
+ double r0[3], r1[3], rd[3];
+
+ icmXYZ2Lab(&icmD50, p0, pat0);
+ icmXYZ2Lab(&icmD50, p1, pat1);
+ ICMSUB3(pd, p0, p1);
+ icmXYZ2Lab(&icmD50, r0, ref0);
+ icmXYZ2Lab(&icmD50, r1, ref1);
+ ICMSUB3(rd, r0, r1);
+
+ return -icmDot3(rd, pd);
+}
+#endif
+
/* A chart read color structure */
/* This can hold all representations simultaniously */
typedef struct {
@@ -169,6 +207,15 @@ static int b62_int(char *p) {
return rv;
}
+#ifdef TEST_EVENT_CALLBACK
+void test_event_callback(void *cntx, inst_event_type event) {
+ a1logd(g_log,0,"Got event_callback with 0x%x\n",event);
+
+ if (event == inst_event_scan_ready)
+ normal_beep();
+}
+#endif
+
/* Deal with an instrument error. */
/* Return 0 to retry, 1 to abort */
static int ierror(inst *it, inst_code ic) {
@@ -211,6 +258,8 @@ int displ, /* 1 = Use display emissive mode, 2 = display bright rel. */
/* 3 = display white rel. */
int dtype, /* Display type selection charater */
inst_opt_filter fe, /* Optional filter */
+xcalstd scalstd, /* X-Rite calibration standard to set */
+xcalstd *ucalstd, /* X-Rite calibration standard actually used */
int nocal, /* Disable initial calibration */
int disbidi, /* Disable automatic bi-directional strip recognition */
int highres, /* Use high res spectral mode */
@@ -224,6 +273,7 @@ int spectral, /* Generate spectral info flag */
int uvmode, /* ~~~ i1pro2 test mode ~~~ */
int accurate_expd, /* Expected values can be assumed to be accurate */
int emit_warnings, /* Emit warnings for wrong strip, unexpected value */
+int doplot, /* Plot each spectra in patch by patch mode */
a1log *log /* verb, debug & error log */
) {
inst *it = NULL;
@@ -251,6 +301,11 @@ a1log *log /* verb, debug & error log */
printf("Unknown, inappropriate or no instrument detected\n");
return -1;
}
+
+#ifdef TEST_EVENT_CALLBACK
+ it->set_event_callback(it, test_event_callback, (void *)it);
+#endif
+
/* Establish communications */
if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
printf("Establishing communications with instrument failed with message '%s' (%s)\n",
@@ -276,6 +331,24 @@ a1log *log /* verb, debug & error log */
return -1;
}
+ /* For reflective */
+ if (emis == 0 && trans == 0) {
+
+ /* set XRGA conversion */
+ if (scalstd != xcalstd_none) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_xcalstd, scalstd)) != inst_ok) {
+ printf("Warning: Setting calibration standard not supported by instrument\n");
+ }
+ }
+
+ /* Get actual XRGA conversion */
+ if (ucalstd != NULL) {
+ if ((rv = it->get_set_opt(it, inst_opt_get_xcalstd, ucalstd)) != inst_ok) {
+ *ucalstd = xcalstd_none;
+ }
+ }
+ }
+
*atype = it->get_itype(it); /* Actual instrument type */
if (*atype != itype)
a1logv(log, 1, "Warning: chart is for %s, using instrument %s\n",inst_name(itype),inst_name(*atype));
@@ -297,8 +370,8 @@ a1log *log /* verb, debug & error log */
} else if (emis || displ) {
if (emis) {
- if (!IMODETST(cap, inst_mode_emis_spot)
- && !IMODETST(cap, inst_mode_emis_strip)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok
+ && it->check_mode(it, inst_mode_emis_strip) != inst_ok) {
printf("Need emissive spot or strip reading capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -306,7 +379,7 @@ a1log *log /* verb, debug & error log */
}
} else {
/* Should we allow for non-adaptive mode ? */
- if (!IMODETST(cap, inst_mode_emis_spot)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
printf("Need emissive reading capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -314,7 +387,7 @@ a1log *log /* verb, debug & error log */
}
}
- } else {
+ } else { /* reflectance */
if (!IMODETST(cap, inst_mode_reflection)) {
printf("Need reflection spot, strip, xy or chart reading capability,\n");
printf("and instrument doesn't support it\n");
@@ -461,20 +534,17 @@ a1log *log /* verb, debug & error log */
/* Should look at instrument type & user spec ??? */
if (trans) {
- if (pbypatch && IMODETST(cap, inst_mode_trans_spot)
+ if (pbypatch
&& it->check_mode(it, inst_mode_trans_spot) == inst_ok) {
mode = inst_mode_trans_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_trans_chart)
- && it->check_mode(it, inst_mode_trans_chart) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_chart) == inst_ok) {
mode = inst_mode_trans_chart;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_trans_xy)
- && it->check_mode(it, inst_mode_trans_xy) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_xy) == inst_ok) {
mode = inst_mode_trans_xy;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_trans_strip)
- && it->check_mode(it, inst_mode_trans_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_strip) == inst_ok) {
mode = inst_mode_trans_strip;
rmode = 1;
} else {
@@ -482,23 +552,24 @@ a1log *log /* verb, debug & error log */
rmode = 0;
}
} else if (displ) {
+printf("~1 using displ mode\n");
/* We assume a display mode will always be spot by spot */
mode = inst_mode_emis_spot;
rmode = 0;
} else if (emis) {
- if (pbypatch && IMODETST(cap, inst_mode_emis_spot)
+printf("~1 using emis mode\n");
+ if (pbypatch
&& it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_emis_strip)
- && it->check_mode(it, inst_mode_emis_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_emis_strip) == inst_ok) {
mode = inst_mode_emis_strip;
rmode = 1;
} else {
mode = inst_mode_emis_spot;
rmode = 0;
}
- } else {
+ } else { /* Reflectance */
inst_stat_savdrd sv = inst_stat_savdrd_none;
/* See if instrument has a saved mode, and if it has data that */
@@ -602,58 +673,50 @@ a1log *log /* verb, debug & error log */
}
if (pbypatch
- && IMODETST(cap, inst_mode_s_ref_spot)
&& it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
&& (sv & inst_stat_savdrd_spot)) {
mode = inst_mode_s_ref_spot;
svdmode = 1;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_s_ref_chart)
- && it->check_mode(it, inst_mode_s_ref_chart) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_chart) == inst_ok
&& (sv & inst_stat_savdrd_chart)) {
mode = inst_mode_s_ref_chart;
svdmode = 1;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_s_ref_xy)
- && it->check_mode(it, inst_mode_s_ref_xy) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_xy) == inst_ok
&& (sv & inst_stat_savdrd_xy)) {
mode = inst_mode_s_ref_xy;
svdmode = 1;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_s_ref_strip)
- && it->check_mode(it, inst_mode_s_ref_strip) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_strip) == inst_ok
&& (sv & inst_stat_savdrd_strip)) {
mode = inst_mode_s_ref_strip;
svdmode = 1;
rmode = 1;
- } else if (IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
&& (sv & inst_stat_savdrd_spot)) {
mode = inst_mode_s_ref_spot;
svdmode = 1;
rmode = 0;
- } else if (pbypatch && IMODETST(cap, inst_mode_ref_spot)
+ } else if (pbypatch
&& it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
mode = inst_mode_ref_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_ref_chart)
- && it->check_mode(it, inst_mode_ref_chart) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_chart) == inst_ok) {
mode = inst_mode_ref_chart;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_ref_xy)
- && it->check_mode(it, inst_mode_ref_xy) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_xy) == inst_ok) {
mode = inst_mode_ref_xy;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_ref_strip)
- && it->check_mode(it, inst_mode_ref_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_strip) == inst_ok) {
mode = inst_mode_ref_strip;
rmode = 1;
@@ -1076,6 +1139,12 @@ a1log *log /* verb, debug & error log */
int pai; /* Current pass in current strip */
int oroi; /* Overall row index */
+ if (
+ itype != instDTP20 &&
+ !rand && disbidi == 0) {
+ warning("Can't do bi-directional strip recognition without randomized patch locations");
+ }
+
/* Do any needed calibration before the user places the instrument on a desired spot */
if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
if ((rv = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0))
@@ -1168,6 +1237,7 @@ a1log *log /* verb, debug & error log */
pai = 0;
}
//printf("~1 stix = %d, pis[stix] = %d, oroi = %d, rr %d\n",stix, pis[stix],oroi,scols[oroi * stipa]->rr);
+ // Note we aren't protecting agains a bodgy pis[] value
if (incflag == 1 || scols[oroi * stipa]->rr == 0 || oroi == s_oroi)
break;
}
@@ -1261,8 +1331,8 @@ a1log *log /* verb, debug & error log */
/* Not all rows have been read */
empty_con_chars();
- printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
- scols[i]->loc);
+ printf("\nDone ? - At least one unread patch (%s, %s), Are you sure [y/n]: ",
+ scols[i]->id, scols[i]->loc);
fflush(stdout);
ch = next_con_char();
printf("\n");
@@ -1333,7 +1403,8 @@ a1log *log /* verb, debug & error log */
return -1;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1386,9 +1457,9 @@ a1log *log /* verb, debug & error log */
double werror = 0.0; /* Worst case error in best correlation strip */
double xbcorr = 1e6; /* Expected pass correlation value */
- int xboff; /* Expected pass offset */
+ int xboff; /* Expected pass best offset */
int xbdir; /* Expected pass overall pass direction */
- double xwerror = 0.0; /* Expected pass worst error in best strip */
+ double xwerror = 0.0; /* Expected pass worst patcch error */
if (rand && disbidi == 0 && (cap2 & inst2_bidi_scan))
dirrg = 2; /* Enable bi-directional strip recognition */
@@ -1426,17 +1497,29 @@ a1log *log /* verb, debug & error log */
}
/* Compare just sample patches (not padding Max/Min) */
- for (pwerr = corr = 0.0, n = 0, i = 0; i < stipa; i++, n++) {
+#ifdef USESTRDELTA
+ for (pwerr = corr = 0.0, n = 0, i = 0; i < (stipa-1); i++, n++)
+#else
+ for (pwerr = corr = 0.0, n = 0, i = 0; i < stipa; i++, n++)
+#endif
+ {
double vcorr;
- int ix = i+skipp+toff;
- if (dir != 0)
+ int ix = i+skipp+toff, ix1 = ix+1;
+ if (dir != 0) {
ix = stipa - 1 - ix;
+ ix1 = stipa - 1 - ix1;
+ }
if (vals[ix].XYZ_v == 0)
error("Instrument didn't return XYZ value");
+#ifdef USESTRDELTA
+ vcorr = xyzLabcorr(vals[ix].XYZ, scb[i]->eXYZ,
+ vals[ix1].XYZ, scb[i+1]->eXYZ);
+#else
vcorr = xyzLabDE(ynorm, vals[ix].XYZ, scb[i]->eXYZ);
+#endif
//printf("DE %f from vals[%d] %f %f %f and scols[%d] %f %f %f\n", vcorr, ix, vals[ix].XYZ[0], vals[ix].XYZ[1], vals[ix].XYZ[2], i + choroi * stipa, scb[i]->eXYZ[0], scb[i]->eXYZ[1], scb[i]->eXYZ[2]);
corr += vcorr;
- if (vcorr > pwerr)
+ if (vcorr > pwerr) /* Worsed patch error */
pwerr = vcorr;
}
corr /= (double)n;
@@ -1444,16 +1527,16 @@ a1log *log /* verb, debug & error log */
printf(" Strip %d dir %d offset %d correlation = %f\n",choroi,dir,toff,corr);
#endif
- /* Expected strip correlation and */
- /* best fir to off by 1 and direction */
+ /* If this is the expected strip, */
+ /* note correlation and best fit to off by 1 and direction */
if (choroi == oroi && corr < xbcorr) {
- xbcorr = corr;
+ xbcorr = corr; /* Expected strip correlation */
xboff = toff;
xbdir = dir;
xwerror = pwerr; /* Expected passes worst error */
}
- /* Best matched strip correlation */
+ /* Best overall matched strip correlation */
if (corr < bcorr) {
boroi = choroi;
bcorr = corr;
@@ -1624,6 +1707,7 @@ a1log *log /* verb, debug & error log */
inst_set_uih('G', 'G', DUIH_CMND);
inst_set_uih('d', 'd', DUIH_CMND);
inst_set_uih('D', 'D', DUIH_CMND);
+ inst_set_uih('k', 'k', DUIH_CMND);
inst_set_uih('q', 'q', DUIH_ABORT);
inst_set_uih('Q', 'Q', DUIH_ABORT);
inst_set_uih(0xd, 0xd, DUIH_TRIG); /* Return */
@@ -1637,7 +1721,7 @@ a1log *log /* verb, debug & error log */
incflag = 3;
/* Until we're done */
- for(;pix < npat;) {
+ for (;pix < npat;) {
char buf[200], *bp = NULL, *ep = NULL;
char ch = 0;
@@ -1716,7 +1800,7 @@ a1log *log /* verb, debug & error log */
}
if (xtern != 0) { /* User entered values */
- printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ printf("\nReady to read patch '%s' at '%s'%s\n",scols[pix]->id, scols[pix]->loc,
i >= npat ? "(All patches read!)" :
strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
scols[pix]->rr ? " (Already read)" : "");
@@ -1747,7 +1831,7 @@ a1log *log /* verb, debug & error log */
empty_con_chars();
- printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ printf("\nReady to read patch '%s' at '%s'%s\n",scols[pix]->id, scols[pix]->loc,
i >= npat ? " (All patches read!)" :
strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
scols[pix]->rr ? " (Already read)" : "");
@@ -1755,7 +1839,7 @@ a1log *log /* verb, debug & error log */
printf("hit 'f' to move forward, 'F' move forward 10,\n");
printf(" 'b' to move back, 'B; to move back 10,\n");
printf(" 'n' for next unread, 'g' to goto patch,\n");
- printf(" 'd' when done, <esc> to abort,\n");
+ printf(" 'd' when done, 'k' to calibrate, <esc> to abort,\n");
if (uswitch)
printf(" Instrument switch, <return> or <space> to read:");
@@ -1772,7 +1856,7 @@ a1log *log /* verb, debug & error log */
good_beep();
ch = '0';
- /* Deal with user trigger */
+ /* Deal with user trigger via user interface callback function */
} else if ((rv & inst_mask) == inst_user_trig) {
if (cap2 & inst2_no_feedback)
good_beep();
@@ -1841,7 +1925,8 @@ a1log *log /* verb, debug & error log */
return -1;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1891,6 +1976,15 @@ a1log *log /* verb, debug & error log */
}
printf("\n");
continue;
+ } else if (ch == 'k') {
+ inst_code ev;
+
+ ev = inst_handle_calibrate(it, inst_calt_available, inst_calc_none, NULL, NULL, 0);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ it->del(it);
+ return -1;
+ }
+ continue;
} else if (ch == 'f') {
incflag = 1;
continue;
@@ -1920,8 +2014,8 @@ a1log *log /* verb, debug & error log */
/* Not all patches have been read */
empty_con_chars();
- printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
- scols[i]->loc);
+ printf("\nDone ? - At least one unread patch (%s, %s), Are you sure [y/n]: ",
+ scols[i]->id, scols[i]->loc);
fflush(stdout);
if ((ch = next_con_char()) == 0x1b) {
printf("\n");
@@ -1996,6 +2090,10 @@ a1log *log /* verb, debug & error log */
}
scols[pix]->rr = 1; /* Has been read */
printf(" Patch read OK\n");
+
+ if (doplot && val.sp.spec_n > 0)
+ xspect_plot_w(&val.sp, NULL, NULL, 0);
+
/* Advance to next patch. */
incflag = 1;
} else { /* Unrecognised response */
@@ -2018,7 +2116,7 @@ usage() {
fprintf(stderr,"usage: chartread [-options] outfile\n");
fprintf(stderr," -v Verbose mode\n");
fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
- if ((icmps = new_icompaths(NULL)) != NULL) {
+ if ((icmps = new_icompaths(g_log)) != NULL) {
icompath **paths;
if ((paths = icmps->paths) != NULL) {
int i;
@@ -2046,6 +2144,7 @@ usage() {
fprintf(stderr," p Polarising filter\n");
fprintf(stderr," 6 D65\n");
fprintf(stderr," u U.V. Cut\n");
+ fprintf(stderr," -A N|A|X|G XRGA conversion (default N)\n");
fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
fprintf(stderr," -B Disable auto bi-directional strip recognition\n");
fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
@@ -2055,12 +2154,19 @@ usage() {
int i;
fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
fprintf(stderr," -Q observ Choose CIE Observer for CCSS instrument:\n");
+#ifdef SALONEINSTLIB
+ fprintf(stderr," 1931_2 (def), 1964_10\n");
+#else /* !SALONEINSTLIB */
fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+#endif /* !SALONEINSTLIB */
}
fprintf(stderr," -T ratio Modify strip patch consistency tolerance by ratio\n");
fprintf(stderr," -S Suppress wrong strip & unexpected value warnings\n");
// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -P Plot spectral if patch by patch\n");
+#endif
fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
fprintf(stderr," outfile Base name for input[ti2]/output[ti3] file\n");
if (icmps != NULL)
@@ -2092,11 +2198,14 @@ int main(int argc, char *argv[]) {
int xtern = 0; /* Take external values, 1 = Lab, 2 = XYZ */
int spectral = 1; /* Save spectral information */
int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ xcalstd scalstd = xcalstd_none; /* X-Rite calibration standard to set */
+ xcalstd ucalstd = xcalstd_none; /* X-Rite calibration standard actually used */
int accurate_expd = 0; /* Expected value assumed to be accurate */
int emit_warnings = 1; /* Emit warnings for wrong strip, unexpected value */
int dolab = 0; /* 1 = Save CIE as Lab, 2 = Save CIE as XYZ and Lab */
int doresume = 0; /* Resume reading a chart */
int nocal = 0; /* Disable initial calibration */
+ int doplot = 0; /* Plot spectral of patch by patch */
char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
icxObserverType obType = icxOT_default; /* ccss observer */
static char inname[MAXNAMEL+1] = { 0 }; /* Input cgats file base name */
@@ -2191,12 +2300,14 @@ int main(int argc, char *argv[]) {
obType = icxOT_CIE_1931_2;
} else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
obType = icxOT_CIE_1964_10;
+#ifndef SALONEINSTLIB
} else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
obType = icxOT_Stiles_Burch_2;
} else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
obType = icxOT_Judd_Voss_2;
} else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
obType = icxOT_Shaw_Fairchild_2;
+#endif /* !SALONEINSTLIB */
} else
usage();
}
@@ -2217,7 +2328,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage();
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -2320,6 +2431,27 @@ int main(int argc, char *argv[]) {
else
usage();
+ /* XRGA conversion */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (na[0] == 'N')
+ scalstd = xcalstd_none;
+ else if (na[0] == 'A')
+ scalstd = xcalstd_xrga;
+ else if (na[0] == 'X')
+ scalstd = xcalstd_xrdi;
+ else if (na[0] == 'G')
+ scalstd = xcalstd_gmdi;
+ else
+ usage();
+
+#ifndef SALONEINSTLIB
+ /* Plot spectral patch by patch */
+ } else if (argv[fa][1] == 'P') {
+ doplot = 1;
+#endif
+
/* Extra flags */
} else if (argv[fa][1] == 'Y') {
if (na == NULL)
@@ -2392,7 +2524,7 @@ int main(int argc, char *argv[]) {
if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
error ("Unrecognised chart target instrument '%s'", icg->t[0].kdata[ti]);
} else {
- itype = instDTP41; /* Default chart target instrument */
+ itype = instI1Pro; /* Default chart target instrument */
}
}
@@ -2508,10 +2640,6 @@ int main(int argc, char *argv[]) {
tlen = atof(icg->t[0].kdata[ti]);
}
- if (itype != instDTP20 && !rand && disbidi == 0) {
- warning("Can't do bi-directional strip recognition without randomize patch locations");
- }
-
if (verb) {
printf("Steps in each Pass = %d\n",stipa);
printf("Passes in each Strip = ");
@@ -2537,6 +2665,8 @@ int main(int argc, char *argv[]) {
totpa = (npat + stipa -1)/stipa; /* Total passes for all strips */
runpat = stipa * totpa; /* Rounded up totao number of patches */
+ if (runpat < npat) /* (If pattern doesn't match patches) */
+ runpat = npat;
if ((cols = (chcol *)malloc(sizeof(chcol) * runpat)) == NULL)
error("Malloc failed!");
if ((scols = (chcol **)calloc(sizeof(chcol *), runpat)) == NULL)
@@ -2684,29 +2814,40 @@ int main(int argc, char *argv[]) {
cal = NULL;
}
- /* Set up the location sorted array of pointers */
- for (i = 0; i < npat; i++) {
- scols[i] = &cols[i];
- if ((cols[i].loci = patch_location_order(paix, saix, ixord, cols[i].loc)) < 0)
- error ("Bad location field value '%s' on patch %d", cols[i].loc, i);
- }
- for (; i < runpat; i++) { /* Extra on end */
- scols[i] = &cols[i];
- cols[i].loci = (totpa-1) * (256 - stipa) + i;
+ /* Set up the location sorted array of pointers. */
+ /* If the order is not randomized, we don't care what form */
+ /* the location identifiers take - i.e. they can be arbitrary. */
+ {
+ int badloc = 0;
+
+ for (i = 0; i < npat; i++) {
+ scols[i] = &cols[i];
+ if ((cols[i].loci = patch_location_order(paix, saix, ixord, cols[i].loc)) < 0)
+ badloc = 1;
+ }
+ for (; i < runpat; i++) { /* Extra on end */
+ scols[i] = &cols[i];
+ cols[i].loci = (totpa-1) * (256 - stipa) + i;
/* printf("~~extra = %d, %d\n",cols[i].loci >> 8, cols[i].loci & 255); */
- }
+ }
- /* Reset 'read' flag and all data */
- for (i = 0; i < runpat; i++) {
- cols[i].rr = 0;
- cols[i].XYZ[0] = -1.0;
- cols[i].XYZ[1] = -1.0;
- cols[i].XYZ[2] = -1.0;
- cols[i].sp.spec_n = 0;
- }
+ /* Reset 'read' flag and all data */
+ for (i = 0; i < runpat; i++) {
+ cols[i].rr = 0;
+ cols[i].XYZ[0] = -1.0;
+ cols[i].XYZ[1] = -1.0;
+ cols[i].XYZ[2] = -1.0;
+ cols[i].sp.spec_n = 0;
+ }
+
+ if (rand && badloc)
+ error ("Bad location field value '%s' on patch %d", cols[i].loc, i);
+ if (!badloc) {
#define HEAP_COMPARE(A,B) (A->loci < B->loci)
- HEAPSORT(chcol *, scols, npat);
+ HEAPSORT(chcol *, scols, npat);
+ }
+ }
/* If we're resuming a chartread, fill in all the patches that */
/* have been read. */
@@ -2840,17 +2981,20 @@ int main(int argc, char *argv[]) {
}
}
- if ((icmps = new_icompaths(g_log)) == NULL)
- error("Finding instrument paths failed");
- if ((ipath = icmps->get_path(icmps, comport)) == NULL)
- error("No instrument at port %d",comport);
+ if (!xtern) {
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+ }
/* Read all of the strips in */
if (read_strips(itype, scols, &atype, npat, totpa, stipa, pis, paix,
saix, ixord, rstart, rand, hex, ipath, fc, plen, glen, tlen,
- trans, emis, displ, dtype, fe, nocal, disbidi, highres, ccxxname, obType,
+ trans, emis, displ, dtype, fe, scalstd, &ucalstd, nocal, disbidi, highres,
+ ccxxname, obType,
scan_tol, pbypatch, xtern, spectral, uvmode, accurate_expd,
- emit_warnings, g_log) == 0) {
+ emit_warnings, doplot, g_log) == 0) {
/* And save the result */
int nrpat; /* Number of read patches */
@@ -2861,6 +3005,10 @@ int main(int argc, char *argv[]) {
/* Note what instrument the chart was read with */
ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(atype) , NULL);
+ /* X-Rite calibration standard (If reflective mode) */
+ if (displ == 0 && trans == 0 && ucalstd != xcalstd_none)
+ ocg->add_kword(ocg, 0, "DEVCALSTD",xcalstd2str(ucalstd), NULL);
+
/* Count patches actually read */
for (nrpat = i = 0; i < npat; i++) {
if (cols[i].rr) {
diff --git a/spectro/colorhug.c b/spectro/colorhug.c
index 7397314..fefe766 100644
--- a/spectro/colorhug.c
+++ b/spectro/colorhug.c
@@ -1138,8 +1138,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-colorhug_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+colorhug_get_set_opt(inst *pp, inst_opt_type m, ...) {
colorhug *p = (colorhug *)pp;
inst_code ev = inst_ok;
@@ -1184,7 +1183,17 @@ colorhug_get_set_opt(inst *pp, inst_opt_type m, ...)
return colorhug_set_LEDs(p, mask);
}
- 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 */
diff --git a/spectro/colorhug.h b/spectro/colorhug.h
index 90fff6f..8617705 100644
--- a/spectro/colorhug.h
+++ b/spectro/colorhug.h
@@ -20,6 +20,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update colorhug_interp_error() and colorhug_interp_code() in colorhug.c */
/* if anything of these #defines are added or subtracted */
@@ -94,6 +98,10 @@ struct _colorhug {
/* Constructor */
extern colorhug *new_colorhug(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define COLORHUG_H
#endif /* COLORHUG_H */
diff --git a/spectro/conv.c b/spectro/conv.c
index 94023db..284a30c 100644
--- a/spectro/conv.c
+++ b/spectro/conv.c
@@ -64,7 +64,7 @@
#include "conv.h"
#include "icoms.h"
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
//#include <stdbool.h>
#include <sys/sysctl.h>
#include <sys/param.h>
@@ -81,7 +81,7 @@
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
# include <objc/objc-auto.h>
#endif
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#undef DEBUG
@@ -131,6 +131,8 @@ int next_con_char(void) {
return c;
}
+#ifdef NEVER // Don't need this now.
+
/* Horrible hack to poll stdin when we're not interactive. */
/* This has the drawback that the char and returm must be */
/* written in one operation for the character to be recognised - */
@@ -143,9 +145,12 @@ static int th_read_char(void *pp) {
DWORD bread;
if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ *rp = 0; /* We've started */
return 0;
}
+ *rp = 0; /* We've started */
+
if (ReadFile(stdinh, buf, 1, &bread, NULL)
&& bread == 1
&& buf[0] != '\r' && buf[0] != '\n') {
@@ -154,32 +159,65 @@ static int th_read_char(void *pp) {
return 0;
}
+#endif /* NEVER */
/* If there is one, return the next character from the keyboard, else return 0 */
/* (If not_interactive, always returns 0) */
int poll_con_char(void) {
if (not_interactive) { /* Can't assume that it's the console */
+
+#ifdef NEVER // Use better approach below.
athread *getch_thread = NULL;
- char c = 0;
+ volatile char c = 0xff;
/* This is pretty horrible. The problem is that we can't use */
/* any of MSWin's async file read functions, because we */
/* have no way of ensuring that the STD_INPUT_HANDLE has been */
/* opened with FILE_FLAG_OVERLAPPED. Used a thread instead... */
- /* ReOpenFile() would fix this, but it's not available in WinXP, only Visa+ :-( */
- if ((getch_thread = new_athread(th_read_char, &c)) != NULL) {
+ /* ReOpenFile() would in theory fix this, but it's not available in WinXP, only Visa+, */
+ /* and aparently doesn't work on stdin anyway! :-( */
+ if ((getch_thread = new_athread(th_read_char, (char *)&c)) != NULL) {
HANDLE stdinh;
if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
return 0;
}
- Sleep(100); /* We just hope 1 msec is enough for the thread to start */
- CancelIo(stdinh);
+ /* Wait for the thread to start */
+ while (c == 0xff) {
+ Sleep(10); /* We just hope 1 msec is enough for the thread to start */
+ }
+ Sleep(10); /* Give it time to read */
+ CancelIo(stdinh); /* May not work since ReadFile() is on a different thread ? */
getch_thread->del(getch_thread);
return c;
}
+#else /* ! NEVER */
+ /* This approach is very flakey from the console, but seems */
+ /* to work reliably when operated progromatically. */
+ HANDLE stdinh;
+ char buf[10] = { 0 }, c;
+ DWORD bread;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+// printf("Waiting\n");
+ if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) {
+// printf("stdin signalled\n");
+
+// FlushFileBuffers(stdinh);
+// FlushConsoleInputBuffer(stdinh);
+ if (ReadFile(stdinh, buf, 1, &bread, NULL)) {
+ int i;
+// fprintf(stderr,"Read %d chars 0x%x 0x%x 0x%x\n",bread,buf[0],buf[1], buf[2]);
+ if (buf[0] != '\r' && buf[0] != '\n')
+ return buf[0];
+ return 0;
+ }
+ }
+#endif /* !NEVER */
return 0;
}
@@ -192,10 +230,23 @@ int poll_con_char(void) {
}
/* Suck all characters from the keyboard */
-/* (If not_interactive, does nothing) */
+/* (If not_interactive, does nothing ?) */
void empty_con_chars(void) {
if (not_interactive) {
+ HANDLE stdinh;
+ char buf[100] = { 0 }, c;
+ DWORD bread;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
+ return;
+ for (;;) {
+ if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) {
+ ReadFile(stdinh, buf, 100, &bread, NULL);
+ } else {
+ break;
+ }
+ }
return;
}
@@ -211,51 +262,6 @@ void sleep(unsigned int secs) {
Sleep(secs * 1000);
}
-/* Sleep for the given number of msec */
-void msec_sleep(unsigned int msec) {
- Sleep(msec);
-}
-
-/* Return the current time in msec since */
-/* the first invokation of msec_time() */
-/* (Is this based on timeGetTime() ? ) */
-unsigned int msec_time() {
- unsigned int rv;
- static unsigned int startup = 0;
-
- rv = GetTickCount();
- if (startup == 0)
- startup = rv;
-
- return rv - startup;
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-/* Return -1.0 if not available */
-double usec_time() {
- double rv;
- LARGE_INTEGER val;
- static double scale = 0.0;
- static LARGE_INTEGER startup;
-
- if (scale == 0.0) {
- if (QueryPerformanceFrequency(&val) == 0)
- return -1.0;
- scale = 1000000.0/val.QuadPart;
- QueryPerformanceCounter(&val);
- startup.QuadPart = val.QuadPart;
-
- } else {
- QueryPerformanceCounter(&val);
- }
- val.QuadPart -= startup.QuadPart;
-
- rv = val.QuadPart * scale;
-
- return rv;
-}
-
static athread *beep_thread = NULL;
static int beep_delay;
static int beep_freq;
@@ -552,126 +558,6 @@ void empty_con_chars(void) {
tcflush(STDIN_FILENO, TCIFLUSH);
}
-/* Sleep for the given number of msec */
-/* (Note that OS X 10.9+ App Nap can wreck this, unless */
-/* it is turned off.) */
-void msec_sleep(unsigned int msec) {
-#ifdef NEVER
- if (msec > 1000) {
- unsigned int secs;
- secs = msec / 1000;
- msec = msec % 1000;
- sleep(secs);
- }
- usleep(msec * 1000);
-#else
- struct timespec ts;
-
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- nanosleep(&ts, NULL);
-#endif
-}
-
-
-#if defined(__APPLE__) && !defined(CLOCK_MONOTONIC)
-
-#include <mach/mach_time.h>
-
-unsigned int msec_time() {
- mach_timebase_info_data_t timebase;
- static uint64_t startup = 0;
- uint64_t time;
- double msec;
-
- time = mach_absolute_time();
- if (startup == 0)
- startup = time;
-
- mach_timebase_info(&timebase);
- time -= startup;
- msec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e6);
-
- return (unsigned int)floor(msec + 0.5);
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-double usec_time() {
- mach_timebase_info_data_t timebase;
- static uint64_t startup = 0;
- uint64_t time;
- double usec;
-
- time = mach_absolute_time();
- if (startup == 0)
- startup = time;
-
- mach_timebase_info(&timebase);
- time -= startup;
- usec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e3);
-
- return usec;
-}
-
-#else
-
-/* Return the current time in msec */
-/* since the first invokation of msec_time() */
-unsigned int msec_time() {
- unsigned int rv;
- static struct timespec startup = { 0, 0 };
- struct timespec cv;
-
- clock_gettime(CLOCK_MONOTONIC, &cv);
-
- /* Set time to 0 on first invocation */
- if (startup.tv_sec == 0 && startup.tv_nsec == 0)
- startup = cv;
-
- /* Subtract, taking care of carry */
- cv.tv_sec -= startup.tv_sec;
- if (startup.tv_nsec > cv.tv_nsec) {
- cv.tv_sec--;
- cv.tv_nsec += 1000000000;
- }
- cv.tv_nsec -= startup.tv_nsec;
-
- /* Convert nsec to msec */
- rv = cv.tv_sec * 1000 + cv.tv_nsec / 1000000;
-
- return rv;
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-double usec_time() {
- double rv;
- static struct timespec startup = { 0, 0 };
- struct timespec cv;
-
- clock_gettime(CLOCK_MONOTONIC, &cv);
-
- /* Set time to 0 on first invocation */
- if (startup.tv_sec == 0 && startup.tv_nsec == 0)
- startup = cv;
-
- /* Subtract, taking care of carry */
- cv.tv_sec -= startup.tv_sec;
- if (startup.tv_nsec > cv.tv_nsec) {
- cv.tv_sec--;
- cv.tv_nsec += 1000000000;
- }
- cv.tv_nsec -= startup.tv_nsec;
-
- /* Convert to usec */
- rv = cv.tv_sec * 1000000.0 + cv.tv_nsec/1000;
-
- return rv;
-}
-
-#endif
-
/* - - - - - - - - - - - - - - - - - - - - - - - - */
int acond_timedwait_imp(pthread_cond_t *cond, pthread_mutex_t *lock, int msec) {
@@ -699,7 +585,7 @@ int acond_timedwait_imp(pthread_cond_t *cond, pthread_mutex_t *lock, int msec) {
/* Set the current threads priority */
int set_interactive_priority() {
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#ifdef NEVER
int rv = 0;
struct task_category_policy tcatpolicy;
@@ -725,7 +611,7 @@ int set_interactive_priority() {
// a1logd(g_log, 8, "set_interactive_priority: set to important got %d\n",rv);
return rv;
#endif /* NEVER */
-#else /* !APPLE */
+#else /* !UNIX_APPLE */
int rv;
struct sched_param param;
param.sched_priority = 32;
@@ -734,11 +620,11 @@ int set_interactive_priority() {
rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
// a1logd(g_log, 8, "set_interactive_priority: set got %d\n",rv);
return rv;
-#endif /* !APPLE */
+#endif /* !UNIX_APPLE */
}
int set_normal_priority() {
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#ifdef NEVER
int rv = 0;
struct task_category_policy tcatpolicy;
@@ -763,7 +649,7 @@ int set_normal_priority() {
// a1logd(g_log, 8, "set_normal_priority: set to standard got %d\n",rv);
return rv;
#endif /* NEVER */
-#else /* !APPLE */
+#else /* !UNIX_APPLE */
struct sched_param param;
param.sched_priority = 0;
int rv;
@@ -771,7 +657,7 @@ int set_normal_priority() {
rv = pthread_setschedparam(pthread_self(), SCHED_OTHER, &param);
// a1logd(g_log, 8, "set_normal_priority: reset got %d\n",rv);
return rv;
-#endif /* !APPLE */
+#endif /* !UNIX_APPLE */
}
#endif /* NEVER */
@@ -786,7 +672,7 @@ static int beep_msec;
static int delayed_beep(void *pp) {
msec_sleep(beep_delay);
a1logd(g_log,8, "msec_beep activate\n");
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
# else
@@ -812,7 +698,7 @@ void msec_beep(int delay, int freq, int msec) {
a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
} else {
a1logd(g_log,8, "msec_beep activate\n");
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
# else
@@ -980,7 +866,7 @@ int create_parent_directories(char *path) {
#endif /* defined(UNIX) */
/* - - - - - - - - - - - - - - - - - - - - - - - - */
-#if defined(__APPLE__) || defined(NT)
+#if defined(UNIX_APPLE) || defined(NT)
/* Thread to monitor and kill the named processes */
static int th_kkill_nprocess(void *pp) {
@@ -1109,7 +995,7 @@ int kill_nprocess(char **pname, a1log *log) {
#endif /* NT */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
/* Kill a list of named process. */
/* Kill the first process found, then return */
@@ -1188,411 +1074,8 @@ int kill_nprocess(char **pname, a1log *log) {
return rv;
}
-#endif /* __APPLE__ */
-
-#endif /* __APPLE__ || NT */
-
-/* ============================================================= */
-
-/* A very small subset of icclib, copied to here. */
-/* This is just enough to support the standalone instruments */
-#ifdef SALONEINSTLIB
-
-sa_XYZNumber sa_D50 = {
- 0.9642, 1.0000, 0.8249
-};
-
-sa_XYZNumber sa_D65 = {
- 0.9505, 1.0000, 1.0890
-};
-
-void sa_SetUnity3x3(double mat[3][3]) {
- int i, j;
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++) {
- if (i == j)
- mat[j][i] = 1.0;
- else
- mat[j][i] = 0.0;
- }
- }
-
-}
-
-void sa_Cpy3x3(double dst[3][3], double src[3][3]) {
- int i, j;
-
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++)
- dst[j][i] = src[j][i];
- }
-}
-
-void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]) {
- double tt[3];
-
- tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
- tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
- tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+#endif /* UNIX_APPLE */
- out[0] = tt[0];
- out[1] = tt[1];
- out[2] = tt[2];
-}
-
-void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
- int i, j, k;
- double td[3][3]; /* Temporary dest */
-
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++) {
- double tt = 0.0;
- for (k = 0; k < 3; k++)
- tt += src1[j][k] * src2[k][i];
- td[j][i] = tt;
- }
- }
-
- /* Copy result out */
- for (j = 0; j < 3; j++)
- for (i = 0; i < 3; i++)
- dst[j][i] = td[j][i];
-}
-
-
-/* Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
-#define det2x2(a, b, c, d) (a * d - b * c)
-
-static void adjoint(
-double out[3][3],
-double in[3][3]
-) {
- double a1, a2, a3, b1, b2, b3, c1, c2, c3;
-
- /* assign to individual variable names to aid */
- /* selecting correct values */
-
- a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
- a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
- a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
-
- /* row column labeling reversed since we transpose rows & columns */
-
- out[0][0] = det2x2(b2, b3, c2, c3);
- out[1][0] = - det2x2(a2, a3, c2, c3);
- out[2][0] = det2x2(a2, a3, b2, b3);
-
- out[0][1] = - det2x2(b1, b3, c1, c3);
- out[1][1] = det2x2(a1, a3, c1, c3);
- out[2][1] = - det2x2(a1, a3, b1, b3);
-
- out[0][2] = det2x2(b1, b2, c1, c2);
- out[1][2] = - det2x2(a1, a2, c1, c2);
- out[2][2] = det2x2(a1, a2, b1, b2);
-}
-
-static double sa_Det3x3(double in[3][3]) {
- double a1, a2, a3, b1, b2, b3, c1, c2, c3;
- double ans;
-
- a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
- a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
- a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
-
- ans = a1 * det2x2(b2, b3, c2, c3)
- - b1 * det2x2(a2, a3, c2, c3)
- + c1 * det2x2(a2, a3, b2, b3);
- return ans;
-}
-
-#define SA__SMALL_NUMBER 1.e-8
-
-int sa_Inverse3x3(double out[3][3], double in[3][3]) {
- int i, j;
- double det;
-
- /* calculate the 3x3 determinant
- * if the determinant is zero,
- * then the inverse matrix is not unique.
- */
- det = sa_Det3x3(in);
-
- if ( fabs(det) < SA__SMALL_NUMBER)
- return 1;
-
- /* calculate the adjoint matrix */
- adjoint(out, in);
-
- /* scale the adjoint matrix to get the inverse */
- for (i = 0; i < 3; i++)
- for(j = 0; j < 3; j++)
- out[i][j] /= det;
- return 0;
-}
-
-#undef SA__SMALL_NUMBER
-#undef det2x2
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Transpose a 3x3 matrix */
-void sa_Transpose3x3(double out[3][3], double in[3][3]) {
- int i, j;
- if (out != in) {
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- out[i][j] = in[j][i];
- } else {
- double tt[3][3];
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- tt[i][j] = in[j][i];
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- out[i][j] = tt[i][j];
- }
-}
-
-/* Scale a 3 vector by the given ratio */
-void sa_Scale3(double out[3], double in[3], double rat) {
- out[0] = in[0] * rat;
- out[1] = in[1] * rat;
- out[2] = in[2] * rat;
-}
-
-/* Clamp a 3 vector to be +ve */
-void sa_Clamp3(double out[3], double in[3]) {
- int i;
- for (i = 0; i < 3; i++)
- out[i] = in[i] < 0.0 ? 0.0 : in[i];
-}
-
-/* Return the normal Delta E given two Lab values */
-double sa_LabDE(double *Lab0, double *Lab1) {
- double rv = 0.0, tt;
-
- tt = Lab0[0] - Lab1[0];
- rv += tt * tt;
- tt = Lab0[1] - Lab1[1];
- rv += tt * tt;
- tt = Lab0[2] - Lab1[2];
- rv += tt * tt;
-
- return sqrt(rv);
-}
-
-/* CIE XYZ to perceptual CIE 1976 L*a*b* */
-void
-sa_XYZ2Lab(icmXYZNumber *w, double *out, double *in) {
- double X = in[0], Y = in[1], Z = in[2];
- double x,y,z,fx,fy,fz;
-
- x = X/w->X;
- y = Y/w->Y;
- z = Z/w->Z;
-
- if (x > 0.008856451586)
- fx = pow(x,1.0/3.0);
- else
- fx = 7.787036979 * x + 16.0/116.0;
-
- if (y > 0.008856451586)
- fy = pow(y,1.0/3.0);
- else
- fy = 7.787036979 * y + 16.0/116.0;
-
- if (z > 0.008856451586)
- fz = pow(z,1.0/3.0);
- else
- fz = 7.787036979 * z + 16.0/116.0;
-
- out[0] = 116.0 * fy - 16.0;
- out[1] = 500.0 * (fx - fy);
- out[2] = 200.0 * (fy - fz);
-}
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* A sub-set of ludecomp code from numlib */
-
-int sa_lu_decomp(double **a, int n, int *pivx, double *rip) {
- int i, j;
- double *rscale, RSCALE[10];
-
- if (n <= 10)
- rscale = RSCALE;
- else
- rscale = dvector(0, n-1);
-
- for (i = 0; i < n; i++) {
- double big;
- for (big = 0.0, j=0; j < n; j++) {
- double temp;
- temp = fabs(a[i][j]);
- if (temp > big)
- big = temp;
- }
- if (fabs(big) <= DBL_MIN) {
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 1;
- }
- rscale[i] = 1.0/big;
- }
-
- for (*rip = 1.0, j = 0; j < n; j++) {
- double big;
- int k, bigi = 0;
-
- for (i = 0; i < j; i++) {
- double sum;
- sum = a[i][j];
- for (k = 0; k < i; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- }
-
- for (big = 0.0, i = j; i < n; i++) {
- double sum, temp;
- sum = a[i][j];
- for (k = 0; k < j; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- temp = rscale[i] * fabs(sum);
- if (temp >= big) {
- big = temp;
- bigi = i;
- }
- }
-
- if (j != bigi) {
- {
- double *temp;
- temp = a[bigi];
- a[bigi] = a[j];
- a[j] = temp;
- }
- *rip = -(*rip);
- rscale[bigi] = rscale[j];
- }
-
- pivx[j] = bigi;
- if (fabs(a[j][j]) <= DBL_MIN) {
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 1;
- }
-
- if (j != (n-1)) {
- double temp;
- temp = 1.0/a[j][j];
- for (i = j+1; i < n; i++)
- a[i][j] *= temp;
- }
- }
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 0;
-}
-
-void sa_lu_backsub(double **a, int n, int *pivx, double *b) {
- int i, j;
- int nvi;
-
- for (nvi = -1, i = 0; i < n; i++) {
- int px;
- double sum;
-
- px = pivx[i];
- sum = b[px];
- b[px] = b[i];
- if (nvi >= 0) {
- for (j = nvi; j < i; j++)
- sum -= a[i][j] * b[j];
- } else {
- if (sum != 0.0)
- nvi = i;
- }
- b[i] = sum;
- }
-
- for (i = (n-1); i >= 0; i--) {
- double sum;
- sum = b[i];
- for (j = i+1; j < n; j++)
- sum -= a[i][j] * b[j];
- b[i] = sum/a[i][i];
- }
-}
-
-int sa_lu_invert(double **a, int n) {
- int i, j;
- double rip;
- int *pivx, PIVX[10];
- double **y;
-
- if (n <= 10)
- pivx = PIVX;
- else
- pivx = ivector(0, n-1);
-
- if (sa_lu_decomp(a, n, pivx, &rip)) {
- if (pivx != PIVX)
- free_ivector(pivx, 0, n-1);
- return 1;
- }
-
- y = dmatrix(0, n-1, 0, n-1);
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++) {
- y[i][j] = a[i][j];
- }
- }
-
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++)
- a[i][j] = 0.0;
- a[i][i] = 1.0;
- sa_lu_backsub(y, n, pivx, a[i]);
- }
-
- free_dmatrix(y, 0, n-1, 0, n-1);
- if (pivx != PIVX)
- free_ivector(pivx, 0, n-1);
-
- return 0;
-}
-
-int sa_lu_psinvert(double **out, double **in, int m, int n) {
- int rv = 0;
- double **tr;
- double **sq;
-
- tr = dmatrix(0, n-1, 0, m-1);
- matrix_trans(tr, in, m, n);
-
- if (m > n) {
- sq = dmatrix(0, n-1, 0, n-1);
- if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
- if ((rv = sa_lu_invert(sq, n)) == 0) {
- rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
- }
- }
- free_dmatrix(sq, 0, n-1, 0, n-1);
- } else {
- sq = dmatrix(0, m-1, 0, m-1);
- if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
- if ((rv = sa_lu_invert(sq, m)) == 0) {
- rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
- }
- }
- free_dmatrix(sq, 0, m-1, 0, m-1);
- }
-
- free_dmatrix(tr, 0, n-1, 0, m-1);
- return rv;
-}
-
-
-#endif /* SALONEINSTLIB */
-/* ============================================================= */
+#endif /* UNIX_APPLE || NT */
diff --git a/spectro/conv.h b/spectro/conv.h
index 4e14dd9..a6adcbf 100644
--- a/spectro/conv.h
+++ b/spectro/conv.h
@@ -32,7 +32,7 @@
# include <io.h>
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined(UNIX)
# include <unistd.h>
# include <glob.h>
# include <pthread.h>
@@ -57,19 +57,8 @@ int poll_con_char(void);
/* (If not_interactive, does nothing) */
void empty_con_chars(void);
-/* Sleep for the given number of msec */
-void msec_sleep(unsigned int msec);
-
-/* Return the current time in msec since */
-/* the first invokation of msec_time() */
-unsigned int msec_time();
-
-/* Return the current time in usec */
-/* the first invokation of usec_time() */
-double usec_time();
-
/* Activate the system beeper after a delay */
-/* (Note frequancy and duration may not be honoured on all systems) */
+/* (Note frequency and duration may not be honoured on all systems) */
void msec_beep(int delay, int freq, int msec);
void normal_beep(); /* Emit a "normal" beep */
@@ -149,7 +138,7 @@ struct _athread {
#if defined (NT)
HANDLE th; /* Thread */
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined(UNIX)
pthread_t thid; /* Thread ID */
#endif
int finished; /* Set when the thread returned */
@@ -197,7 +186,7 @@ struct _kkill_nproc_ctx {
void (*del)(struct _kkill_nproc_ctx *p);
}; typedef struct _kkill_nproc_ctx kkill_nproc_ctx;
-#if defined(__APPLE__) || defined(NT)
+#if defined(UNIX_APPLE) || defined(NT)
/* Kill a list of named processes. NULL for last */
/* return < 0 if this fails. */
@@ -209,65 +198,10 @@ int kill_nprocess(char **pname, a1log *log);
/* Call ctx->del() when done */
kkill_nproc_ctx *kkill_nprocess(char **pname, a1log *log);
-#endif /* __APPLE__ || NT */
+#endif /* UNIX_APPLE || NT */
#include "xdg_bds.h"
-/* - - - - - - - - - - - - - - - - - - -- */
-/* A very small subset of icclib */
-#ifdef SALONEINSTLIB
-
-typedef struct {
- double X;
- double Y;
- double Z;
-} sa_XYZNumber;
-
-typedef enum {
- sa_SigXYZData = 0x58595A20L, /* 'XYZ ' */
- sa_SigLabData = 0x4C616220L /* 'Lab ' */
-} sa_ColorSpaceSignature;
-
-extern sa_XYZNumber sa_D50;
-extern sa_XYZNumber sa_D65;
-void sa_SetUnity3x3(double mat[3][3]);
-void sa_Cpy3x3(double out[3][3], double mat[3][3]);
-void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]);
-void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
-int sa_Inverse3x3(double out[3][3], double in[3][3]);
-void sa_Transpose3x3(double out[3][3], double in[3][3]);
-void sa_Scale3(double out[3], double in[3], double rat);
-double sa_LabDE(double *in0, double *in1);
-
-
-#define icmXYZNumber sa_XYZNumber
-#define icColorSpaceSignature sa_ColorSpaceSignature
-#define icSigXYZData sa_SigXYZData
-#define icSigLabData sa_SigLabData
-#define icmD50 sa_D50
-#define icmD65 sa_D65
-#define icmSetUnity3x3 sa_SetUnity3x3
-#define icmCpy3x3 sa_Cpy3x3
-#define icmMulBy3x3 sa_MulBy3x3
-#define icmMul3x3_2 sa_Mul3x3_2
-#define icmInverse3x3 sa_Inverse3x3
-#define icmTranspose3x3 sa_Transpose3x3
-#define icmScale3 sa_Scale3
-#define icmClamp3 sa_Clamp3
-#define icmLabDE sa_LabDE
-#define icmXYZ2Lab sa_XYZ2Lab
-
-/* A subset of numlib */
-
-int sa_lu_psinvert(double **out, double **in, int m, int n);
-
-#define lu_psinvert sa_lu_psinvert
-
-#endif /* SALONEINSTLIB */
-
-/* - - - - - - - - - - - - - - - - - - -- */
-
-
#ifdef __cplusplus
}
#endif
diff --git a/spectro/cubecal.h b/spectro/cubecal.h
index 60f7380..93f1ada 100644
--- a/spectro/cubecal.h
+++ b/spectro/cubecal.h
@@ -1,6 +1,7 @@
/*
* Calibration Table for SwatchMate Cube
+ * This is #included in smcube.c
*
* Copyright 2015 Graeme W. Gill
* All rights reserved
diff --git a/spectro/dev.h b/spectro/dev.h
new file mode 100644
index 0000000..0b62de3
--- /dev/null
+++ b/spectro/dev.h
@@ -0,0 +1,41 @@
+
+#ifndef DEV_H
+
+/*
+ * Abstract base class for all devices handled here.
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/8/2016
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+#include "icoms.h" /* libinst Includes this functionality */
+#include "conv.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Device base object. */
+#define DEV_OBJ_BASE \
+ a1log *log; /* Pointer to debug & error logging class */ \
+ icoms *icom; /* Device coms object */ \
+ instType itype; /* Device type determined by driver */ \
+
+/* The base object type */
+struct _dev {
+ DEV_OBJ_BASE
+ }; typedef struct _dev dev;
+
+#define DEV_H
+#endif /* DEV_H */
diff --git a/spectro/dispcal.c b/spectro/dispcal.c
index 97337cd..65e2f10 100644
--- a/spectro/dispcal.c
+++ b/spectro/dispcal.c
@@ -62,8 +62,13 @@
Change white point gamut clipping to be a measurement
search rather than computing from primary XYZ ?
- Add bell at end of calibration ?
+ Handling of white and black device clipping is not so good.
+ White clipping isn't characterized very well due to sparse sampling,
+ and moncurve tends to smooth over the clip inflection point,
+ making it innacurate. This particularly hurts the black point
+ accuracy, leading to raised or crushed blacks.
+ Add bell at end of calibration ?
Add option to plot graph of native and calibrated RGB ?
@@ -1012,7 +1017,7 @@ static void init_csamp(csamp *p, calx *x, int doupdate, int verify, int psrand,
p->_no = p->no = no;
- if ((p->s = (csp *)malloc(p->_no * sizeof(csp))) == NULL)
+ if ((p->s = (csp *)calloc(p->_no, sizeof(csp))) == NULL)
error("csamp malloc failed");
/* Compute v and txyz */
@@ -1715,7 +1720,7 @@ int main(int argc, char *argv[]) {
set_exe_path(argv[0]); /* Set global exe_path and error_program */
check_if_not_interactive();
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
{
SInt32 MacMajVers, MacMinVers, MacBFVers;
@@ -1939,7 +1944,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Paramater expected following -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -2572,7 +2577,7 @@ int main(int argc, char *argv[]) {
#ifdef MEAS_RES
if (doreport == 1) {
if (sigbits == 0) {
- warning("Unable to determine Video LUT entry bit depth");
+ warning("Unable to determine effective Video LUT entry bit depth");
} else {
printf("Effective Video LUT entry depth seems to be %d bits\n",sigbits);
}
@@ -3701,8 +3706,9 @@ int main(int argc, char *argv[]) {
else
printf(" Current Brightness = %.2f\n", tcols[2].XYZ[1]);
- printf(" Target 50%% Level = %.3f, Current = %.3f, error = % .1f%%\n",
+ printf(" Target 50%% Level = %.3f, Current = %.3f (Aprox. Gamma %.2f), error = % .1f%%\n",
tarh, tcols[1].XYZ[1],
+ mgamma,
100.0 * (tcols[1].XYZ[1] - tarh)/tarw);
printf(" Target Near Black = %.4f, Current = %.4f, error = % .1f%%\n",
@@ -4354,7 +4360,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
80.0, /* Display is 80 cd/m^2 */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
break;
case gt_Rec709:
@@ -4365,7 +4371,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
1000.0/3.1415, /* Luminance of white in the Image field (cd/m^2) */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
break;
default:
@@ -4378,7 +4384,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
x.twh[1], /* Target white level (cd/m^2) */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
/* Compute the normalisation values */
x.svc->XYZ_to_cam(x.svc, Jab, x.nwh); /* Relative white point */
@@ -4532,7 +4538,10 @@ int main(int argc, char *argv[]) {
}
#endif
- dr->reset_targ_w(dr); /* Reset white drift target at start of main cal. */
+ /* If native white and white drift compensation enabled, */
+ /* reset white drift target at start of main cal. */
+ if (x.nat && asgrey.s[0].v == 1.0 && wdrift)
+ dr->reset_targ_w(dr);
/* Now we go into the main verify & refine loop */
for (it = (verify == 2) ? mxits : 0;
@@ -5485,6 +5494,29 @@ int main(int argc, char *argv[]) {
if ((wr_icco = new_icc()) == NULL)
error("Write: Creation of ICC object failed");
+ /* Set the header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass;
+ wh->colorSpace = icSigRgbData; /* Display is RGB */
+ wh->pcs = icSigXYZData; /* XYZ for matrix based profile */
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ wh->manufacturer = icmSigUnknownType;
+ wh->model = icmSigUnknownType;
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef UNIX_APPLE
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX_X11)
+ wh->platform = icmSig_nix;
+#endif
+ }
+
/* Lookup white and black points */
{
int j;
@@ -5561,9 +5593,9 @@ int main(int argc, char *argv[]) {
printf("RGB 1 through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
}
#endif
- /* Adapt matrix */
+ /* Chromatic Adaptation matrix */
icmAry2XYZ(swp, wp);
- wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, icmD50, swp, mat);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, NULL, mat, icmD50, swp);
#ifdef NEVER
{
double rgb[3], xyz[3], lab[3];
@@ -5603,9 +5635,9 @@ int main(int argc, char *argv[]) {
printf("RGB cal through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
}
#endif
- /* Adapt matrix */
+ /* Chromatic Adaptation matrix */
icmAry2XYZ(swp, wp);
- wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, icmD50, swp, mat);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, NULL, mat, icmD50, swp);
#ifdef NEVER
{
double rgb[3], xyz[3], lab[3];
@@ -5619,30 +5651,7 @@ int main(int argc, char *argv[]) {
}
}
- /* Add all the tags required */
-
- /* The header: */
- {
- icmHeader *wh = wr_icco->header;
-
- /* Values that must be set before writing */
- wh->deviceClass = icSigDisplayClass;
- wh->colorSpace = icSigRgbData; /* Display is RGB */
- wh->pcs = icSigXYZData; /* XYZ for matrix based profile */
- wh->renderingIntent = icRelativeColorimetric; /* For want of something */
-
- wh->manufacturer = icmSigUnknownType;
- wh->model = icmSigUnknownType;
-#ifdef NT
- wh->platform = icSigMicrosoft;
-#endif
-#ifdef __APPLE__
- wh->platform = icSigMacintosh;
-#endif
-#if defined(UNIX_X11)
- wh->platform = icmSig_nix;
-#endif
- }
+ /* Add all the other tags required */
/* Profile Description Tag: */
{
@@ -5715,6 +5724,7 @@ int main(int argc, char *argv[]) {
wr_icco, icSigLuminanceTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ /* (Only Y is used according to the ICC spec.) */
wo->size = 1;
wo->allocate((icmBase *)wo); /* Allocate space */
wo->data[0].X = 0.0;
diff --git a/spectro/dispread.c b/spectro/dispread.c
index 8a78fcc..4c96b76 100644
--- a/spectro/dispread.c
+++ b/spectro/dispread.c
@@ -271,7 +271,7 @@ int main(int argc, char *argv[]) {
/* 0X = use current color management cLut (MadVR) */
/* 1X = disable color management cLUT (MadVR) */
double cal[3][MAX_CAL_ENT]; /* Display calibration */
- int ncal = 256; /* number of cal entries used */
+ int ncal = 256; /* Default number of cal entries used */
cgats *icg; /* input cgats structure */
cgats *ocg; /* output cgats structure */
time_t clk = time(0);
@@ -572,7 +572,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Parameter expected after -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -855,8 +855,9 @@ int main(int argc, char *argv[]) {
if ((ncal = ccg->t[0].nsets) <= 0)
error ("No data in set of file '%s'",calname);
- if (ncal != 256)
- error ("Expect 256 data sets in file '%s'",calname);
+ if (ncal < 2 || ncal > MAX_CAL_ENT)
+ error("Data set size %d is out of range for '%s'",ncal,calname);
+
if (ncal > MAX_CAL_ENT)
error ("Cant handle %d data sets in file '%s', max is %d",ncal,calname,MAX_CAL_ENT);
diff --git a/spectro/dispsup.c b/spectro/dispsup.c
index 57a598e..281912d 100644
--- a/spectro/dispsup.c
+++ b/spectro/dispsup.c
@@ -281,18 +281,28 @@ a1log *log /* Verb, debug & error log */
itype = p->get_itype(p); /* Actual type */
p->capabilities(p, &cap, &cap2, &cap3);
- if (tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ if (tele && p->check_mode(p, inst_mode_emis_tele) != inst_ok) {
printf("Want telephoto measurement capability but instrument doesn't support it\n");
printf("so falling back to emissive spot mode.\n");
tele = 0;
}
- if (!tele && !IMODETST(cap, inst_mode_emis_spot)) {
+ if (!tele && p->check_mode(p, inst_mode_emis_spot) != inst_ok) {
printf("Want emissive spot measurement capability but instrument doesn't support it\n");
printf("so switching to telephoto spot mode.\n");
tele = 1;
}
+ if (( tele && p->check_mode(p, inst_mode_emis_tele) != inst_ok)
+ || (!tele && p->check_mode(p, inst_mode_emis_spot) != inst_ok)) {
+ printf("Need %s emissive measurement capability,\n", tele ? "telephoto" : "spot");
+ printf("but instrument doesn't support it\n");
+ a1logd(p->log,1,"Need %s emissive measurement capability but device doesn't support it,\n",
+ tele ? "telephoto" : "spot");
+ p->del(p);
+ return -1;
+ }
+
/* Set to emission mode to read a display */
if (tele)
mode = inst_mode_emis_tele;
@@ -434,6 +444,7 @@ static int disprd_read_imp(
ipatch val; /* Return value */
int ch; /* Character */
int cal_type;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
inst2_capability cap2;
@@ -521,7 +532,7 @@ static int disprd_read_imp(
return 3;
}
/* Do calibrate, but ignore return code. Press on regardless. */
- if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, &idtype, id)) != inst_ok) {
a1logd(p->log,1,"warning, frequency calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
}
@@ -538,7 +549,7 @@ static int disprd_read_imp(
return 3;
}
/* Do calibrate, but ignore return code. Press on regardless. */
- if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, &idtype, id)) != inst_ok) {
a1logd(p->log,1,"warning, display integration calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
}
@@ -681,7 +692,8 @@ static int disprd_read_imp(
return 1;
}
printf("\n");
- if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ if ((p->it->icom->port_type(p->it->icom) & icomt_serial)
+ && !(p->it->icom->port_attr(p->it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = p->it->last_scomerr(p->it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1198,7 +1210,7 @@ int disprd_ambient(
p->it->capabilities(p->it, &cap, &cap2, &cap3);
}
- if (!IMODETST(cap, inst_mode_emis_ambient)) {
+ if (p->it->check_mode(p->it, inst_mode_emis_ambient) != inst_ok) {
printf("Need ambient measurement capability,\n");
printf("but instrument doesn't support it\n");
return 8;
@@ -1297,7 +1309,7 @@ int disprd_ambient(
setup_display_calibrate, &dwi, 0);
setup_display_calibrate(p->it,inst_calc_none, &dwi);
if (rv != inst_ok) { /* Abort or fatal error */
- return 1;
+ return ((rv & inst_mask) == inst_user_abort) ? 1 : 2;
}
continue;
@@ -1336,7 +1348,8 @@ int disprd_ambient(
return 1;
}
printf("\n");
- if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ if ((p->it->icom->port_type(p->it->icom) & icomt_serial)
+ && !(p->it->icom->port_attr(p->it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = p->it->last_scomerr(p->it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -2146,21 +2159,21 @@ static int config_inst_displ(disprd *p) {
p->it->capabilities(p->it, &cap, &cap2, &cap3);
- if (p->tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ if (p->tele && p->it->check_mode(p->it, inst_mode_emis_tele) != inst_ok) {
printf("Want telephoto measurement capability but instrument doesn't support it\n");
printf("so falling back to spot mode.\n");
a1logd(p->log,1,"No telephoto mode so falling back to spot mode.\n");
p->tele = 0;
}
- if (!p->tele && !IMODETST(cap, inst_mode_emis_spot)) {
+ if (!p->tele && p->it->check_mode(p->it, inst_mode_emis_spot) != inst_ok) {
printf("Want emissive spot measurement capability but instrument doesn't support it\n");
printf("so switching to telephoto spot mode.\n");
p->tele = 1;
}
- if (( p->tele && !IMODETST(cap, inst_mode_emis_tele))
- || (!p->tele && !IMODETST(cap, inst_mode_emis_spot))) {
+ if (( p->tele && p->it->check_mode(p->it, inst_mode_emis_tele) != inst_ok)
+ || (!p->tele && p->it->check_mode(p->it, inst_mode_emis_spot) != inst_ok)) {
printf("Need %s emissive measurement capability,\n", p->tele ? "telephoto" : "spot");
printf("but instrument doesn't support it\n");
a1logd(p->log,1,"Need %s emissive measurement capability but device doesn't support it,\n",
@@ -2685,7 +2698,7 @@ a1log *log /* Verb, debug & error log */
printf("Calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
p->del(p);
- if (errc != NULL) *errc = 2;
+ if (errc != NULL) *errc = ((rv & inst_mask) == inst_user_abort) ? 1 : 2;
return NULL;
}
}
diff --git a/spectro/dispsup.h b/spectro/dispsup.h
index bca3070..07a66e2 100644
--- a/spectro/dispsup.h
+++ b/spectro/dispsup.h
@@ -91,9 +91,6 @@ typedef struct {
} col;
-/* Maximum number of entries to setup for calibration */
-#define MAX_CAL_ENT 4096
-
/* Display reading context */
struct _disprd {
diff --git a/spectro/disptechs.c b/spectro/disptechs.c
index 70e150f..bade777 100644
--- a/spectro/disptechs.c
+++ b/spectro/disptechs.c
@@ -22,14 +22,15 @@
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include "numsup.h"
#ifndef SALONEINSTLIB
#include "copyright.h"
#include "aconfig.h"
#include "icc.h"
#else
#include "sa_config.h"
+#include "sa_conv.h"
#endif /* !SALONEINSTLIB */
-#include "numsup.h"
#include "conv.h"
#include "disptechs.h"
diff --git a/spectro/dispwin.c b/spectro/dispwin.c
index fffbaee..368f707 100644
--- a/spectro/dispwin.c
+++ b/spectro/dispwin.c
@@ -31,6 +31,10 @@
* Should add dithering support to overcome 8 bit limitations of
* non-RAMDAC access or limited RAMDAC depth. (How do we easily
* determine the latter ??)
+ *
+ * For X11/XRANDR, should we check for and save/restore CscMatrix property ??
+ * - or should we assumed that the use intends to use this to manually calibrate the display ??
+ * See <http://us.download.nvidia.com/XFree86/Linux-x86/364.12/README/xrandrextension.html#CscMatrix>
*/
#include <stdio.h>
@@ -69,7 +73,7 @@
# endif
#endif
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/*
Note that the new ColorSync API is defined in
@@ -113,14 +117,14 @@ typedef float CGFloat;
#endif
#endif /* !NSINTEGER_DEFINED */
-#include <IOKit/Graphics/IOGraphicsLib.h>
+#include <IOKit/graphics/IOGraphicsLib.h>
#if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1060
/* This wasn't declared in 10.6, although it is needed */
CFUUIDRef CGDisplayCreateUUIDFromDisplayID (uint32_t displayID);
#endif /* < 10.6 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#define VERIFY_TOL (1.0/255.0)
#undef DISABLE_RANDR /* Disable XRandR code */
@@ -388,7 +392,7 @@ disppath **get_displays() {
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Note :- some recent releases of OS X have a feature which */
/* automatically adjusts the screen brigtness with ambient level. */
/* We may have to find a way of disabling this during calibration and profiling. */
@@ -548,7 +552,7 @@ disppath **get_displays() {
}
free(dids);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
int i, j, k;
@@ -636,8 +640,8 @@ disppath **get_displays() {
/* Look at all the screens outputs */
for (jj = j = 0; j < scrnres->noutput; j++) {
- XRROutputInfo *outi;
- XRRCrtcInfo *crtci;
+ XRROutputInfo *outi = NULL;
+ XRRCrtcInfo *crtci = NULL;
if ((outi = XRRGetOutputInfo(mydisplay, scrnres, scrnres->outputs[j])) == NULL) {
debugrr("XRRGetOutputInfo failed\n");
@@ -649,12 +653,13 @@ disppath **get_displays() {
if (outi->connection == RR_Disconnected ||
outi->crtc == None) {
+ XRRFreeOutputInfo(outi);
continue;
}
/* Check that the VideoLUT's are accessible */
{
- XRRCrtcGamma *crtcgam;
+ XRRCrtcGamma *crtcgam = NULL;
debugrr("Checking XRandR 1.2 VideoLUT access\n");
if ((crtcgam = XRRGetCrtcGamma(mydisplay, outi->crtc)) == NULL
@@ -666,8 +671,11 @@ disppath **get_displays() {
disps = NULL;
j = scrnres->noutput;
i = dcount;
+ XRRFreeOutputInfo(outi);
continue; /* Abort XRandR 1.2 */
}
+ if (crtcgam != NULL)
+ XRRFreeGamma(crtcgam);
}
#ifdef NEVER
{
@@ -692,6 +700,7 @@ disppath **get_displays() {
if ((disps = (disppath **)calloc(sizeof(disppath *), 1 + 1)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
return NULL;
@@ -701,6 +710,7 @@ disppath **get_displays() {
sizeof(disppath *) * (ndisps + 2))) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
return NULL;
@@ -711,6 +721,7 @@ disppath **get_displays() {
if ((disps[ndisps] = calloc(sizeof(disppath),1)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -741,6 +752,7 @@ disppath **get_displays() {
if ((disps[ndisps]->description = strdup(desc2)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -756,6 +768,7 @@ disppath **get_displays() {
if ((disps[ndisps]->name = strdup(dnbuf)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -809,6 +822,7 @@ disppath **get_displays() {
if ((disps[ndisps]->edid = malloc(sizeof(unsigned char) * ret_len)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -833,7 +847,6 @@ disppath **get_displays() {
}
XRRFreeOutputInfo(outi);
}
-
XRRFreeScreenResources(scrnres);
}
XSetErrorHandler(NULL);
@@ -1136,15 +1149,16 @@ void free_a_disppath(disppath *path) {
/* ----------------------------------------------- */
-/* For VideoLUT/RAMDAC use, we assume that the number of entries in the RAMDAC */
-/* meshes perfectly with the display raster depth, so that we can */
-/* figure out how to apportion device values. We fail if they don't */
-/* seem to mesh. */
+/* For VideoLUT/RAMDAC use, we assume that the frame buffer */
+/* may map through some intermediate hardware or lookup */
+/* into a RAMDAC index. */
/* !!! Would be nice to add an error message return to dispwin and */
/* !!! pass errors back to it so that the detail can be reported */
/* !!! to the user. */
+static void dispwin_dump_ramdac(FILE *fp, ramdac *r);
+
/* Get RAMDAC values. ->del() when finished. */
/* Return NULL if not possible */
static ramdac *dispwin_get_ramdac(dispwin *p) {
@@ -1168,9 +1182,11 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
debugr("dispwin_get_ramdac failed on malloc()\n");
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
- r->clone = dispwin_clone_ramdac;
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+ r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -1186,9 +1202,9 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
}
/* GetDeviceGammaRamp() is hard coded for 3 x 256 entries (Quantize) */
- if (r->nent != 256) {
+ if (256 != r->nent) {
free(r);
- debugr2((errout,"GetDeviceGammaRamp() is hard coded for nent == 256, and we've got nent = %d!\n",r->nent));
+ debugr2((errout,"GetDeviceGammaRamp number of entries %d inconsistent with expected value %d\n",256,p->nent));
return NULL;
}
@@ -1204,7 +1220,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
unsigned int nent;
CGGammaValue vals[3][16385];
@@ -1220,8 +1236,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"CGGetDisplayTransferByTable number of entries %d mismatches screen depth %d\n",nent,p->pdepth));
+ if (nent != p->nent) {
+ debugr2((errout,"CGGetDisplayTransferByTable number of entries %u inconsistent with previous value %d\n",nent,p->nent));
return NULL;
}
@@ -1231,8 +1247,10 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -1252,7 +1270,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
r->v[j][i] = vals[j][i];
}
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
unsigned short vals[3][16384];
@@ -1275,13 +1293,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
nent = crtcgam->size;
- if (nent > 16384) {
- debugr("XRRGetCrtcGammaSize has more entries than we can handle\n");
- return NULL;
- }
-
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"XRRGetCrtcGammaSize number of entries %d mismatches screen depth %d bits\n",nent,(1 << p->pdepth)));
+ if (nent != p->nent) {
+ debugr2((errout,"XRRGetCrtcGammaSize number of entries %d inconsistent with previous value\n",nent,p->nent));
return NULL;
}
@@ -1331,8 +1344,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- if (nent > 16384) {
- debugr("XF86VidModeGetGammaRampSize has more entries than we can handle\n");
+ if (nent != p->nent) {
+ debugr2((errout,"XF86VidModeGetGammaRampSize number of entries %d inconsistent with previous value\n",nent,p->nent));
return NULL;
}
@@ -1340,11 +1353,6 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
debugr("XF86VidModeGetGammaRamp failed\n");
return NULL;
}
-
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"CGGetDisplayTransferByTable number of entries %d mismatches screen depth %d bits\n",nent,(1 << p->pdepth)));
- return NULL;
- }
}
/* Allocate a ramdac */
@@ -1353,9 +1361,11 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
- r->clone = dispwin_clone_ramdac;
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+ r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
for (j = 0; j < 3; j++) {
@@ -1379,7 +1389,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return r;
}
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Various support functions */
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1060
@@ -1643,7 +1653,7 @@ static void *cur_colorsync_ref(dispwin *p) {
return cspr;
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* Set the RAMDAC values. */
/* Return nz if not possible */
@@ -1666,6 +1676,7 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
for (j = 0; j < 3; j++) {
for (i = 0; i < r->nent; i++) {
double vv = r->v[j][i];
+
if (vv < 0.0)
vv = 0.0;
else if (vv > 1.0)
@@ -1676,12 +1687,15 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
if (SetDeviceGammaRamp(p->hdc, vals) == 0) {
debugr2((errout,"dispwin_set_ramdac failed on SetDeviceGammaRamp() with error %d\n",GetLastError()));
+#ifdef NEVER
+ dispwin_dump_ramdac(stderr, r);
+#endif
return 1;
}
GdiFlush();
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
{ /* Transient first */
CGGammaValue vals[3][16384];
@@ -2115,7 +2129,7 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
}
#endif /* < 10.6 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
unsigned short vals[3][16384];
@@ -2214,6 +2228,24 @@ ramdac *dispwin_clone_ramdac(ramdac *r) {
return nr;
}
+/* Debug dump ramdac */
+static void dispwin_dump_ramdac(FILE *fp, ramdac *r) {
+ int i, j;
+
+ fprintf(fp,"Ramdac fdepth %d, rdepth %d, ndepth %d, nent %d\n",
+ r->fdepth, r->rdepth, r->ndepth, r->nent);
+
+ for (i = 0; i < r->nent; i++) {
+ int note = 0;
+ for (j = 0; j < 3; j++) {
+ if (r->v[j][i] < 0.0 || r->v[j][i] > 1.0
+ || (i > 0 && r->v[j][i] < r->v[j][i-1]))
+ note = 1;
+ }
+ fprintf(fp," %d: %f %f %f%s\n",i, r->v[0][i], r->v[1][i], r->v[2][i], note ? " #" : "");
+ }
+}
+
/* Set the ramdac values to linear */
void dispwin_setlin_ramdac(ramdac *r) {
int i, j;
@@ -2522,7 +2554,7 @@ int dispwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
}
#endif /* OS X || Linux */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
@@ -2685,7 +2717,7 @@ int dispwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
return 0;
}
#endif /* 10.6 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
{
@@ -2862,7 +2894,7 @@ int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
}
}
#endif /* OS X || Linux */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
{
char *dpath; /* Un-install file path */
@@ -2980,7 +3012,7 @@ int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
return 0;
}
#endif /* 10.6 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
{
@@ -3043,7 +3075,7 @@ icmFile *dispwin_get_profile(dispwin *p, char *name, int mxlen) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
char *dpath; /* Read file path */
@@ -3187,7 +3219,7 @@ icmFile *dispwin_get_profile(dispwin *p, char *name, int mxlen) {
return rd_fp;
}
#endif /* 10.5 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
/* Try and get the currently installed profile from ucmm */
@@ -3454,7 +3486,7 @@ static void dispwin_uninstall_signal_handlers(dispwin *p) {
/* ----------------------------------------------- */
/* Test patch window specific declarations */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
@class DWWin;
@class DWView;
@@ -3467,6 +3499,8 @@ typedef struct {
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
NSColorSpace *nscs; /* Colorspace from profile */
#endif
+ NSRect rect; /* Size and position to create window */
+ int err; /* Error code */
} osx_cntx_t;
// - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -3545,6 +3579,15 @@ unsigned char emptyCursor[43] = {
@end
+/* Function called back by main thread to trigger a drawRect */
+
+static void doSetNeedsDisplay(void *cntx) {
+ osx_cntx_t *cx = (osx_cntx_t *)cntx;
+
+ [cx->view setNeedsDisplay: YES ];
+
+ cx->err = 0;
+}
// - - - - - - - - - - - - - - - - - - - - - - - - -
@interface DWWin : NSWindow {
@@ -3582,7 +3625,9 @@ unsigned char emptyCursor[43] = {
@end
/* Create our window */
-static void create_my_win(NSRect rect, osx_cntx_t *cx) {
+/* We run this on the main thread using a custom message */
+static void create_my_win(void *cntx) {
+ osx_cntx_t *cx = (osx_cntx_t *)cntx;
dispwin *p = cx->p;
SInt32 MacMajVers, MacMinVers, MacBFVers;
void *cspr = NULL; /* ColorSync profile ref. */
@@ -3607,7 +3652,7 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
}
/* Create Window */
- cx->window = [[DWWin alloc] initWithContentRect: rect
+ cx->window = [[DWWin alloc] initWithContentRect: cx->rect
styleMask: NSBorderlessWindowMask
backing: NSBackingStoreBuffered
defer: YES
@@ -3626,7 +3671,8 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
/* Moves the window to the front of the screen list within its level, */
/* and show the window (i.e. make it "key") */
- /* Trigger crash on OS X 10.11 El Capitan ? */
+ /* Trigger warning on OS X 10.11 El Capitan ? */
+ /* (Doesn't happen using 1.6.3 which ran everything in the main thread.) */
[cx->window makeKeyAndOrderFront: nil];
/* Use a null color transform to ensure device values */
@@ -3686,9 +3732,10 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
}
#endif
+ cx->err = 0;
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* ----------------------------------------------- */
@@ -3726,22 +3773,24 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
//if (p->out_tvenc) {
//printf(" %d: 8 bit tv = s_rgb %f %f %f\n",j, p->s_rgb[0], p->s_rgb[1], p->s_rgb[2]);
-//printf(" %d: %d bitraster r_rgb %f %f %f\n",j, p->pdepth,p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
+//printf(" %d: %d bitraster r_rgb %f %f %f\n",j, p->edepth,p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
//}
/* Use ramdac for high precision native output. */
/* The ramdac is used to hold the lsb that the frame buffer */
/* doesn't hold. */
if ((p->native & 1) == 1) {
- double prange = p->r->nent - 1.0;
+ double frange = (1 << p->fdepth) - 1.0;
+ double rrange = (1 << p->rdepth) - 1.0;
+ double nrange = p->nent - 1.0;
p->r->setlin(p->r); /* In case something else altered this */
@@ -3756,9 +3805,66 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
if (p->out_tvenc && p->edepth > 8)
vv = (vv * 255 * (1 << (p->edepth - 8)))/((1 << p->edepth) - 1.0);
- tt = (int)(vv * prange + 0.5);
- p->r_rgb[j] = (double)tt/prange; /* RAMDAC output Quantized value */
+ /* Determine the ramdac index that the quantized frame buffer */
+ /* value will make use of */
+#ifdef NT
+ /* Assume all depths match, or linear mapping between them */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = (int)(tt/frange * rrange + 0.5); /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+#ifdef UNIX_APPLE
+ /* We assume linear mapping with perfect rounding between rdepth and ndepth */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = (int)(tt/frange * rrange + 0.5); /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+#if defined(UNIX_X11)
+ /* We assume linear mapping with perfect rounding between rdepth and ndepth */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = p->rmap[j][tt]; /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+
+#ifdef NEVER // Just set entry we think will get hit
p->r->v[j][tt] = vv;
+#else
+
+ /* Set the three entries around target and create ramp either side,
+ to allow for some video cards not having a precise
+ definition of what value translates to what frame buffer value. */
+ {
+ int i;
+ double maxv = 1.0;
+
+ if (p->out_tvenc && p->edepth > 8)
+ maxv = (maxv * 255 * (1 << (p->edepth - 8)))/((1 << p->edepth) - 1.0);
+
+ if ((tt-1) == 0) {
+ p->r->v[j][tt-1] = vv;
+ } else {
+ for (i = 0; i <= (tt-1); i++)
+ p->r->v[j][i] = vv * i/(tt-1);
+ }
+
+ p->r->v[j][tt] = vv;
+
+ if ((tt+1) == (p->r->nent-1)) {
+ p->r->v[j][tt+1] = vv;
+ } else {
+ for (i = tt+1; i < p->r->nent; i++)
+ p->r->v[j][i] = vv + (maxv - vv) * (i - (tt+1))/((p->r->nent-1) - (tt+1));
+ }
+
+#ifdef NEVER
+ for (i = 0; i < p->r->nent; i++)
+ printf("~1 %d, %d -> %f\n",j,i,p->r->v[j][i]);
+#endif
+ }
+#endif
//printf(" cell[%d] = r_rgb %f, cell val %f\n",tt, p->r_rgb[j], vv);
}
@@ -3796,7 +3902,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
#endif
p->colupd++;
-//printf("~1 set color %f %f %f\n", p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
/* Trigger a WM_PAINT */
if (!InvalidateRect(p->hwnd, NULL, FALSE)) {
@@ -3810,13 +3918,14 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
while (p->colupd != p->colupde && p->cberror == 0) {
msec_sleep(10);
}
-//printf("~1 paint done\n");
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
}
#endif /* NT */
/* - - - - - - - - - - - - - - */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if (p->winclose) {
return 2;
@@ -3840,11 +3949,7 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
if ((stat = GetCurrentProcess(&cpsn)) != noErr) {
debugr2((errout,"GetCurrentProcess returned error %d\n",stat));
} else {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
- if ((stat = TransformProcessType(&cpsn, kProcessTransformToForegroundApplication)) != noErr) {
- debugr2((errout,"TransformProcessType returned error %d\n",stat));
- }
-#endif /* OS X 10.3 */
+ // [window makeGetAndOrderFront:] ??
if ((stat = SetFrontProcess(&cpsn)) != noErr) {
debugr2((errout,"SetFrontProcess returned error %d\n",stat));
}
@@ -3852,40 +3957,56 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
p->btf = 1;
}
- /* Trigger an update that fills window with r_rgb[] */
- [((osx_cntx_t *)(p->osx_cntx))->view setNeedsDisplay: YES ];
+ /* Prepare to wait for events */
+ ui_aboutToWait();
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
+
+// [((osx_cntx_t *)(p->osx_cntx))->view setNeedsDisplay: YES ];
+
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)p->osx_cntx, doSetNeedsDisplay);
+
+ /* Wait for any events generated by paint to complete */
+ ui_waitForEvents();
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
if (tpool != nil)
[tpool release];
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* - - - - - - - - - - - - - - */
#if defined(UNIX_X11)
{
- Colormap mycmap;
- XColor col;
- int vali[3];
+ unsigned int vali[3];
+ unsigned long fbval;
/* Indicate that we've got activity to the X11 Screensaver */
XResetScreenSaver(p->mydisplay);
- /* Quantize to 16 bit color */
+ /* Quantize to frame buffer component depth */
for (j = 0; j < 3; j++)
- vali[j] = (int)(65535.0 * p->r_rgb[j] + 0.5);
+ vali[j] = (int)(((1 << p->fdepth)-1.0) * p->r_rgb[j] + 0.5);
- mycmap = DefaultColormap(p->mydisplay, p->myscreen);
- col.red = vali[0];
- col.green = vali[1];
- col.blue = vali[2];
- XAllocColor(p->mydisplay, mycmap, &col);
- XSetForeground(p->mydisplay, p->mygc, col.pixel);
+ /* Compose frame buffer pixel value */
+ fbval = (vali[0] << p->shift[0])
+ | (vali[1] << p->shift[1])
+ | (vali[2] << p->shift[2]);
+ XSetForeground(p->mydisplay, p->mygc, fbval);
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
XFillRectangle(p->mydisplay, p->mywindow, p->mygc,
p->tx, p->ty, p->tw, p->th);
XSync(p->mydisplay, False); /* Make sure it happens */
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
}
#endif /* UNXI X11 */
@@ -4029,6 +4150,7 @@ dispwin *p
if (p->mth != NULL) { /* Message thread */
p->mth->del(p->mth);
}
+ p->hwnd = NULL;
}
if (p->hdc != NULL)
@@ -4038,7 +4160,7 @@ dispwin *p
/* -------------------------------------------------- */
/* -------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if (p->nowin == 0) { /* We have a window up */
restore_display(p);
if (p->osx_cntx != NULL) { /* And we've allocated a context */
@@ -4061,7 +4183,7 @@ dispwin *p
// ~~
// CGDisplayShowCursor(p->ddid);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
@@ -4071,22 +4193,43 @@ dispwin *p
if (p->mydisplay != NULL) {
if (p->nowin == 0) { /* We have a window up */
- XFreeGC(p->mydisplay, p->mygc);
- XDestroyWindow(p->mydisplay, p->mywindow);
+ if (p->mygc != 0)
+ XFreeGC(p->mydisplay, p->mygc);
+ if (p->mywindow != 0)
+ XDestroyWindow(p->mydisplay, p->mywindow);
}
XCloseDisplay(p->mydisplay);
+ p->mydisplay = NULL;
+ }
+ {
+ int j;
+ for (j = 0; j < 3; j++) {
+ if (p->rmap[j] != NULL) {
+ free(p->rmap[j]);
+ p->rmap[j] = NULL;
+ }
+ }
}
debugr("finished\n");
+ if (p->edid != NULL)
+ free(p->edid);
+
#endif /* UNXI X11 */
/* -------------------------------------------------- */
- if (p->name != NULL)
+ if (p->name != NULL) {
free(p->name);
- if (p->description != NULL)
+ p->name = NULL;
+ }
+ if (p->description != NULL) {
free(p->description);
- if (p->callout != NULL)
+ p->description = NULL;
+ }
+ if (p->callout != NULL) {
free(p->callout);
+ p->callout = NULL;
+ }
free(p);
}
@@ -4234,6 +4377,10 @@ static LRESULT CALLBACK MainWndProc(
#endif /* NT */
+#ifdef UNIX_APPLE
+
+#endif /* UNIX_APPLE */
+
#if defined(UNIX_X11)
/* None */
#endif /* UNXI X11 */
@@ -4241,7 +4388,8 @@ static LRESULT CALLBACK MainWndProc(
/* ----------------------------------------------- */
#ifdef NT
-/* Thread to handle message processing, so that there is no delay */
+/* Thread to create the window if it doesn'r exist, */
+/* and handle message processing, so that there is no delay */
/* when the main thread is doing other things. */
int win_message_thread(void *pp) {
dispwin *p = (dispwin *)pp;
@@ -4333,7 +4481,7 @@ int win_message_thread(void *pp) {
}
if (UnregisterClass(p->AppName, NULL) == 0) {
- warning("UnregisterClass failed, lasterr = %d\n",GetLastError());
+ warning("UnregisterClass failed, lasterr = %d",GetLastError());
}
p->hwnd = NULL; /* Signal it's been deleted */
@@ -4400,7 +4548,10 @@ int ddebug /* >0 to print debug statements to stderr */
) {
dispwin *p = NULL;
- debug("new_dispwin called\n");
+#ifndef DEBUG
+ if (ddebug)
+#endif
+ fprintf(errout, "new_dispwin called\n");
#if defined(UNIX_X11) && defined(USE_UCMM)
dispwin_checkfor_colord(); /* Make colord functions available */
@@ -4444,6 +4595,8 @@ int ddebug /* >0 to print debug statements to stderr */
/* Basic object is initialised, so create a window */
+ ui_UsingGUI();
+
/* -------------------------------------------------- */
#ifdef NT
{
@@ -4511,7 +4664,7 @@ int ddebug /* >0 to print debug statements to stderr */
p->wh = he;
/* It's a bit difficult to know how windows defines the display */
- /* depth. Microsofts doco is fuzzy, and typical values */
+ /* depth. Microsoft's doco is fuzzy, and typical values */
/* for BITSPIXEL and PLANES are confusing (What does "32" and "1" */
/* mean ?) NUMCOLORS seems to be -1 on my box, and perhaps */
/* is only applicable to up to 256 paletized colors. The doco */
@@ -4530,12 +4683,17 @@ int ddebug /* >0 to print debug statements to stderr */
}
bpp = GetDeviceCaps(p->hdc, COLORRES);
if (bpp <= 0)
- p->pdepth = 8; /* Assume this is so */
+ p->fdepth = 8; /* Assume this is so */
else
- p->pdepth = bpp/3;
+ p->fdepth = bpp/3;
+ p->rdepth = p->fdepth; /* Assume this is so */
+ p->ndepth = 8; /* Assume this is so */
+ p->nent = (1 << p->ndepth);
p->edepth = 16;
+ debugr2((errout,"new_dispwin: fdepth %d, rdepth %d, ndepth %d, edepth %d\n", p->fdepth,p->rdepth,p->ndepth,p->edepth));
+
if (nowin == 0) {
/* We use a thread to process the window messages, so that */
@@ -4549,6 +4707,9 @@ int ddebug /* >0 to print debug statements to stderr */
p->wi = wi;
p->he = he;
+ debugr2((errout,"new_dispwin about to create window\n"));
+
+ /* Create the window and then process events */
if ((p->mth = new_athread(win_message_thread, (void *)p)) == NULL) {
debugr2((errout, "new_dispwin: new_athread failed\n"));
dispwin_del(p);
@@ -4556,6 +4717,9 @@ int ddebug /* >0 to print debug statements to stderr */
}
/* Wait for thread to run */
+ /* (Hmm. This doesn't actually gurantee that our window has */
+ /* been created yet ? */
+ // ~~ should sync by sending a custom message and getting notified ? */
while (p->inited == 0) {
msec_sleep(20);
}
@@ -4565,6 +4729,8 @@ int ddebug /* >0 to print debug statements to stderr */
dispwin_del(p);
return NULL;
}
+
+ debugr2((errout,"new_dispwin window created\n"));
}
/* Install the signal handler to ensure cleanup */
@@ -4575,7 +4741,7 @@ int ddebug /* >0 to print debug statements to stderr */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if ((p->name = strdup(disp->name)) == NULL) {
debugr2((errout,"new_dispwin: Malloc failed\n"));
@@ -4584,31 +4750,13 @@ int ddebug /* >0 to print debug statements to stderr */
}
p->ddid = disp->ddid; /* Display we're working on */
- /* Hmm. Could we use CGDisplayGammaTableCapacity() instead ? */
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
CGDisplayModeRef dispmode;
CFStringRef pixenc;
- int cap = CGDisplayGammaTableCapacity(p->ddid);
int fbdepth = 0;
- debugr2((errout,"new_dispwin: CGDisplayGammaTableCapacity = %d\n",cap));
-
- /* Compute GammaTable depth */
- {
- for (p->pdepth = 1; p->pdepth < 17; p->pdepth++) {
- if ((1 << p->pdepth) == cap)
- break;
- }
- if (p->pdepth >= 17) {
- debugr2((errout,"new_dispwin: failed to extract depth from GammaTableCapacity %d\n",cap));
- dispwin_del(p);
- return NULL;
- }
- debugr2((errout,"new_dispwin: found pixel depth %d bits\n",p->pdepth));
- }
- /* Get frame buffer depth for sanity check, but don't actually make used of it */
-
+ /* Get frame buffer depth */
dispmode = CGDisplayCopyDisplayMode(p->ddid);
pixenc = CGDisplayModeCopyPixelEncoding(dispmode);
@@ -4625,6 +4773,9 @@ int ddebug /* >0 to print debug statements to stderr */
else if (CFStringCompare(pixenc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)
== kCFCompareEqualTo)
fbdepth = 5;
+ else
+ fbdepth = 8; /* Assume */
+
#ifndef DEBUG
if (p->ddebug)
#endif
@@ -4637,26 +4788,56 @@ int ddebug /* >0 to print debug statements to stderr */
CFRelease(pixenc);
CGDisplayModeRelease(dispmode);
- if (p->pdepth != fbdepth) {
- static int warned = 0;
- if (!warned) {
- warning("new_dispwin: frame buffer depth %d != GammaTable depth %d\n",fbdepth, p->pdepth);
- warned = 1;
+ p->fdepth = fbdepth;
+ p->rdepth = p->fdepth; /* We don't know of any HW between frame buffer and VideoLUT */
+
+ /* Get CGDisplayGammaTable size */
+ p->nent = CGDisplayGammaTableCapacity(p->ddid);
+
+ /* Compute GammaTable/VideoLUT/RAMDAC depth */
+ {
+ for (p->ndepth = 1; p->ndepth < 17; p->ndepth++) {
+ if ((1 << p->ndepth) >= p->nent)
+ break;
+ }
+ if (p->ndepth >= 17) {
+ debugr2((errout,"new_dispwin: failed to extract depth from GammaTableCapacity %d\n",p->nent));
+ dispwin_del(p);
+ return NULL;
+ }
+ debugr2((errout,"new_dispwin: found actual VideoLUT depth %d bits\n",p->ndepth));
+ }
+
+ if (p->rdepth > p->ndepth) {
+ debugr2((errout,"new_dispwin: Frame buffer depth %d > VideoLUT depth %d\n",p->rdepth, p->ndepth));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if (p->rdepth != p->ndepth) {
+ if (!p->warned) {
+ warning("new_dispwin: Frame buffer depth %d doesn't matcv VideoLUT %d",p->rdepth, p->ndepth);
+ p->warned = 1;
}
}
}
#else
- p->pdepth = CGDisplayBitsPerSample(p->ddid);
+ /* Life is simple */
+ p->fdepth = CGDisplayBitsPerSample(p->ddid);
+ p->rdepth = p->fdepth;
+ p->ndepth = p->rdepth;
+ p->nent = (1 << p->ndepth);
#endif
p->edepth = 16; /* By experiment it seems to be 16 bits too */
+ debugr2((errout,"new_dispwin: fdepth %d, rdepth %d, ndepth %d, edepth %d\n", p->fdepth,p->rdepth,p->ndepth,p->edepth));
+
if (nowin == 0) { /* Create a window */
osx_cntx_t *cx;
CGSize sz; /* Display size in mm */
int wi, he; /* Width and height in pixels */
int xo, yo; /* Window location */
- NSRect wrect;
debugr2((errout, "new_dispwin: About to open display '%s'\n",disp->name));
@@ -4716,22 +4897,33 @@ int ddebug /* >0 to print debug statements to stderr */
p->ww = wi;
p->wh = he;
- wrect.origin.x = xo;
- wrect.origin.y = yo;
- wrect.size.width = wi;
- wrect.size.height = he;
+ cx->rect.origin.x = xo;
+ cx->rect.origin.y = yo;
+ cx->rect.size.width = wi;
+ cx->rect.size.height = he;
+
+ debugr2((errout,"new_dispwin about to create window\n"));
+
+ /* Prepare to wait for events */
+ ui_aboutToWait();
- create_my_win(wrect, cx);
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)cx, create_my_win);
+
+ /* Wait for events generated by window creation to complete */
+ ui_waitForEvents();
if (tpool != nil)
[tpool release];
p->winclose = 0;
+
+ debugr2((errout,"new_dispwin window created\n"));
}
/* Install the signal handler to ensure cleanup */
dispwin_install_signal_handlers(p);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
@@ -4755,6 +4947,8 @@ int ddebug /* >0 to print debug statements to stderr */
Window rootwindow;
char *appname = "TestWin";
Visual *myvisual;
+ XVisualInfo template, *vinfo;
+ int nitems = 0;
XSetWindowAttributes myattr;
XEvent myevent;
XTextProperty myappname;
@@ -4817,15 +5011,184 @@ int ddebug /* >0 to print debug statements to stderr */
memmove(p->edid, disp->edid, p->edid_len);
}
- //p->pdepth = DefaultDepth(p->mydisplay, p->myscreen)/3;
+#ifdef NEVER
+#pragma message("######### dispwin.c DirectColor test is defined! ########")
+
+ /* To test DirectColor Visual when it's not the default:*/
+ debugr2((errout,"new_dispwin: Testing DirectColor Visual\n"));
+
+ // test DirectColor visual
+ template.class = DirectColor;
+ if ((vinfo = XGetVisualInfo(p->mydisplay, VisualClassMask, &template, &nitems)) == NULL) {
+ debugr2((errout,"new_dispwin: Unable to find a DirectColor Visual\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ myvisual = vinfo->visual;
- // Hmm. Should we explicitly get the root window visual,
- // since our test window inherits it from root ?
+#else
myvisual = DefaultVisual(p->mydisplay, p->myscreen);
- p->pdepth = myvisual->bits_per_rgb;
- p->edepth = 16;
+#endif
+
+ /* Expect TrueColor (fixed/no map) or DirectColor (read/write map) Visual - */
+ /* anything else is not suitable for high quality color. */
+
+ /* Get the VisualInfo */
+ template.visualid = myvisual->visualid;
+ vinfo = XGetVisualInfo(p->mydisplay, VisualIDMask, &template, &nitems);
+
+ if (nitems < 1) {
+ debugr2((errout,"new_dispwin: Failed to get XGetVisualInfo of defalt Visual\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if (vinfo->class != TrueColor && vinfo->class != DirectColor) {
+ debugr2((errout,"new_dispwin: Default Visual is not TrueColor or DirectColor\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Compute per component frame buffer depth */
+ {
+ for (p->fdepth = 1; p->fdepth < 17; p->fdepth++) {
+ if ((1 << p->fdepth) >= myvisual->map_entries)
+ break;
+ }
+ if (p->fdepth >= 17) {
+ debugr2((errout,"new_dispwin: failed to extract depth from Visual bits_per_rgb %d\n",myvisual->map_entries));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+ p->rdepth = myvisual->bits_per_rgb; /* X11 colormap entry size */
+ p->edepth = 16; /* Assumed */
+
+ /* Check that vinfo->red_mask, green_mask & blue_mask all have */
+ /* myvisual->map_entries number of bits set, and determine the shift. */
+ {
+ unsigned long bit;
+ int depth;
+
+ if (vinfo->red_mask == 0 || vinfo->green_mask == 0 || vinfo->blue_mask == 0) {
+ debugr2((errout,"new_dispwin: one of default Visual r/g/b masks is 0\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[0] = 0, bit = 1; (bit & vinfo->red_mask) == 0; p->shift[0]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->red_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual red mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[1] = 0, bit = 1; (bit & vinfo->green_mask) == 0; p->shift[1]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->green_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual green mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[2] = 0, bit = 1; (bit & vinfo->blue_mask) == 0; p->shift[2]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->blue_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual blue mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+
+ /* Check the VideoLUT depth */
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ if (p->crtc != 0) { /* Using Xrandr 1.2 */
+
+ if ((p->nent = XRRGetCrtcGammaSize(p->mydisplay, p->crtc)) <= 0) {
+ p->nent = 0;
+ }
+ } else
+#endif /* randr >= V 1.2 */
+ {
+ p->nent = 0;
+
+ if (XF86VidModeQueryExtension(p->mydisplay, &evb, &erb) != 0) {
+ int nent = -1;
+
+ /* Some propietary multi-screen drivers (ie. TwinView & MergedFB) */
+ /* don't implement the XVidMode extenstion properly. */
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugr("new_dispwin failed on XSetErrorHandler\n");
+ XSetErrorHandler(NULL); /* Restore handler */
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ if (XF86VidModeGetGammaRampSize(p->mydisplay, p->myrscreen, &nent) != 0
+ && nent != -1) {
+ p->nent = nent;
+ }
+ XSetErrorHandler(NULL); /* Restore handler */
+ }
+ }
+
+ if (p->nent == 0) {
+ p->ndepth = 0;
+
+ if (!p->warned) {
+ warning("new_dispwin: VideoLUT is not accessible");
+ p->warned = 1;
+ }
+
+ } else {
+ if (p->nent > 16384) {
+ debugr("VideoLUT has more entries than we can handle\n");
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Compute actual ramdac depth */
+ for (p->ndepth = 1; p->ndepth < 17; p->ndepth++) {
+ if ((1 << p->ndepth) >= p->nent)
+ break;
+ }
+
+ if (p->nent != (1 << p->rdepth)) {
+ if (!p->warned) {
+ warning("new_dispwin: Expected VideoLUT depth %d doesn't match actual %d",p->rdepth, p->ndepth);
+ p->warned = 1;
+ }
+ }
+ }
+
+ debugr2((errout,"new_dispwin: %s fdepth %d, rdepth %d, ndepth %d, edepth %d, r/g/b shifts %d %d %d\n", vinfo->class != TrueColor ? "TreuColor" : "DirectColor", p->fdepth,p->rdepth,p->ndepth,p->edepth, p->shift[0], p->shift[1], p->shift[2]));
if (nowin == 0) { /* Create a window */
+ unsigned long attrmask = 0;
+ XWindowAttributes mywa;
+ Colormap mycmap = None;
+ int ncolors, i;
+
rootwindow = RootWindow(p->mydisplay, p->myscreen);
myforeground = BlackPixel(p->mydisplay, p->myscreen);
@@ -4887,6 +5250,53 @@ int ddebug /* >0 to print debug statements to stderr */
else
myattr.override_redirect = False;
+ attrmask |= CWBackPixel | CWBitGravity /* Attributes Valumask */
+ | CWWinGravity | CWBackingStore | CWOverrideRedirect;
+
+ /* For a DirectColor Visual, set the X11 color map */
+ if (vinfo->class == DirectColor) {
+ Colormap mycmap = None;
+ XColor *colors;
+ int ncolors = (1 << p->fdepth), i;
+
+ debugr2((errout,"new_dispwin: setting DirectColor colormap\n"));
+
+ if ((mycmap = XCreateColormap(p->mydisplay, rootwindow, myvisual, AllocAll)) == None) {
+ debugr2((errout,"new_dispwin: XCreateColormap failed\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if ((colors = malloc(sizeof(XColor) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for XColors\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Set a linear mapping */
+ for (i = 0; i < ncolors; i++) {
+ colors[i].pixel = i << p->shift[0] | i << p->shift[1] | i << p->shift[2];
+ colors[i].red =
+ colors[i].green =
+ colors[i].blue = (unsigned short) (65535.0 * i/(ncolors-1.0) + 0.5);
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ if (!XStoreColors(p->mydisplay, mycmap, colors, ncolors)) {
+ debugr2((errout,"new_dispwin: DirectColor XStoreColors failed\n"));
+ free(colors);
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ free(colors);
+
+ myattr.colormap = mycmap;
+ attrmask |= CWColormap;
+ }
+
debugr("Opening window\n");
p->mywindow = XCreateWindow(
p->mydisplay, rootwindow,
@@ -4894,9 +5304,9 @@ int ddebug /* >0 to print debug statements to stderr */
0, /* Border width */
CopyFromParent, /* Depth */
InputOutput, /* Class */
- CopyFromParent, /* Visual */
- CWBackPixel | CWBitGravity /* Attributes Valumask */
- | CWWinGravity | CWBackingStore | CWOverrideRedirect,
+// CopyFromParent, /* Visual */
+ myvisual, /* Visual */
+ attrmask, /* Attributes Valumask */
&myattr /* Attribute details */
);
@@ -4908,10 +5318,12 @@ int ddebug /* >0 to print debug statements to stderr */
p->mydisplay, p->mywindow,
&mywattributes) == 0) {
debugr("new_dispwin: XGetWindowAttributes failed\n");
+ XFree(vinfo);
dispwin_del(p);
return NULL;
}
- p->pdepth = mywattributes.depth/3;
+ p->fdepth = mywattributes.depth/3;
+ p->rdepth = p->fdepth;
#endif
/* Setup TextProperty */
@@ -4926,6 +5338,9 @@ int ddebug /* >0 to print debug statements to stderr */
&mywmhints,
NULL); /* No class hints */
+ // ~1 should free myappname, but there doesn't seem to be
+ // a XFreeXTextProperty(&myappname); ???
+
/* Set aditional properties */
{
Atom optat;
@@ -4975,8 +5390,8 @@ int ddebug /* >0 to print debug statements to stderr */
XSelectInput(p->mydisplay,p->mywindow, ExposureMask);
+ debugr2((errout,"new_dispwin about to raise window\n"));
XMapRaised(p->mydisplay,p->mywindow);
- debug("Raised window\n");
/* ------------------------------------------------------- */
/* Suspend any screensavers if we can */
@@ -5065,7 +5480,7 @@ int ddebug /* >0 to print debug statements to stderr */
}
/* Deal with any pending events */
- debug("About to enter main loop\n");
+ debugr("About to enter main loop\n");
while(XPending(p->mydisplay) > 0) {
XNextEvent(p->mydisplay, &myevent);
switch(myevent.type) {
@@ -5079,10 +5494,94 @@ int ddebug /* >0 to print debug statements to stderr */
break;
}
}
+
+ /* Deal with Colormaps */
+ debugr2((errout,"new_dispwin: window created - dealling with colormap\n"));
+
+ if (!XGetWindowAttributes(p->mydisplay, p->mywindow, &mywa)) {
+ debugr2((errout,"new_dispwin: XGetWindowAttributes failed\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ mycmap = mywa.colormap;
+ ncolors = (1 << p->fdepth);
+
+ for (i = 0; i < 3; i++) {
+ if ((p->rmap[i] = malloc(sizeof(int) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for rmap[%d]\n",i));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+
+ /* Get the X11 colormaps, so that we know how to translate */
+ /* between the frame buffer pixel value and the ramdac */
+ /* index number. */
+ if (mycmap != None) {
+ XColor *colors;
+
+ debugr2((errout,"new_dispwin: getting colormap\n"));
+
+ if ((colors = malloc(sizeof(XColor) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for XColors\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (i = 0; i < ncolors; i++) {
+ colors[i].pixel = i << p->shift[0] | i << p->shift[1] | i << p->shift[2];
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ if (!XQueryColors(p->mydisplay, mycmap, colors, ncolors)) {
+ debugr2((errout,"new_dispwin: DirectColor XQueryColors failed\n"));
+ free(colors);
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Map from frame buffer value to ramdac index */
+ for (i = 0; i < ncolors; i++) {
+ p->rmap[0][i] = (int)(colors[i].red/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[1][i] = (int)(colors[i].green/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[2][i] = (int)(colors[i].blue/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+
+//printf("%d: %d %d %d\n",i,p->rmap[0][i],p->rmap[1][i],p->rmap[2][i]);
+ }
+
+ free(colors);
+
+ /* Assume a default linear mapping */
+ } else {
+ debugr2((errout,"new_dispwin: assuming a linear colormap\n"));
+ for (i = 0; i < ncolors; i++) {
+ p->rmap[0][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[1][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[2][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ }
+
+ if (p->fdepth != p->rdepth) {
+ static int warned = 0;
+ if (!warned) {
+ warning("new_dispwin: frame buffer depth %d != VideoLUT depth %d",p->fdepth, p->rdepth);
+ warned = 1;
+ }
+ }
+ }
+
+ debugr2((errout,"new_dispwin: dealt with colormap\n"));
+
} else {
/* Install the signal handler to ensure cleanup */
dispwin_install_signal_handlers(p);
}
+
+ XFree(vinfo); vinfo = NULL;
}
#endif /* UNIX X11 */
/* -------------------------------------------------- */
@@ -5750,7 +6249,7 @@ main(int argc, char *argv[]) {
if (fa < argc) {
strncpy(calname,argv[fa++],MAXNAMEL); calname[MAXNAMEL] = '\000';
if (installprofile == 0 && loadprofile == 0 && verify == 0)
- loadfile = 1; /* Load the given profile into the videoLUT */
+ loadfile = 1; /* Load the given profile into the VideoLUT */
}
#if defined(UNIX_X11)
@@ -5949,7 +6448,7 @@ main(int argc, char *argv[]) {
/* Should we load calfile instead of installed profile if it's present ??? */
if (loadprofile) {
if (calname[0] != '\000')
- warning("Profile '%s' provided as argument is being ignored!\n",calname);
+ warning("Profile '%s' provided as argument is being ignored!",calname);
/* Get the current displays profile */
debug2((errout,"Loading calibration from display profile '%s'\n",dw->name));
@@ -5974,7 +6473,7 @@ main(int argc, char *argv[]) {
is_ok_icc = 1; /* The profile is OK */
if ((wo = (icmVideoCardGamma *)icco->read_tag(icco, icSigVideoCardGammaTag)) == NULL) {
- warning("No vcgt tag found in profile - assuming linear\n");
+ warning("No vcgt tag found in profile - assuming linear");
for (i = 0; i < dw->r->nent; i++) {
iv = i/(dw->r->nent-1.0);
dw->r->v[0][i] = iv;
@@ -6008,7 +6507,7 @@ main(int argc, char *argv[]) {
} else { /* See if it's a .cal file */
int ncal;
int ii, fi, ri, gi, bi;
- double cal[3][256];
+ double cal[3][MAX_CAL_ENT];
int out_tvenc = 0; /* nz to use (16-235)/255 video encoding */
icco->del(icco); /* Don't need these now */
@@ -6032,8 +6531,8 @@ main(int argc, char *argv[]) {
if ((ncal = ccg->t[0].nsets) <= 0)
error("No data in set of file '%s'",calname);
- if (ncal != 256)
- error("Expect 256 data sets in file '%s'",calname);
+ if (ncal < 2 || ncal > MAX_CAL_ENT)
+ error("Data set size %d is out of range for '%s'",ncal,calname);
if ((fi = ccg->find_kword(ccg, 0, "DEVICE_CLASS")) < 0)
error("Calibration file '%s' doesn't contain keyword COLOR_REP",calname);
diff --git a/spectro/dispwin.h b/spectro/dispwin.h
index b5e14ce..47fd256 100644
--- a/spectro/dispwin.h
+++ b/spectro/dispwin.h
@@ -73,11 +73,11 @@ WINSHLWAPI LPWSTR WINAPI PathFindFileNameW(LPCWSTR);
#endif /* NT */
-#ifdef __APPLE__ /* Assume OS X Cocoa */
+#ifdef UNIX_APPLE /* Assume OS X Cocoa */
#include <Carbon/Carbon.h> /* To declare CGDirectDisplayID */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
#include <X11/Xlib.h>
@@ -114,9 +114,9 @@ typedef struct {
char monid[128]; /* Monitor ID */
int prim; /* NZ if primary display monitor */
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
CGDirectDisplayID ddid;
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
int screen; /* Screen to select */
int uscreen; /* Underlying screen */
@@ -158,9 +158,17 @@ struct _ramdac {
/* Should have separate frame buffer depth + representation to account */
/* for floating point frame buffers, even though this isn't currently used. */
- int pdepth; /* Frame buffer depth into RAMDAC, usually 8 */
- int nent; /* Number of entries, = 2^pdepth */
- double *v[3]; /* 2^pdepth entries for RGB, values 0.0 - 1.0 */
+ int fdepth; /* Frame buffer depth, typically 8, could be more. */
+ int rdepth; /* Expected ramdac index depth. May be different to fdepth */
+ /* if there is another level of mapping between the frame buffer */
+ /* and ramdac, i.e. X11 DirectorColor Colormap. */
+
+ int ndepth; /* Actual ramdac depth, typically = rdepth */
+ int nent; /* Number of entries, = 2^ndepth, typically = 2^rdepth, */
+ /* but may be different for some video cards. */
+ /* Will be 0 if ramdac is not accessible */
+
+ double *v[3]; /* nent entries for RGB, values 0.0 - 1.0 */
/* Clone ourselves */
struct _ramdac *(*clone)(struct _ramdac *p);
@@ -255,12 +263,12 @@ struct _dispwin {
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
CGDirectDisplayID ddid;
void *osx_cntx; /* OSX specific info */
int btf; /* Flag, nz if window has been brought to the front once */
int winclose; /* Flag, set to nz if window was closed */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
Display *mydisplay;
@@ -271,6 +279,9 @@ struct _dispwin {
unsigned char *edid; /* 128 or 256 bytes of monitor EDID, NULL if none */
int edid_len; /* 128 or 256 */
+ int shift[3]; /* Bit shift to create RGB value from components */
+ int *rmap[3]; /* Map of fdepth to rdepth values */
+
#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2
/* Xrandr stuff - output is connected 1:1 to a display */
RRCrtc crtc; /* Associated crtc */
@@ -308,10 +319,21 @@ struct _dispwin {
volatile int cberror; /* NZ if error detected in a callback routine */
int ddebug; /* >0 to print debug to stderr */
+ int warned; /* Warning message has been issued */
+
/* public: */
- int pdepth; /* Frame buffer plane depth of display */
- int edepth; /* Notional ramdac entry size in bits. (Bits actually used may be less) */
- /* This is used to scale out_tvenc appropriately */
+ int fdepth; /* Frame buffer depth, typically 8, could be more */
+ int rdepth; /* Expected ramdac index depth. May be different to fdepth */
+ /* if there is another level of mapping between the frame buffer */
+ /* and ramdac, i.e. X11 DirectorColor Colormap. */
+
+ int ndepth; /* Actual ramdac depth, typically = rdepth */
+ int nent; /* Number of entries, = s^ndepth, typically = 2^rdepth, */
+ /* but may be different for some video cards. */
+ /* Will be 0 if ramdac is not accessible */
+
+ int edepth; /* Notional frame buffer/ramdac entry size in bits. (Bits actually used */
+ /* may be less). This is just used to scale out_tvenc appropriately. */
/* Get RAMDAC values. ->del() when finished. */
/* Return NULL if not possible */
diff --git a/spectro/dtp20.c b/spectro/dtp20.c
index 6af2484..a125a53 100644
--- a/spectro/dtp20.c
+++ b/spectro/dtp20.c
@@ -72,6 +72,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp20.h"
+#include "xrga.h"
static inst_code dtp20_interp_code(inst *pp, int ec);
static inst_code activate_mode(dtp20 *p);
@@ -345,12 +346,27 @@ dtp20_init_inst(inst *pp) {
dtp20 *p = (dtp20 *)pp;
char buf[MAX_MES_SIZE];
inst_code rv = inst_ok;
+ char *envv;
a1logd(p->log, 2, "dtp20_init_inst: called\n");
if (p->gotcoms == 0)
return inst_no_coms; /* Must establish coms before calling init */
+
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Reset it (without disconnecting USB or clearing stored data) */
if ((rv = dtp20_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
return rv;
@@ -534,7 +550,8 @@ ipatch *vals) { /* Pointer to array of values */
tp += strlen(tp) + 1;
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
@@ -575,6 +592,11 @@ ipatch *vals) { /* Pointer to array of values */
}
a1logv(p->log, 1, "All saved strips read\n");
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
return inst_ok;
}
@@ -762,7 +784,8 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
@@ -813,6 +836,11 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
}
}
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -993,7 +1021,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
int j;
/* Set to read spectral reflectance */
@@ -1051,6 +1080,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -1086,6 +1118,7 @@ static inst_code dtp20_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) */
) {
dtp20 *p = (dtp20 *)pp;
@@ -1098,6 +1131,7 @@ 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 = dtp20_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1136,6 +1170,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
;
*cp = '\000';
strcpy(id, buf);
+ *idtype = inst_calc_id_ref_sn;
*calc = inst_calc_man_ref_white;
return inst_cal_setup;
}
@@ -1686,7 +1721,7 @@ inst_opt_type m, /* Requested status type */
}
/* !! It's not clear if there is a way of knowing */
- /* whether the instrument has a UV filter. */
+ /* whether the instrument has a UV filter !! */
/* Use default implementation of other inst_opt_type's */
{
diff --git a/spectro/dtp20.h b/spectro/dtp20.h
index c575c67..a8b6862 100644
--- a/spectro/dtp20.h
+++ b/spectro/dtp20.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP20_INTERNAL_ERROR 0x81 /* Internal software error */
#define DTP20_COMS_FAIL 0x82 /* Communication failure */
@@ -128,12 +132,17 @@ struct _dtp20 {
int savix; /* Index of last saved spot reading read */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp20 dtp20;
/* Constructor */
extern dtp20 *new_dtp20(icoms *icom, instType itype);
-
+#ifdef __cplusplus
+ }
+#endif
#define DTP20_H
#endif /* DTP20_H */
diff --git a/spectro/dtp22.c b/spectro/dtp22.c
index 2cb3634..37249f0 100644
--- a/spectro/dtp22.c
+++ b/spectro/dtp22.c
@@ -32,6 +32,11 @@
and agreed to support.
*/
+/*
+ Would like to add a thread to return status of
+ switch, so that we can fully run this in progromatic trigger mode.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -51,6 +56,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp22.h"
+#include "xrga.h"
/* Default flow control (Instrument doesn't support HW flow control) */
#define DEFFC fc_XonXOff
@@ -186,7 +192,7 @@ dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -209,40 +215,37 @@ dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
- a1logd(p->log, 4, "dtp22_init_coms: Trying different baud rates (%u msec to go)\n",
- etime - msec_time());
-
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+
+ a1logd(p->log, 4, "dtp22_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(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
- }
- if (((ev = dtp22_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
-
- /* 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, "dtp22_init_coms: user aborted\n");
- return ev;
- }
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ }
+ if (((ev = dtp22_command(p, "\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) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return ev;
}
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 5)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ got_coms:;
/* Set the handshaking */
if ((ev = dtp22_command(p, fcc, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
@@ -287,6 +290,7 @@ dtp22_init_inst(inst *pp) {
dtp22 *p = (dtp22 *)pp;
char buf[MAX_MES_SIZE], *bp;
inst_code ev = inst_ok;
+ char *envv;
int i;
a1logd(p->log, 2, "dtp22_init_inst: called\n");
@@ -294,6 +298,19 @@ dtp22_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Warm reset it */
if ((ev = dtp22_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
return ev;
@@ -333,7 +350,7 @@ dtp22_init_inst(inst *pp) {
/* - - - - - - - - - - - - - - - - - - - - - - - - */
/* Get some information about the instrument */
- if ((ev = dtp22_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ if ((ev = dtp22_command(p, "GI\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok) {
a1logd(p->log, 1, "dtp22: GI command failed with ICOM err 0x%x\n",ev);
return ev;
}
@@ -577,7 +594,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.spec_n = 0;
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
int j;
char *fmt;
@@ -605,6 +623,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.norm = 100.0;
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -640,6 +661,7 @@ inst_code dtp22_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) */
) {
dtp22 *p = (dtp22 *)pp;
@@ -654,6 +676,7 @@ 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 = dtp22_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -683,7 +706,8 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (*calt & inst_calt_ref_white) { /* White calibration */
- sprintf(id, "Serial no. %d",p->plaqueno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",p->plaqueno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_whitek) {
*calc = inst_calc_man_ref_whitek;
ev = inst_cal_setup;
@@ -1046,6 +1070,37 @@ dtp22_get_set_opt(inst *pp, inst_opt_type m, ...)
{
dtp22 *p = (dtp22 *)pp;
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
/* Record the trigger mode */
if (m == inst_opt_trig_prog
|| m == inst_opt_trig_user
@@ -1054,7 +1109,17 @@ dtp22_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- 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 */
diff --git a/spectro/dtp22.h b/spectro/dtp22.h
index 95dce16..af565e8 100644
--- a/spectro/dtp22.h
+++ b/spectro/dtp22.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update dtp22_interp_error() and dtp22_interp_code() in dtp22.c */
/* if anything of these #defines are added or subtracted */
@@ -95,11 +99,17 @@ struct _dtp22 {
int noutocalib; /* Don't mode change or auto calibrate */
inst_opt_type trig; /* Reading trigger mode */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp22 dtp22;
/* Constructor */
extern dtp22 *new_dtp22(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define DTP22_H
#endif /* DTP22_H */
diff --git a/spectro/dtp41.c b/spectro/dtp41.c
index 44ac6c6..97a3db1 100644
--- a/spectro/dtp41.c
+++ b/spectro/dtp41.c
@@ -53,6 +53,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp41.h"
+#include "xrga.h"
/* Default flow control */
#define DEFFC fc_XonXOff
@@ -169,7 +170,7 @@ dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -192,36 +193,35 @@ dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp41_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(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
+ }
+ if (((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
- }
- if (((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
-
- /* 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, "dtp41_init_coms: user aborted\n");
- return inst_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) {
+ a1logd(p->log, 1, "dtp41_init_coms: user aborted\n");
+ return inst_user_abort;
}
- if (++i >= 9)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 9)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ got_coms:;
/* set the protocol to RCI */
if ((ev = dtp41_command(p, "0012CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
@@ -319,6 +319,7 @@ static inst_code
dtp41_init_inst(inst *pp) {
dtp41 *p = (dtp41 *)pp;
static char tbuf[100], buf[MAX_MES_SIZE];
+ char *envv;
inst_code ev = inst_ok;
a1logd(p->log, 2, "dtp41_init_inst: called\n");
@@ -326,6 +327,19 @@ dtp41_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Resetting instrument resets the baud rate, so do manual reset. */
/* Set emulation mode to DTP41 */
@@ -603,7 +617,9 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
tp += strlen(tp) + 1;
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || (XCALSTD_NEEDED(p->target_calstd, p->native_calstd)
+ && ((p->mode & inst_mode_illum_mask) != inst_mode_transmission))) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp41_command(p, "0403TS\r", buf, MAX_RD_SIZE, 0.5 + npatch * 0.1)) != inst_ok)
@@ -639,6 +655,11 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
tp += strlen(tp) + 1;
}
}
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -790,7 +811,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.spec_n = 0;
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || (XCALSTD_NEEDED(p->target_calstd, p->native_calstd)
+ && ((p->mode & inst_mode_illum_mask) != inst_mode_transmission))) {
int j;
/* Gather the results in Spectral reflectance */
@@ -840,6 +863,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if ((ev = dtp41_command(p, "0113CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
return ev;
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -881,6 +907,7 @@ inst_code dtp41_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) */
) {
dtp41 *p = (dtp41 *)pp;
@@ -892,6 +919,7 @@ 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 = dtp41_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -919,7 +947,6 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
return inst_unsupported;
}
-
if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
if (*calt & inst_calt_trans_white) {
@@ -1236,6 +1263,37 @@ dtp41_get_set_opt(inst *pp, inst_opt_type m, ...)
inst_code rv = inst_ok;
static char buf[MAX_MES_SIZE];
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
if (!p->gotcoms)
return inst_no_coms;
if (!p->inited)
@@ -1259,7 +1317,17 @@ dtp41_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- 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 */
diff --git a/spectro/dtp41.h b/spectro/dtp41.h
index 529f94c..018ed5c 100644
--- a/spectro/dtp41.h
+++ b/spectro/dtp41.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP41_INTERNAL_ERROR 0x61 /* Internal software error */
#define DTP41_COMS_FAIL 0x62 /* Communication failure */
@@ -101,10 +105,17 @@ struct _dtp41 {
int need_cal; /* needs calibration */
inst_opt_type trig; /* Reading trigger mode */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp41 dtp41;
/* Constructor */
extern dtp41 *new_dtp41(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define DTP41_H
#endif /* DTP41_H */
diff --git a/spectro/dtp51.c b/spectro/dtp51.c
index ab1999d..0b2ecab 100644
--- a/spectro/dtp51.c
+++ b/spectro/dtp51.c
@@ -202,7 +202,7 @@ dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -225,37 +225,36 @@ dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
-
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
- }
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp51_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(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
+ }
- if (((ev = dtp51_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
+ if (((ev = dtp51_command(p, "\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) {
- a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
- return inst_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) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return inst_user_abort;
}
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 5)
+ i = 0;
}
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ return inst_coms_fail;
+
+ got_coms:;
/* Set the handshaking */
if ((ev = dtp51_command(p, fcc, buf, MAX_MES_SIZE, 1.5)) != inst_ok)
@@ -595,6 +594,7 @@ inst_code dtp51_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) */
) {
dtp51 *p = (dtp51 *)pp;
@@ -606,6 +606,7 @@ 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 = dtp51_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -857,8 +858,7 @@ inst_code dtp51_set_mode(inst *pp, inst_mode m) {
* was assume that all of these can be done before initialisation.
*/
static inst_code
-dtp51_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+dtp51_get_set_opt(inst *pp, inst_opt_type m, ...) {
dtp51 *p = (dtp51 *)pp;
static char buf[MAX_MES_SIZE];
@@ -868,7 +868,31 @@ dtp51_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- return inst_unsupported;
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ *standard = p->native_calstd;
+
+ return inst_ok;
+ }
+
+ /* 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 */
@@ -896,5 +920,7 @@ extern dtp51 *new_dtp51(icoms *icom, instType itype) {
p->icom = icom;
p->itype = itype;
+ p->native_calstd = xcalstd_xrdi; /* Not alterable */
+
return p;
}
diff --git a/spectro/dtp51.h b/spectro/dtp51.h
index 329c5d6..804b8ae 100644
--- a/spectro/dtp51.h
+++ b/spectro/dtp51.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP51_INTERNAL_ERROR 0x61 /* Internal software error */
#define DTP51_COMS_FAIL 0x62 /* Communication failure */
@@ -91,12 +95,16 @@ struct _dtp51 {
int need_cal; /* needs calibration */
inst_opt_type trig; /* Reading trigger mode */
- }; typedef struct _dtp51 dtp51;
+ xcalstd native_calstd; /* Instrument native calibration standard */
+
+}; typedef struct _dtp51 dtp51;
/* Constructor */
extern dtp51 *new_dtp51(icoms *icom, instType itype);
-
+#ifdef __cplusplus
+ }
+#endif
#define DTP51_H
#endif /* DTP51_H */
diff --git a/spectro/dtp92.c b/spectro/dtp92.c
index 3b6dacd..33b8fa0 100644
--- a/spectro/dtp92.c
+++ b/spectro/dtp92.c
@@ -58,7 +58,7 @@
#include "dtp92.h"
/* Default flow control */
-#define DEFFC fc_none
+#define DEFFC fc_None
#define DEF_TIMEOUT 0.5
#define MED_TIMEOUT 2.5
@@ -147,7 +147,8 @@ dtp92_fcommand(
icoms_fix(in), icoms_fix(out),rv);
#ifdef IGNORE_NEEDS_OFFSET_DRIFT_CAL_ERR
- if (strcmp(in, "0PR\r") == 0 && rv == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
+ if ((strcmp(in, "0PR\r") == 0
+ || strcmp(in, "EFC\r") == 0) && rv == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
static int warned = 0;
if (!warned) {
a1logw(p->log,"dtp92: Got error NEEDS_OFFSET_DRIFT_CAL on instrument reset - being ignored.");
@@ -239,7 +240,7 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -262,41 +263,42 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp92_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(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
+ }
- a1logd(p->log, 4, "dtp92_init_coms: Trying different baud rates (%u msec to go)\n",
- etime - msec_time());
+ /* Throw one response away, to work around some USB<->Serial quirks */
+ p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
- }
+ if (((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, DEF_TIMEOUT)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
- if (((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, DEF_TIMEOUT)) & inst_mask)
- != inst_coms_fail)
- break; /* 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) {
- a1logd(p->log, 1, "dtp92_init_coms: user aborted\n");
- return inst_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) {
+ a1logd(p->log, 1, "dtp92_init_coms: user aborted\n");
+ return inst_user_abort;
}
-
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
- }
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
+ if (++i >= 5)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
+
+ got_coms:;
+
+ /* Throw one response away, to work around some USB<->Serial quirks */
+ p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
/* Set the handshaking */
if ((ev = dtp92_command(p, fcc, buf, MAX_MES_SIZE, DEF_TIMEOUT)) != inst_ok)
@@ -317,6 +319,7 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Loose a character (not sure why) */
p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
+
#else /* !ENABLE_SERIAL */
a1logd(p->log, 1, "dtp92: Failed to find serial connection to instrument\n");
return inst_coms_fail;
@@ -621,6 +624,14 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (sscanf(buf, " X%*c %lf\t Y%*c %lf\t Z%*c %lf ",
&val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) == 3) {
+ /* Hmm. The DTP92 seems to return strange X & Z values if the light */
+ /* level is zero, and it's black level is out of calibration */
+ /* (i.e. internally it has -ve Y ?) */
+ if (val->XYZ[1] == 0.0 && val->XYZ[0] == 999.99)
+ val->XYZ[0] = 0.0;
+ if (val->XYZ[1] == 0.0 && val->XYZ[2] == 999.99)
+ val->XYZ[2] = 0.0;
+
/* Apply the colorimeter correction matrix */
icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
@@ -778,6 +789,7 @@ static inst_code dtp92_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) */
) {
dtp92 *p = (dtp92 *)pp;
@@ -790,6 +802,7 @@ 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 = dtp92_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1356,8 +1369,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-dtp92_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+dtp92_get_set_opt(inst *pp, inst_opt_type m, ...) {
dtp92 *p = (dtp92 *)pp;
char buf[MAX_MES_SIZE];
inst_code ev = inst_ok;
@@ -1369,12 +1381,17 @@ dtp92_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* 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 inst_unsupported;
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/dtp92.h b/spectro/dtp92.h
index 317fb7a..8a6885e 100644
--- a/spectro/dtp92.h
+++ b/spectro/dtp92.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update dtp92_interp_error() and dtp92_interp_code() in dtp92.c */
/* if anything of these #defines are added or subtracted */
@@ -100,6 +104,9 @@ struct _dtp92 {
/* Constructor */
extern dtp92 *new_dtp92(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define DTP92_H
#endif /* DTP92_H */
diff --git a/spectro/ex1.c b/spectro/ex1.c
index b336cbc..5f4eae2 100644
--- a/spectro/ex1.c
+++ b/spectro/ex1.c
@@ -328,7 +328,9 @@ ex1_init_inst(inst *pp) {
//printf("~1 raw range = %d - %d\n",sconf->rawrange.off, sconf->rawrange.off + sconf->rawrange.num-1);
//printf("~1 = %f - %f nm\n",rspec_raw2nm(sconf, sconf->rawrange.off), rspec_raw2nm(sconf, sconf->rawrange.off + sconf->rawrange.num-1));
- sconf->ktype = rspec_gausian;
+ sconf->ktype = rspec_gausian; /* Default */
+// sconf->ktype = rspec_lanczos2;
+// sconf->ktype = rspec_lanczos3;
// sconf->ktype = rspec_triangle;
// sconf->ktype = rspec_cubicspline;
sconf->wl_space = 2.0;
@@ -702,6 +704,7 @@ inst_code ex1_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) */
) {
ex1 *p = (ex1 *)pp;
@@ -1160,8 +1163,7 @@ static void ex1_set_noinitcalib(ex1 *p, int v, int losecs) {
* error if it hasn't been initialised.
*/
static inst_code
-ex1_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+ex1_get_set_opt(inst *pp, inst_opt_type m, ...) {
ex1 *p = (ex1 *)pp;
inst_code ev = inst_ok;
@@ -1194,7 +1196,17 @@ ex1_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 */
diff --git a/spectro/ex1.h b/spectro/ex1.h
index d69b7ca..a278777 100644
--- a/spectro/ex1.h
+++ b/spectro/ex1.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Communication errors */
#define EX1_TIMEOUT 0xFF02 /* Communication timeout */
#define EX1_COMS_FAIL 0xFF03 /* Communication failure */
@@ -143,6 +147,9 @@ struct _ex1 {
/* Constructor */
extern ex1 *new_ex1(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define EX1_H
#endif /* EX1_H */
diff --git a/spectro/hcfr.c b/spectro/hcfr.c
index a6c457e..22b5170 100644
--- a/spectro/hcfr.c
+++ b/spectro/hcfr.c
@@ -366,7 +366,7 @@ hcfr_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
inst_code ev = inst_ok;
icomuflags usbflags = icomuf_no_open_clear | icomuf_detach;
-#if defined(__APPLE__) && !defined(__ppc__)
+#if defined(UNIX_APPLE) && !defined(__ppc__)
/* Except on Intel OS X 10.4/5 for some reasone. */
/* It would be good if the HCFR had a better USB implementation... */
usbflags &= ~icomuf_no_open_clear;
@@ -919,7 +919,17 @@ hcfr_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
- 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 */
diff --git a/spectro/hcfr.h b/spectro/hcfr.h
index 8910cec..2420fdf 100644
--- a/spectro/hcfr.h
+++ b/spectro/hcfr.h
@@ -35,11 +35,14 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Required minimum firmware version */
#define HCFR_FIRMWARE_MAJOR_VERSION 5
#define HCFR_FIRMWARE_MINOR_VERSION 0
-
/* Command byte contents. (A value of 0x00 won't be tranmsitted properly) */
/* 0xff = get firmware version */
@@ -99,6 +102,9 @@ struct _hcfr {
/* Constructor */
extern hcfr *new_hcfr(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define HCFR_H
#endif /* HCFR_H */
diff --git a/spectro/hidio.c b/spectro/hidio.c
index c930755..2d8649f 100644
--- a/spectro/hidio.c
+++ b/spectro/hidio.c
@@ -178,7 +178,7 @@ int hid_get_paths(icompaths *p) {
pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
dinfod.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; ; i++) {
- instType itype;
+ devType itype;
if (SetupDiEnumDeviceInterfaces(hdinfo, NULL, &HidGuid, i, &did) == 0) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
@@ -269,7 +269,7 @@ int hid_get_paths(icompaths *p) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
CFAllocatorContext alocctx;
@@ -308,7 +308,7 @@ int hid_get_paths(icompaths *p) {
CFNumberRef vref, pref; /* HID Vendor and Product ID propeties */
CFNumberRef lidpref; /* Location ID properties */
unsigned int vid = 0, pid = 0, lid = 0;
- instType itype;
+ devType itype;
IOHIDDeviceRef ioob = values[i]; /* HID object found */
if ((vref = IOHIDDeviceGetProperty(ioob, CFSTR(kIOHIDVendorIDKey))) != NULL) {
@@ -376,7 +376,7 @@ int hid_get_paths(icompaths *p) {
CFNumberRef vref, pref; /* HID Vendor and Product ID propeties */
CFNumberRef lidpref; /* Location ID properties */
unsigned int vid = 0, pid = 0, lid = 0;
- instType itype;
+ devType itype;
if ((ioob = IOIteratorNext(mit)) == 0)
break;
@@ -426,7 +426,7 @@ int hid_get_paths(icompaths *p) {
IOObjectRelease(mit); /* Release the itterator */
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
@@ -483,14 +483,14 @@ int hid_get_paths(icompaths *p) {
#endif /* NEVER */
#endif /* UNIX_X11 */
- a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* HID Interrupt callback for OS X */
/* This seems to only get called when the run loop is active. */
@@ -516,7 +516,7 @@ UInt32 size
a1logd(p->log, 8, "HID callback has no run loop\n");
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -571,7 +571,7 @@ char **pnames /* List of process names to try and kill before opening */
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
/* Open the device */
@@ -644,7 +644,7 @@ char **pnames /* List of process names to try and kill before opening */
}
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
p->is_open = 1;
a1logd(p->log, 8, "hid_open_port: HID port is now open\n");
@@ -669,7 +669,7 @@ void hid_close_port(icoms *p) {
CloseHandle(p->hidd->fh);
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (IOHIDDeviceClose(p->hidd->ioob, kIOHIDOptionsTypeNone) != kIOReturnSuccess) {
a1loge(p->log, ICOM_SYS, "hid_close_port: closing HID port '%s' failed",p->name);
@@ -701,7 +701,7 @@ void hid_close_port(icoms *p) {
}
p->hidd->device = NULL;
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
p->is_open = 0;
a1logd(p->log, 8, "hid_close_port: has been released and closed\n");
@@ -770,7 +770,7 @@ icoms_hid_read(icoms *p,
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
IOReturn result;
@@ -899,7 +899,7 @@ printf("~1 IOHIDDeviceGet returned 0x%x\n",result);
}
#endif // NEVER
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
if (breadp != NULL)
*breadp = bread;
@@ -968,7 +968,7 @@ icoms_hid_write(icoms *p,
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
IOReturn result;
@@ -1039,7 +1039,7 @@ printf("~1 IOHIDDeviceSetReportWithCallback returned 0x%x\n",result);
}
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
if (bwrittenp != NULL)
*bwrittenp = bwritten;
@@ -1101,7 +1101,7 @@ int hid_copy_hid_idevice(icoms *d, icompath *s) {
return ICOM_SYS;
}
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
d->hidd->ioob = s->hidd->ioob;
CFRetain(d->hidd->ioob);
@@ -1109,7 +1109,7 @@ int hid_copy_hid_idevice(icoms *d, icompath *s) {
d->hidd->ioob = s->hidd->ioob;
IOObjectRetain(d->hidd->ioob);
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined (UNIX_X11)
#endif
return ICOM_OK;
@@ -1124,7 +1124,7 @@ void hid_del_hid_idevice(struct hid_idevice *hidd) {
if (hidd->dpath != NULL)
free(hidd->dpath);
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (hidd->ioob != 0)
CFRelease(hidd->ioob);
@@ -1132,7 +1132,7 @@ void hid_del_hid_idevice(struct hid_idevice *hidd) {
if (hidd->ioob != 0)
IOObjectRelease(hidd->ioob);
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined (UNIX_X11)
#endif
free(hidd);
diff --git a/spectro/hidio.h b/spectro/hidio.h
index 90a741b..87edd43 100644
--- a/spectro/hidio.h
+++ b/spectro/hidio.h
@@ -1,7 +1,7 @@
#ifndef HIDIO_H
- /* General USB HID I/O support */
+/* General USB HID I/O support */
/*
* Argyll Color Correction System
@@ -16,16 +16,17 @@
* see the License2.txt file for licencing details.
*/
+
/* These routines supliement the class code in ntio.c and unixio.c */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <CoreFoundation/CoreFoundation.h>
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#ifdef __cplusplus
extern "C" {
@@ -59,7 +60,7 @@ struct hid_idevice {
HANDLE fh; /* File handle for write/read */
OVERLAPPED ols; /* Overlapped structure for write/read */
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
int lid; /* Location ID */
IOHIDDeviceRef ioob; /* Object to open */
diff --git a/spectro/huey.c b/spectro/huey.c
index b09ed2c..2c82b4c 100644
--- a/spectro/huey.c
+++ b/spectro/huey.c
@@ -885,7 +885,8 @@ huey_check_unlock(
if ((ev = huey_command(p, i1d_status, buf, buf, 1.0,1.0)) != inst_ok)
return ev;
- if (strncmp((char *)buf, "Locked", 6) == 0) {
+ /* Hmm. Some Lenovo Huey's say they are unlocked, even when they are not. */
+ if (p->lenovo || strncmp((char *)buf, "Locked", 6) == 0) {
memset(buf, 0, 7);
if (p->lenovo)
strcpy((char *)buf,"huyL");
@@ -902,6 +903,7 @@ huey_check_unlock(
if (strncmp((char *)buf, "huL002", 6) != 0 /* Lenovo Huey ? */
&& strncmp((char *)buf, "ECCM2 ", 6) != 0 /* Lenovo Thinkpad W530 Huey ? */
+ && strncmp((char *)buf, "ECCM3 ", 6) != 0 /* Lenovo Thinkpad W530 Huey ? */
&& strncmp((char *)buf, "Cir001", 6) != 0) { /* Huey */
a1logd(p->log,1,"huey_check_unlock: unknown model '%s'\n",buf);
return huey_interp_code((inst *)p, HUEY_UNKNOWN_MODEL);
@@ -920,7 +922,7 @@ huey_read_all_regs(
inst_code ev;
int i;
- a1logd(p->log,2,"huey_check_unlock: about to read all the registers\n");
+ a1logd(p->log,2,"huey_read_all_regs: about to read all the registers\n");
/* Serial number */
if ((ev = huey_rdreg_word(p, &p->ser_no, 0) ) != inst_ok)
@@ -988,7 +990,7 @@ huey_read_all_regs(
return ev;
a1logd(p->log,3,"Integration time = %d\n",p->int_clocks);
- a1logd(p->log,2,"huey_check_unlock: all registers read OK\n");
+ a1logd(p->log,2,"huey_read_all_regs: all registers read OK\n");
return inst_ok;
}
@@ -1671,8 +1673,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-huey_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+huey_get_set_opt(inst *pp, inst_opt_type m, ...) {
huey *p = (huey *)pp;
inst_code ev = inst_ok;
@@ -1717,7 +1718,17 @@ huey_get_set_opt(inst *pp, inst_opt_type m, ...)
return huey_set_LEDs(p, mask);
}
- 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 */
diff --git a/spectro/huey.h b/spectro/huey.h
index aec96a0..f13056b 100644
--- a/spectro/huey.h
+++ b/spectro/huey.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
/* if anything of these #defines are added or subtracted */
@@ -131,6 +135,9 @@ struct _huey {
/* Constructor */
extern huey *new_huey(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define HUEY_H
#endif /* HUEY_H */
diff --git a/spectro/i1d3.c b/spectro/i1d3.c
index df7d3f0..4562a52 100644
--- a/spectro/i1d3.c
+++ b/spectro/i1d3.c
@@ -2464,6 +2464,8 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* On Linux, the i1d3 doesn't seem to close properly, and won't re-open - */
/* something to do with detaching the default HID driver ?? */
#if defined(UNIX_X11)
+ usbflags |= icomuf_detach;
+ usbflags |= icomuf_no_open_clear;
usbflags |= icomuf_reset_before_close;
#endif
/* Open as an HID if available */
@@ -2485,7 +2487,7 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Set config, interface, write end point, read end point */
/* ("serial" end points aren't used - the i1d3 uses USB control messages) */
/* We need to detatch the HID driver on Linux */
- if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags | icomuf_detach, 0, NULL))
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, 0, NULL))
!= ICOM_OK) {
a1logd(p->log, 1, "i1d3_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
return i1d3_interp_code((inst *)p, icoms2i1d3_err(se, 0));
@@ -2695,6 +2697,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (!p->inited)
return inst_no_init;
+ a1logd(p->log, 1, "i1d3: i1d3_read_sample called\n");
+
if (p->trig == inst_opt_trig_user) {
if (p->uicallback == NULL) {
@@ -2944,6 +2948,7 @@ static inst_code i1d3_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) */
) {
i1d3 *p = (i1d3 *)pp;
@@ -2955,6 +2960,7 @@ 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 = i1d3_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -3816,8 +3822,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-i1d3_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1d3 *p = (i1d3 *)pp;
inst_code ev;
@@ -4018,7 +4023,18 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...)
if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
return inst_ok;
}
- 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 */
diff --git a/spectro/i1d3.h b/spectro/i1d3.h
index bb239df..a7c3b24 100644
--- a/spectro/i1d3.h
+++ b/spectro/i1d3.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
/* if anything of these #defines are added or subtracted */
@@ -79,7 +83,7 @@
typedef enum {
i1d3_disppro = 0, /* i1 DisplayPro */
i1d3_munkdisp = 1, /* ColorMunki Display */
- i1d3_oem = 2, /* OEM */
+ i1d3_oem = 2, /* Generic OEM */
i1d3_nec_ssp = 3, /* NEC SpectraSensor Pro */
i1d3_quato_sh3 = 4, /* Quato Silver Haze 3 */
i1d3_hp_dreamc = 5, /* HP DreameColor */
@@ -169,6 +173,9 @@ struct _i1d3 {
/* Constructor */
extern i1d3 *new_i1d3(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define I1D3_H
#endif /* I1D3_H */
diff --git a/spectro/i1disp.c b/spectro/i1disp.c
index 489c6cd..9e4b01f 100644
--- a/spectro/i1disp.c
+++ b/spectro/i1disp.c
@@ -481,7 +481,7 @@ i1disp_rdexreg_bytes(
) {
unsigned char ibuf[16];
unsigned char obuf[16];
- int rsize;
+ int ooff, rsize;
inst_code ev;
if (p->dtype != 2) /* Only ColorMunki Smile ? */
@@ -493,7 +493,7 @@ i1disp_rdexreg_bytes(
if (len < 0 || (addr + len) > 0x0200)
return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
- for (; len > 0; ) {
+ for (ooff = 0; len > 0; ) {
int rlen = len;
if (rlen > 4)
rlen = 4;
@@ -512,7 +512,8 @@ i1disp_rdexreg_bytes(
if (obuf[0] != rlen) /* Number of bytes returned */
return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_VAL);
- memcpy(outp + addr, obuf + 1, rlen);
+ memcpy(outp + ooff, obuf + 1, rlen);
+ ooff += rlen;
addr += rlen;
len -= rlen;
}
@@ -643,6 +644,7 @@ i1d1_take_measurement(
int i;
int edgec[3]; /* Edge count 1..255 for each channel */
inst_code ev;
+ double edge_aim = p->clk_freq;
if (p->inited == 0)
return i1disp_interp_code((inst *)p, I1DISP_NOT_INITED);
@@ -659,13 +661,18 @@ i1d1_take_measurement(
a1logd(p->log, 3, "Initial RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
/* Compute adjusted edge count, aiming */
- /* for count values of clk_freq = 1 second (~1e6). */
+ /* for count values of clk_freq = 1 second (~1e6), */
+ /* or 2 seconds if an older instrument */
+ if (p->stype == i1d1_sencoreIV
+ || p->stype == i1d1_sencoreIII)
+ edge_aim = 2.0 * p->clk_freq;;
+
for (i = 0; i < 3; i++) {
double ns;
- if (p->clk_freq > ((255.0 - 0.5) * rgb[i]))
+ if (edge_aim > ((255.0 - 0.5) * rgb[i]))
ns = 255.0;
else {
- ns = floor(p->clk_freq/rgb[i]) + 0.5;
+ ns = floor(edge_aim/rgb[i]) + 0.5;
if (ns < 1.0)
ns = 1.0;
}
@@ -1254,12 +1261,13 @@ i1disp_take_XYZ_measurement(
for (j = 0; j < 3; j++) {
XYZ[i] += mat[i * 3 + j] * rgb[j];
}
- XYZ[i] *= CALFACTOR; /* Times magic scale factor */
-#ifdef NEVER
- if (p->chroma4)
- XYZ[i] *= 4.0/3.0; /* (Not sure about this factor!) */
-#endif
+
+ /* Magic factors for other devices ?? */
+ if (p->stype == i1d1_sencoreIV)
+ XYZ[i] *= CALFACTOR; /* (Not sure about this factor!) */
+ else
+ XYZ[i] *= CALFACTOR; /* Times magic scale factor */
}
if (!IMODETST(p->mode, inst_mode_emis_ambient)) {
@@ -1402,25 +1410,26 @@ i1disp_check_unlock(
struct {
unsigned char code[4];
- int *flag;
+ i1d2_dtype stype;
} codes[] = {
- { { 'G','r','M','b' }, NULL }, /* "GrMb" i1 Display */
- { { 'L','i','t','e' }, &p->lite }, /* "Lite" i1 Display LT */
- { { 'M','u','n','k' }, &p->munki }, /* "Munk" ColorMunki Create */
- { { 'O','b','i','W' }, &p->hpdream }, /* "ObiW" HP DreamColor */
- { { 'O','b','i','w' }, &p->hpdream }, /* "Obiw" HP DreamColor */
- { { 'C','M','X','2' }, &p->calmanx2 }, /* "CMX2" Calman X2 */
- { { 0x24,0xb6,0xb5,0x13 }, NULL }, /* ColorMunki Smile */
- { { 'S','p','C','3' }, NULL }, /* SpectraCal C3 (Based on Smile) */
- { { 'R','G','B','c' }, NULL }, /* */
- { { 'C','E','C','5' }, NULL }, /* */
- { { 'C','M','C','5' }, NULL }, /* */
- { { 'C','M','G','5' }, NULL }, /* */
- { { 0x00,0x00,0x01,0x00 }, NULL }, /* */
- { { 0x09,0x0b,0x0c,0x0d }, NULL }, /* */
- { { 0x0e,0x0e,0x0e,0x0e }, NULL }, /* */
- { { 0x11,0x02,0xde,0xf0 }, NULL }, /* Barco Chroma 5 ? */
- { { ' ',' ',' ',' ' }, (int *)-1 }
+ { { 'G','r','M','b' }, i1d2_norm }, /* "GrMb" i1 Display */
+ { { 'L','i','t','e' }, i1d2_lite }, /* "Lite" i1 Display LT */
+ { { 'M','u','n','k' }, i1d2_munki }, /* "Munk" ColorMunki Create */
+ { { 'O','b','i','W' }, i1d2_hpdream }, /* "ObiW" HP DreamColor */
+ { { 'O','b','i','w' }, i1d2_hpdream }, /* "Obiw" HP DreamColor */
+ { { 'C','M','X','2' }, i1d1_calmanx2 }, /* "CMX2" Calman X2 */
+ { { 0x24,0xb6,0xb5,0x13 }, i1d2_norm }, /* ColorMunki Smile */
+ { { 'S','p','C','3' }, i1d2_norm }, /* SpectraCal C3 (Based on Smile) */
+ { { 'R','G','B','c' }, i1d2_norm }, /* */
+ { { 'C','E','C','5' }, i1d2_norm }, /* */
+ { { 'C','M','C','5' }, i1d2_norm }, /* */
+ { { 'C','M','G','5' }, i1d2_norm }, /* */
+ { { 0x00,0x00,0x01,0x00 }, i1d2_norm }, /* */
+ { { 0x09,0x0b,0x0c,0x0d }, i1d2_norm }, /* */
+ { { 0x0e,0x0e,0x0e,0x0e }, i1d2_norm }, /* */
+ { { 0x11,0x02,0xde,0xf0 }, i1d2_norm }, /* Barco Chroma 5 ? */
+// { { 0xff,0xff,0xff,0xff }, i1d2_norm }, /* Chroma 5 isn't locked ? */
+ { { ' ',' ',' ',' ' }, -1 }
};
a1logd(p->log, 3, "i1disp: about to check response and unlock instrument if needed\n");
@@ -1433,17 +1442,9 @@ i1disp_check_unlock(
/* Try and unlock it if it is locked */
if ((ev & inst_imask) == I1DISP_LOCKED) {
- /* Reset any flags */
- for (i = 0; ;i++) {
- if (codes[i].flag == (int *)-1)
- break;
- if (codes[i].flag != NULL)
- *codes[i].flag = 0;
- }
-
/* Try each code in turn */
for (i = 0; ;i++) {
- if (codes[i].flag == (int *)-1) {
+ if (codes[i].stype == -1) {
a1logd(p->log, 3, "Failed to find correct unlock code\n");
return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_MODEL);
}
@@ -1461,8 +1462,9 @@ i1disp_check_unlock(
return ev; /* An error other than being locked */
if (ev == inst_ok) { /* Correct code */
- if (codes[i].flag != NULL)
- *codes[i].flag = 1;
+ p->stype = codes[i].stype;
+ a1logd(p->log, 3, "Unlocked with code '%c%c%c%c'\n",
+ codes[i].code[0], codes[i].code[1], codes[i].code[2], codes[i].code[3]);
break;
}
}
@@ -1485,15 +1487,30 @@ i1disp_check_unlock(
a1logd(p->log, 3, "Version character = 0x%02x = '%c'\n",vv,vv);
- /* Sequel Chroma 4 with vv == 0xff ? */
- /* Barco Chroma 5 with ver = 5.01 and vv = '5' */
- if (ver >= 4.0 && ver < 5.1
- && (vv == 0xff || vv == 0x35)) {
+ /* Barco Chroma 5 with ver = 5.01 vv = '5' */
+ if (ver >= 4.0 && ver < 5.1 && vv == '5') {
p->dtype = 0; /* Sequel Chroma 4 ?? */
- p->chroma4 = 1; /* Treat like an Eye-One Display 1 */
- /* !!! Not fully tested !!! */
+ p->stype = i1d1_chroma4; /* Treat like an Eye-One Display 1 */
+
+ /* Sequel Chroma 4 with vv == 0xff ???? */
+ /* Sencore ColorPro III with ver = 5.01 and vv = 0xff */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 0xff) {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreIII;
+
+ /* Sencore ColorPro IV with ver = 5.01 and vv = 'L' */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 'L') {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreIV; /* Treat like an Eye-One Display 1 */
+
+ /* Sencore ColorPro V with ver = 5.01 and vv = 'B' */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 'B') {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreV; /* Treat like an Eye-One Display 1 */
+
} else if (ver >= 5.1 && ver <= 5.3 && vv == 'L') {
p->dtype = 0; /* Eye-One Display 1 */
+
} else if (ver >= 6.0 && ver <= 6.29 && vv == 'L') {
p->dtype = 1; /* Eye-One Display 2 */
@@ -1506,7 +1523,7 @@ i1disp_check_unlock(
} else {
/* Reject any version or model we don't know about */
- a1logv(p->log, 1, "Version string = %3.1f\nID character = 0x%02x = '%c'\n",ver,vv,vv);
+ a1logd(p->log, 1, "Version string = %5.3f\nID character = 0x%02x = '%c'\n",ver,vv,vv);
return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_VERS_ID);
}
@@ -1998,6 +2015,7 @@ inst_code i1disp_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) */
) {
i1disp *p = (i1disp *)pp;
@@ -2009,6 +2027,7 @@ 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 = i1disp_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -2588,8 +2607,7 @@ int *cbid) {
* was assume that all of these can be done before initialisation.
*/
static inst_code
-i1disp_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1disp_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1disp *p = (i1disp *)pp;
inst_code ev;
@@ -2600,7 +2618,17 @@ i1disp_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- 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 */
diff --git a/spectro/i1disp.h b/spectro/i1disp.h
index 45e21db..eada827 100644
--- a/spectro/i1disp.h
+++ b/spectro/i1disp.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update i1disp_interp_error() and i1disp_interp_code() in i1disp.c */
/* if anything of these #defines are added or subtracted */
@@ -72,17 +76,28 @@
#define I1DISP_WRONG_DEVICE 0x26
#define I1DISP_LOCKED 0x27
+/* Sub-type of instrument (i.e. based on vers, char code, unlock code) */
+typedef enum {
+ i1d2_norm = 0, /* Normal (i1d1, i1d2, Smile) */
+ i1d2_lite = 1, /* "Lite" */
+ i1d2_munki = 2, /* "Munk" */
+ i1d2_hpdream = 3, /* "ObiW" */
+ i1d1_calmanx2 = 4, /* "CMX2" */
+ i1d1_chroma4 = 5, /* Chroma 4 */
+ i1d1_chroma5 = 6, /* Chroma 5 */
+ i1d1_sencoreIII = 7, /* Sencore ColorPro III */
+ i1d1_sencoreIV = 8, /* Sencore ColorPro IV */
+ i1d1_sencoreV = 9 /* Sencore ColorPro V */
+} i1d2_dtype;
+
/* I1DISP communication object */
struct _i1disp {
INST_OBJ_BASE
- int dtype; /* Device type: 0 = i1D1, 1 = i1D2, 2 = Smile */
- int lite; /* i1D2: 0 = normal, 1 = "Lite" */
- int munki; /* i1D2: 0 = normal, 1 = "Munk" */
- int hpdream; /* i1D2: 0 = normal, 1 = "ObiW" */
- int calmanx2; /* i1D2: 0 = normal, 1 = "CMX2" */
- int chroma4; /* 0 = other, 1 = Sequel Chroma 4 (i1D1 based) */
+ int dtype; /* Device type: 0 = i1D1, 1 = i1D2, 2 = Smile */
+ i1d2_dtype stype; /* Sub type */
+
inst_mode mode; /* Currently selected mode */
inst_opt_type trig; /* Reading trigger mode */
@@ -169,6 +184,9 @@ struct _i1disp {
/* Constructor */
extern i1disp *new_i1disp(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define I1DISP_H
#endif /* I1DISP_H */
diff --git a/spectro/i1pro.c b/spectro/i1pro.c
index 816aee5..44614d2 100644
--- a/spectro/i1pro.c
+++ b/spectro/i1pro.c
@@ -3,7 +3,9 @@
* Argyll Color Correction System
*
* Gretag i1Monitor & i1Pro related functions
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -85,7 +87,7 @@ i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
i1pro *p = (i1pro *) pp;
int rsize, se;
icomuflags usbflags = icomuf_none;
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* If the X-Rite software has been installed, then there may */
/* be a daemon process that has the device open. Kill that process off */
/* so that we can open it here, before it re-spawns. */
@@ -95,10 +97,10 @@ i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
NULL
};
int retries = 20;
-#else /* !__APPLE__ */
+#else /* !UNIX_APPLE */
char **pnames = NULL;
int retries = 0;
-#endif /* !__APPLE__ */
+#endif /* !UNIX_APPLE */
a1logd(p->log, 2, "i1pro_init_coms: called\n");
@@ -238,7 +240,7 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
if (!p->inited)
return inst_no_init;
- rv = i1pro_imp_measure(p, vals, npatch, 1);
+ rv = i1pro_imp_measure(p, vals, npatch, instClamp);
return i1pro_interp_code(p, rv);
}
@@ -328,6 +330,7 @@ static inst_code i1pro_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) */
) {
i1pro *p = (i1pro *)pp;
@@ -338,7 +341,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- rv = i1pro_imp_calibrate(p, calt, calc, id);
+ rv = i1pro_imp_calibrate(p, calt, calc, idtype, id);
return i1pro_interp_code(p, rv);
}
@@ -385,8 +388,10 @@ i1pro_interp_error(inst *pp, i1pro_code ec) {
return "EEProm key is the wrong type";
case I1PRO_DATA_KEY_CORRUPT:
return "EEProm key table seems to be corrupted";
- case I1PRO_DATA_KEY_COUNT:
- return "EEProm key table count is too big or small";
+ case I1PRO_DATA_KEY_COUNT_SMALL:
+ return "EEProm key table size is too small for expected number of keys";
+ case I1PRO_DATA_KEY_COUNT_LARGE:
+ return "EEProm key table size is too large for expected number of keys";
case I1PRO_DATA_KEY_UNKNOWN:
return "EEProm unknown key type";
case I1PRO_DATA_KEY_MEMRANGE:
@@ -448,7 +453,7 @@ i1pro_interp_error(inst *pp, i1pro_code ec) {
case I1PRO_RD_TOOMANYPATCHES:
return "Too many patches";
case I1PRO_RD_NOTENOUGHSAMPLES:
- return "Not enough samples per patch";
+ return "Not enough samples per patch - Slow Down!";
case I1PRO_RD_NOFLASHES:
return "No flashes recognized";
case I1PRO_RD_NOAMBB4FLASHES:
@@ -557,11 +562,32 @@ i1pro_interp_code(i1pro *p, i1pro_code ec) {
case I1PRO_CAL_SETUP:
return inst_cal_setup | ec;
+ case I1PRO_DATA_COUNT:
+ case I1PRO_DATA_BUFSIZE:
+ case I1PRO_DATA_MAKE_KEY:
+ case I1PRO_DATA_MEMORY:
+ case I1PRO_DATA_KEYNOTFOUND:
+ case I1PRO_DATA_WRONGTYPE:
+ case I1PRO_DATA_KEY_CORRUPT:
+ case I1PRO_DATA_KEY_COUNT_SMALL:
+ case I1PRO_DATA_KEY_COUNT_LARGE:
+ case I1PRO_DATA_KEY_UNKNOWN:
+ case I1PRO_DATA_KEY_MEMRANGE:
+ case I1PRO_DATA_KEY_ENDMARK:
+
case I1PRO_HW_HIGHPOWERFAIL:
+ case I1PRO_HW_EE_SIZE:
case I1PRO_HW_EE_SHORTREAD:
+ case I1PRO_HW_EE_SHORTWRITE:
case I1PRO_HW_ME_SHORTREAD:
case I1PRO_HW_ME_ODDREAD:
+ case I1PRO_HW_SW_SHORTREAD:
+ case I1PRO_HW_LED_SHORTWRITE:
+ case I1PRO_HW_UNEX_SPECPARMS:
case I1PRO_HW_CALIBINFO:
+ case I1PRO_WL_TOOLOW:
+ case I1PRO_WL_SHAPE:
+ case I1PRO_WL_ERR2BIG:
return inst_hardware_fail | ec;
case I1PRO_RD_DARKREADINCONS:
@@ -718,8 +744,7 @@ static inst_code i1pro_set_mode(inst *pp, inst_mode m) {
* error if it hasn't been initialised.
*/
static inst_code
-i1pro_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1pro_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1pro *p = (i1pro *)pp;
if (m == inst_opt_initcalib) { /* default */
@@ -785,6 +810,81 @@ i1pro_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ imp->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (imp->target_calstd == xcalstd_native)
+ *standard = imp->native_calstd; /* If not overridden */
+ else
+ *standard = imp->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
+ /* Return the white calibration tile spectrum */
+ /* (We always return the normal rez. reference values) */
+ if (m == inst_opt_get_cal_tile_sp) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xspect *sp;
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ if (imp->white_ref[0] == NULL)
+ return inst_no_init;
+
+ sp->spec_n = imp->nwav[0];
+ sp->spec_wl_short = imp->wl_short[0];
+ sp->spec_wl_long = imp->wl_long[0];
+ sp->norm = 100.0;
+
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] = imp->white_ref[0][i] * 100.0;
+
+ return inst_ok;
+ }
+
+ /* Lamp drift remediation */
+ if (m == inst_opt_lamp_remediate) {
+ i1pro_code ev;
+ va_list args;
+ double seconds;
+
+ va_start(args, m);
+ seconds = va_arg(args, double);
+ va_end(args);
+
+ ev = i1pro_imp_lamp_fix(p, seconds);
+
+ return i1pro_interp_code(p, ev);
+ }
+
/* Use default implementation of other inst_opt_type's */
{
inst_code rv;
diff --git a/spectro/i1pro.h b/spectro/i1pro.h
index 4366e4f..e449f2c 100644
--- a/spectro/i1pro.h
+++ b/spectro/i1pro.h
@@ -4,7 +4,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro related defines
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -15,6 +17,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
If you make use of the instrument driver code here, please note
that it is the author(s) of the code who take responsibility
@@ -52,5 +58,9 @@ struct _i1pro {
/* Constructor */
extern i1pro *new_i1pro(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define I1PRO_H
#endif /* I1PRO_H */
diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c
index 8577f8c..a8cb9e0 100644
--- a/spectro/i1pro_imp.c
+++ b/spectro/i1pro_imp.c
@@ -3,7 +3,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro implementation functions
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -34,6 +36,10 @@
/* TTBD:
+ Would be nice to have option to save raw scan data to .ti3 file,
+ and then have a utility/option to replay it through scan
+ recognition, to be able to help remote diagnose scan problems.
+
Some things probably aren't quite correct:
The way the sensor saturation and optimal target is
computed probably doesn't account for the dark level
@@ -46,9 +52,6 @@
(see i1d3.c). Whether this will noticably improve repeatibility
remains to be seen.
- Would be nice to have option to save raw scan data to .ti3 file,
- and then have a utility/option to replay it through scan
- recognition, to be able to help remote diagnose scan problems.
*/
/*
@@ -112,7 +115,7 @@
#define DCALTOUT2 ( 1 * 60 * 60) /* [1 Hr] i1pro2 Dark Calibration timeout in seconds */
#define WCALTOUT ( 1 * 60 * 60) /* [1 Hr] White Calibration timeout in seconds */
-#define MAXSCANTIME 20.0 /* [20] Maximum scan time in seconds */
+#define MAXSCANTIME 30.0 /* [30] Maximum scan time in seconds */
#define SW_THREAD_TIMEOUT (10 * 60.0) /* [10 Min] Switch read thread timeout */
#define SINGLE_READ /* [Def] Use a single USB read for scan to eliminate latency issues. */
@@ -131,6 +134,7 @@
#undef TEST_DARK_INTERP /* Test out the dark interpolation (need DEBUG for plot) */
#undef PATREC_DEBUG /* Print & Plot patch/flash recognition information */
#undef PATREC_ALLBANDS /* Plot all bands of scan */
+#undef PATREC_SAVETRIMMED /* Saved trimmed raw to file "i1pro_raw_trimed_N.csv */
#undef IGNORE_WHITE_INCONS /* Ignore define reference reading inconsistency */
#undef HIGH_RES_DEBUG
#undef HIGH_RES_PLOT
@@ -138,8 +142,8 @@
#undef PLOT_BLACK_SUBTRACT /* Plot temperature corrected black subtraction */
#undef FAKE_AMBIENT /* Fake the ambient mode for a Rev A */
-#define MATCH_SPOT_OMD /* [Def] Match Original Manufacturers Driver. Reduce */
- /* integration time and lamp turn on time */
+#undef USE_SPOT_OMD /* [Und] Use Original Manufacturers Driver timing. Reduce */
+ /* integration time and lamp turn on time. */
#define DISP_INTT 2.0 /* Seconds per reading in display spot mode */
/* More improves repeatability in dark colors, but limits */
@@ -171,6 +175,7 @@
#include "i1pro.h"
#include "i1pro_imp.h"
+#include "xrga.h"
/* - - - - - - - - - - - - - - - - - - */
#define LAMP_OFF_TIME 1500 /* msec to make sure lamp is dark for dark measurement */
@@ -448,9 +453,26 @@ i1pro_code i1pro_imp_init(i1pro *p) {
i1pro_code ev = I1PRO_OK;
unsigned char *eeprom; /* EEProm contents, i1pro = half, i1pro2 = full */
int len = 8192;
+ char *envv;
a1logd(p->log,5,"i1pro_init:\n");
+ m->native_calstd = xcalstd_gmdi; /* Rev A-D */
+ if (p->itype == instI1Pro2) {
+ m->native_calstd = xcalstd_xrga; /* Rev E */
+ }
+ m->target_calstd = xcalstd_native; /* Default to native calibration */
+
+ /* Honor Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ m->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ m->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ m->target_calstd = xcalstd_gmdi;
+ }
+
/* Revert to i1pro if i1pro2 driver is not enabled */
if (p->itype == instI1Pro2
#ifdef ENABLE_2
@@ -1006,22 +1028,27 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->dadaptime = 0.10;
s->wadaptime = 0.10;
-#ifdef MATCH_SPOT_OMD
- s->lamptime = 0.18; /* Lamp turn on time, close to OMD */
- /* (Not ideal, but partly compensated by calib.) */
- /* (The actual value the OMD uses is 0.20332) */
- s->dcaltime = 0.05; /* Longer than the original driver for lower */
- /* noise, and lamptime has been reduces to */
- /* compensate. (OMD uses 0.014552) */
- s->wcaltime = 0.05;
- s->dreadtime = 0.05;
- s->wreadtime = 0.05;
+#ifdef USE_SPOT_OMD
+ s->lamptime = 0.20332; /* (Lamp doesn't stabilize with this) */
+ s->dcaltime = 0.02366;
+ s->wcaltime = 0.02366;
+ s->dreadtime = 0.02366;
+ s->wreadtime = 0.02366;
#else
- s->lamptime = 0.5; /* This should give better accuracy, and better */
- s->dcaltime = 0.5; /* match the scan readings. Difference is about */
- s->wcaltime = 0.5; /* 0.1 DE though, but would be lost in the */
- s->dreadtime = 0.5; /* repeatability noise... */
- s->wreadtime = 0.5;
+#ifndef NEVER
+ s->lamptime = 0.25; /* This should give better accuracy */
+ s->dcaltime = 0.05; /* without increasing lamp usage much. */
+ s->wcaltime = 0.05; /* Make it too large (ie. 1.0 sec total) */
+ s->dreadtime = 0.05; /* and it will dirty the i1pro2 lamp quickly */
+ s->wreadtime = 0.05; /* though. */
+#else
+# pragma message("######### i1pro_imp.c Dirty Lamp timing !!!!! ########")
+ s->lamptime = 0.5; /* Dirty up the lamp. */
+ s->dcaltime = 2.0;
+ s->wcaltime = 2.0;
+ s->dreadtime = 2.0;
+ s->wreadtime = 2.0;
+#endif
#endif
s->maxscantime = 0.0;
s->min_wl = HIGHRES_REF_MIN;/* Too much stray light below this */
@@ -1037,13 +1064,12 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->targoscale = 0.25;
else
s->targoscale = 0.5;
-
- s->lamptime = 0.5; /* Lamp turn on time - lots to match scan */
+ s->lamptime = 0.5; /* Lamp turn on time - lots to match scan */
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 0.5;
- s->wcaltime = 0.5;
- s->dreadtime = 0.10;
+ s->wcaltime = 2.5; /* Lots to get lamp up to temp */
+ s->dreadtime = 0.10; /* and to match OMD scan cal. on time */
s->wreadtime = 0.10;
s->maxscantime = MAXSCANTIME;
s->min_wl = HIGHRES_REF_MIN; /* Too much stray light below this */
@@ -1058,7 +1084,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->adaptive = 0;
s->inttime = DISP_INTT; /* Default disp integration time (ie. 2.0 sec) */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
s->dark_int_time2 = DISP_INTT2; /* Alternate disp integration time (ie. 0.8) */
s->dark_int_time3 = DISP_INTT3; /* Alternate disp integration time (ie. 0.3) */
@@ -1083,7 +1109,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->emiss = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.0;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1100,7 +1126,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->scan = 1;
s->adaptive = 1; /* ???? */
s->inttime = m->min_int_time; /* Maximize scan rate */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
if (m->fwrev >= 301)
s->targoscale = 0.25; /* (We're not using scan targoscale though) */
@@ -1132,7 +1158,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->ambient = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.0;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1161,7 +1187,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->flash = 1;
s->inttime = m->min_int_time; /* Maximize scan rate */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
if (m->fwrev >= 301)
s->targoscale = 0.25; /* (We're not using scan targoscale though) */
@@ -1181,7 +1207,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->trans = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1202,7 +1228,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
else
s->targoscale = 0.5;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1483,6 +1509,7 @@ i1pro_code i1pro_imp_calibrate(
i1pro *p,
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) */
) {
i1pro_code ev = I1PRO_OK;
@@ -2250,6 +2277,16 @@ i1pro_code i1pro_imp_calibrate(
s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
s->cal_factor[1], m->white_ref[1], s->cal_factor[1],
!s->scan); /* Use this for emis hires fine tune if not scan */
+
+ /* Print white lamp magnitude to track lamp darkening */
+ if (p->log != NULL && p->log->debug >= 1) {
+ double sum = 0.0;
+ for (i = 0; i < m->nwav[0]; i++)
+ sum += 1.0/s->cal_factor[0][i];
+
+ a1logd(p->log,1,"Refl. lamp magnitude = %e\n",sum);
+ }
+
if (ev == I1PRO_RD_TRANSWHITEWARN) /* Shouldn't happen ? */
ev = I1PRO_OK;
if (ev != I1PRO_OK) {
@@ -2365,7 +2402,8 @@ i1pro_code i1pro_imp_calibrate(
/* Do ref_white first in case we are doing a high res fine tune. */
if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) {
- sprintf(id, "Serial no. %d",m->serno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",m->serno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) {
/* Calibrate using white tile */
*calc = inst_calc_man_ref_white;
@@ -2373,6 +2411,7 @@ i1pro_code i1pro_imp_calibrate(
}
} else if (*calt & inst_calt_wavelength) { /* Wavelength calibration */
if (cs->emiss && cs->ambient) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_am_dark) {
/* Calibrate using ambient adapter */
@@ -2380,7 +2419,8 @@ i1pro_code i1pro_imp_calibrate(
return I1PRO_CAL_SETUP;
}
} else {
- sprintf(id, "Serial no. %d",m->serno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",m->serno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) {
/* Calibrate using white tile */
*calc = inst_calc_man_ref_white;
@@ -2388,6 +2428,7 @@ i1pro_code i1pro_imp_calibrate(
}
}
} else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) {
/* Any sort of dark reference */
@@ -2395,18 +2436,21 @@ i1pro_code i1pro_imp_calibrate(
return I1PRO_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_dark) { /* Transmissvice dark */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_dark) {
*calc = inst_calc_man_trans_dark;
return I1PRO_CAL_SETUP;
}
} else 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;
return I1PRO_CAL_SETUP;
}
} else if (*calt & inst_calt_emis_int_time) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) {
*calc = inst_calc_emis_white;
@@ -2438,10 +2482,13 @@ i1pro_code i1pro_imp_calibrate(
if (m->transwarn) {
*calc = inst_calc_message;
- if (m->transwarn & 2)
+ if (m->transwarn & 2) {
+ *idtype = inst_calc_id_trans_low;
strcpy(id, "Warning: Transmission light source is too low for accuracy!");
- else
+ } else {
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ }
m->transwarn = 0;
}
@@ -2458,6 +2505,51 @@ int icoms2i1pro_err(int se) {
}
/* - - - - - - - - - - - - - - - - */
+/* Do a dummy reflective read, to fix Lamp Drift. */
+
+i1pro_code i1pro_imp_lamp_fix(
+i1pro *p,
+double seconds) { /* Number of seconds to turn lamp on for */
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ int nummeas;
+ double inttime;
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ i1p_mode cmode = m->mmode; /* Remember current mode */
+
+ if (seconds > (5 * 60.0)) {
+ a1loge(p->log, inst_internal_error, "i1pro_imp_lamp_fix %f sec is too long\n",seconds);
+ return I1PRO_INT_ASSERT;
+ }
+
+ m->mmode = i1p_refl_spot; /* Override current mode */
+ inttime = 0.2; /* Constrain buffer size */
+ nummeas = (int)(seconds/inttime + 0.5);
+ bsize = m->nsen * 2 * nummeas; /* 16 bit raw values */
+
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ m->mmode = cmode;
+ a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Trigger measure and gather raw readings */
+ a1logd(p->log, 1, "i1pro_imp_lamp_fix %f seconds\n",seconds);
+ if ((ev = i1pro_read_patches_1(p, nummeas, nummeas, &inttime, 0,
+ NULL, buf, bsize)) != I1PRO_OK) {
+ m->mmode = cmode;
+ free(buf);
+ return ev;
+ }
+
+ m->mmode = cmode;
+ free(buf);
+
+ return I1PRO_OK;
+}
+
+/* - - - - - - - - - - - - - - - - */
/* Measure a display update delay. It is assumed that */
/* white_stamp(init) has been called, and then a */
/* white to black change has been made to the displayed color, */
@@ -2519,7 +2611,7 @@ int *pinstmsec) { /* Return instrument latency in msec */
}
if (m->whitestamp < 0.0) {
- a1logd(p->log, 1, "i1d3_meas_delay: White transition wasn't timestamped\n");
+ a1logd(p->log, 1, "i1pro_meas_delay: White transition wasn't timestamped\n");
return inst_internal_error;
}
@@ -2940,8 +3032,13 @@ i1pro_code i1pro_imp_measure(
/* Indicate to the user that they can now scan the instrument, */
/* after a little delay that allows for the instrument reaction time. */
if (s->scan) {
- /* 500msec delay, 1KHz for 200 msec */
- msec_beep(200 + (int)(s->lamptime * 1000.0 + 0.5), 1000, 200);
+ int delay = 200 + (int)(s->lamptime * 1000.0 + 0.5);
+ if (p->eventcallback != NULL) {
+ issue_scan_ready((inst *)p, delay);
+ } else {
+ /* delay then 1KHz for 200 msec */
+ msec_beep(delay, 1000, 200);
+ }
}
/* Retry loop for certaing cases */
@@ -4121,6 +4218,7 @@ i1pro_code i1pro_save_calibration(i1pro *p) {
i1pnonv x;
int ss;
int argyllversion = ARGYLL_VERSION;
+ int isRevE = p->itype == instI1Pro2 ? 1 : 0;
strcpy(nmode, "w");
#if !defined(O_CREAT) && !defined(_O_CREAT)
@@ -4157,6 +4255,7 @@ i1pro_code i1pro_save_calibration(i1pro *p) {
write_ints(&x, fp, &argyllversion, 1);
write_ints(&x, fp, &ss, 1);
write_ints(&x, fp, &m->serno, 1);
+ write_ints(&x, fp, &isRevE, 1);
write_ints(&x, fp, (int *)&m->nraw, 1);
write_ints(&x, fp, (int *)&m->nwav[0], 1);
write_ints(&x, fp, (int *)&m->nwav[1], 1);
@@ -4242,6 +4341,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
FILE *fp;
i1pnonv x;
int argyllversion;
+ int isRevE;
int ss, serno, nraw, nwav0, nwav1, nbytes, chsum1, chsum2;
strcpy(nmode, "r");
@@ -4286,6 +4386,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_ints(&x, fp, &argyllversion, 1);
read_ints(&x, fp, &ss, 1);
read_ints(&x, fp, &serno, 1);
+ read_ints(&x, fp, &isRevE, 1);
read_ints(&x, fp, &nraw, 1);
read_ints(&x, fp, &nwav0, 1);
read_ints(&x, fp, &nwav1, 1);
@@ -4293,6 +4394,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
|| argyllversion != ARGYLL_VERSION
|| ss != (sizeof(i1pro_state) + sizeof(i1proimp))
|| serno != m->serno
+ || isRevE != (p->itype == instI1Pro2 ? 1 : 0)
|| nraw != m->nraw
|| nwav0 != m->nwav[0]
|| nwav1 != m->nwav[1]) {
@@ -4398,6 +4500,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_ints(&x, fp, &argyllversion, 1);
read_ints(&x, fp, &ss, 1);
read_ints(&x, fp, &m->serno, 1);
+ read_ints(&x, fp, &isRevE, 1);
read_ints(&x, fp, (int *)&m->nraw, 1);
read_ints(&x, fp, (int *)&m->nwav[0], 1);
read_ints(&x, fp, (int *)&m->nwav[1], 1);
@@ -5323,6 +5426,7 @@ i1pro_code i1pro_read_patches_2(
} else {
a1logd(p->log,3,"Number of patches measured = %d\n",nmeasuered);
+{
/* Recognise the required number of ref/trans patch locations, */
/* and average the measurements within each patch. */
if ((ev = i1pro_extract_patches_multimeas(p, &rv, absraw, numpatches, multimes,
@@ -5332,6 +5436,7 @@ i1pro_code i1pro_read_patches_2(
a1logd(p->log,2,"i1pro_read_patches_2 spot read failed at i1pro_extract_patches_multimeas\n");
return ev;
}
+}
}
}
free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
@@ -5532,7 +5637,7 @@ i1pro_code i1pro_read_patches_all(
unsigned int bsize;
int rv = 0;
- bsize = m->nsen * 2 * numpatches;
+ bsize = m->nsen * 2 * numpatches; /* 16 bit raw values */
if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
return I1PRO_INT_MALLOC;
@@ -5711,6 +5816,11 @@ i1pro_trigger_one_measure(
int measmodeflags; /* Measurement mode command flags */
int measmodeflags2; /* Rev E Measurement mode command flags */
+ /* Sanity check in case bad value was restored, due to switch */
+ /* from Rev A-D to Rev E mode. */
+ if (*inttime < m->min_int_time)
+ *inttime = m->min_int_time;
+
/* The Rev E measure mode has it's own settings */
if (p->itype == instI1Pro2) {
m->intclkp = m->intclkp2; /* From i1pro2_getmeaschar() ? */
@@ -6378,7 +6488,7 @@ i1pro_code i1pro_extract_patches_multimeas(
#ifdef PATREC_DEBUG
/* Plot out 6 lots of 8 values each */
- plot = dmatrixz(0, 8, 0, nummeas-1);
+ plot = dmatrixz(0, 11, 0, nummeas-1);
// for (j = 45; j <= (m->nraw-8); j += 100) /* Do just one band */
#ifdef PATREC_ALLBANDS
for (j = 0; j <= (m->nraw-8); j += 8) /* Plot all the bands */
@@ -6500,7 +6610,6 @@ i1pro_code i1pro_extract_patches_multimeas(
/* to skew slightly towards the center */
for (k = 0; k < FW; k++) {
double wt;
-
wt = fabs(2.0 * k - (FW -1.0))/(FW-1.0);
dev[k] += wt * bdev;
}
@@ -6689,6 +6798,7 @@ i1pro_code i1pro_extract_patches_multimeas(
break;
pat[npat].no++;
}
+
avglegth += (double) pat[npat].no;
npat++;
}
@@ -6812,20 +6922,80 @@ i1pro_code i1pro_extract_patches_multimeas(
a1logd(p->log,7,"Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
}
- /* Now trim the patches simply by shrinking their windows */
+#ifdef NEVER /* [Und] - doesn't seem as good for normal patch sizes. */
+ /* Now trim the patches by expanding the spacers/transitions */
for (k = 1; k < (npat-1); k++) {
- int nno, trim;
+ int sw, xsw, trim;
if (pat[k].use == 0)
continue;
+
+printf("Patch %d @ %d len %d ->",k,pat[k].ss,pat[k].no);
+ /* Figure the previous spacer width */
+ sw = pat[k].ss - (pat[k-1].ss + pat[k-1].no);
+ xsw = (sw * 170 + 85)/100; /* Expand spacer by 170% */
+ trim = (xsw - sw + 1)/2; /* Move start of patch half that expansion */
+ pat[k].ss += trim;
+ pat[k].no -= trim;
+
+ /* Figure the next spacer width */
+ sw = pat[k+1].ss - (pat[k].ss + pat[k].no);
+ xsw = (sw * 170 + 85)/100; /* Expand spacer by 170% */
+ trim = (xsw - sw + 1)/2; /* Move end of patch half that expansion */
+ pat[k].no -= trim;
+
+ if (pat[k].no < 0)
+ pat[k].no = 0;
+printf(" @ %d len %d\n",pat[k].ss,pat[k].no);
+ }
+#else
+ /* Now trim the patches by shrinking their windows */
+ for (k = 1; k < (npat-1); k++) {
+ int nno, trim;
+ if (pat[k].use == 0)
+ continue;
- nno = (pat[k].no * 3)/4;
- trim = (pat[k].no - nno)/2;
+// nno = (pat[k].no * 3 + 0)/4; /* Trim to 75% & round down */
+ nno = (pat[k].no * 2 + 0)/3; /* Trim to 66% & round down [def] */
+// nno = (pat[k].no * 2 + 0)/4; /* Trim to 50% & round down */
+ trim = (pat[k].no - nno + 1)/2;
pat[k].ss += trim;
pat[k].no = nno;
}
+#endif
+
+#ifdef PATREC_SAVETRIMMED /* Save debugging file */
+ {
+ static int filen = 0; /* Debug file index */
+ char fname[100];
+ FILE *fp;
+
+ sprintf(fname, "i1pro_raw_trimed_%d.csv",filen++);
+
+ if ((fp = fopen(fname, "w")) == NULL)
+ error("Unable to open debug output file '%'",fname);
+
+ /* Create fake "slope" value that marks patches */
+ for (i = 0; i < nummeas; i++)
+ slope[i] = 1.0;
+ for (k = 1; k < (npat-1); k++) {
+ if (pat[k].use == 0)
+ continue;
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++)
+ slope[i] = 0.0;
+ }
+
+ for (i = 0; i < nummeas; i++) {
+ fprintf(fp, "%f\t",slope[i]);
+ for (j = 0; j < m->nraw; j++)
+ fprintf(fp, "%f\t", multimeas[i][j]/maxval[j]);
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+ }
+#endif
#ifdef PATREC_DEBUG
a1logd(p->log,7,"After trimming got:\n");
@@ -6846,6 +7016,17 @@ i1pro_code i1pro_extract_patches_multimeas(
}
printf("Trimmed output:\n");
+#ifdef PATREC_ALLBANDS
+ for (j = 0; j <= (m->nraw-9); j += 9) { /* Plot all the bands, 9 at a time */
+ for (i = 0; i < nummeas; i++) {
+ for (k = 0; k < 9; k++)
+ plot[k][i] = multimeas[i][j+k]/maxval[j+k];
+ plot[10][i] = (double)i;
+ }
+ printf("Bands %d - %d\n",j,j+9);
+ do_plot10(plot[10], slope, plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], plot[6], plot[7], plot[8], nummeas, 0);
+ }
+#else
for (i = 0; i < nummeas; i++) {
int jj;
for (jj = 0, j = b_lo; jj < 6 && j < b_hi; jj++, j += ((b_hi-b_lo)/6)) {
@@ -6856,8 +7037,9 @@ i1pro_code i1pro_extract_patches_multimeas(
}
}
for (i = 0; i < nummeas; i++)
- plot[6][i] = (double)i;
- do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+ plot[10][i] = (double)i;
+ do_plot6(plot[10], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif
#endif /* PATREC_DEBUG */
#ifdef PATREC_DEBUG
@@ -7884,6 +8066,8 @@ i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw) {
/* given the current wl_led_off, and set them as current, */
/* using triangular filters of the lagrange interpolation of the */
/* CCD values (i.e. the same type of filter used by the OEM driver) */
+/* [ Interestingly, the resulting filter shape is a bit like lanczos2, */
+/* but not identical. ] */
i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
i1proimp *m = (i1proimp *)p->m;
i1pro_state *s = &m->ms[m->mmode];
@@ -7979,6 +8163,12 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
wlcop[i] = 0.0;
/* for each Lagrange interpolation position (adjacent CCD locations) */
+ /* create the Lagrange and then accuumulate the integral of the convolution */
+ /* of the overlap of the central region, with the triangle of our */
+ /* underlying re-sampling filter. */
+ /* (If we were to run out of enough source points for the Lagrange to */
+ /* encompas the region, then in theory we could use the Lagrange to */
+ /* extrapolate beyond the end from points within.) */
for (lip = six; (lip + 3) < eix; lip++) {
double rwav[4]; /* Relative wavelength of these Lagrange points */
double den[4]; /* Denominator values for points */
@@ -8032,6 +8222,7 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
ihigh = rwav[1];
ilow = rwav[2];
+ /* Over just the central portion, if it overlaps the triangle. */
if ((k == 0 && ilow <= twidth && ihigh >= 0.0) /* Portion is +ve side */
|| (k == 1 && ilow <= 0.0 && ihigh >= -twidth)) { /* Portion is -ve side */
@@ -8186,6 +8377,8 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
#define DO_CCDNORMAVG /* [und ???] Normalise averages rather than per CCD bin */
/* (We relly on fine cal & white cal to fix it) */
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
#undef COMPUTE_DISPERSION /* Compute slit & optics dispersion from red laser data */
#ifdef NEVER
@@ -8219,7 +8412,7 @@ static void i1pro_debug_plot_mtx_coef(i1pro *p) {
do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
free_dvector(xx, -1, m->nraw-1);
- free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 5, -1, m->nraw-1);
}
#endif /* NEVER */
@@ -9540,7 +9733,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
w1 = i1pro_raw2wav(p, refl, (double)i - 0.5);
w2 = i1pro_raw2wav(p, refl, (double)i + 0.5);
-// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
+// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
/* For each filter */
for (j = 0; j < m->nwav[1]; j++) {
@@ -9554,6 +9747,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
+#ifdef BOX_INTEGRATE
/* Integrate in 0.05 nm increments from filter shape */
/* using triangular integration. */
{
@@ -9582,6 +9776,9 @@ i1pro_code i1pro_create_hr(i1pro *p) {
lw = cw;
}
}
+#else
+ we = fabs(w2 - w1) * lanczos2(twidth, rwl);
+#endif
if (m->mtx_c[1][refl].nocoef[j] >= MXNOFC) {
a1logw(p->log, "i1pro: run out of high res filter space\n");
@@ -9943,7 +10140,7 @@ i1pro_code i1pro_set_scan_toll(i1pro *p, double toll_ratio) {
}
-/* Optics adjustment weights */
+/* Optical adjustment weights */
static double opt_adj_weights[21] = {
1.4944496665144658e-282, 2.0036175483913455e-070, 1.2554893022685038e+232,
2.3898157055642966e+190, 1.5697625128432372e-076, 6.6912978722191457e+281,
@@ -9954,7 +10151,8 @@ static double opt_adj_weights[21] = {
9.2709981544886391e+122, 3.7958270103353899e-153, 7.1366083837501666e-154
};
-/* Convert from spectral to XYZ, and transfer to the ipatch array */
+/* Convert from spectral to XYZ, and transfer to the ipatch array. */
+/* Apply XRGA conversion if needed */
i1pro_code i1pro_conv2XYZ(
i1pro *p,
ipatch *vals, /* Values to return */
@@ -10062,6 +10260,10 @@ i1pro_code i1pro_conv2XYZ(
}
conv->del(conv);
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, nvals, xcalstd_nonpol, m->target_calstd, m->native_calstd, clamp);
+
return I1PRO_OK;
}
@@ -11383,6 +11585,7 @@ i1pro_setmcmode(
}
/* Hmm. Give the instrument a little time to reconfigure itself. */
+ /* (Probably needs about 1msec, but err on the safe side) */
msec_sleep(10);
a1logd(p->log,2,"i1pro_setmcmode: done, ICOM err 0x%x (%d msec)\n",
@@ -11727,7 +11930,7 @@ i1pro2_triggermeasure(i1pro *p, int delay) {
i1proimp *m = (i1proimp *)p->m;
int rv = I1PRO_OK;
- a1logd(p->log,2,"i1pro2_triggermeasure: triggering Rev Emeasurement after %dmsec "
+ a1logd(p->log,2,"i1pro2_triggermeasure: triggering Rev E measurement after %dmsec "
"delay @ %d msec\n", delay, msec_time() - m->msec);
/* NOTE := would be better here to create thread once, and then trigger it */
@@ -12512,6 +12715,8 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
i1pro *p = d->p;
int rv = I1PRO_OK;
int dir = 0x1000; /* Location of key directory */
+ int minkeys = 300; /* Expected minumum number of bytes for keys */
+ int maxkeys = 512; /* Expected maxumum number of bytes for keys */
int block_id; /* Block id */
int nokeys;
i1key key, off, nkey = 0, noff = 0;
@@ -12519,14 +12724,16 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
unsigned char *bp;
int i;
- if (extra)
+ if (extra) {
dir = 0x2000; /* Directory is at half way in i1pro2 2nd table */
+ minkeys = 200; /* Hmm. Had a report that the i1Pro2 failed to parse */
+ }
- a1logd(p->log,3,"i1pro_parse_eeprom called with %d bytes\n",len);
+ a1logd(p->log,3,"i1pro_parse_eeprom called with %d bytes, table %d\n",len,extra);
/* Room for minimum number of keys ? */
- if ((dir + 300) > len)
- return I1PRO_DATA_KEY_COUNT;
+ if ((dir + minkeys) > len)
+ return I1PRO_DATA_KEY_COUNT_SMALL;
block_id = buf2ushort(buf + dir);
if ((extra == 0 && block_id != 1) /* Must be 1 for base data */
@@ -12534,12 +12741,15 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
return I1PRO_DATA_KEY_CORRUPT;
nokeys = buf2ushort(buf + dir + 2); /* Bytes in key table */
- if (nokeys < 300 || nokeys > 512)
- return I1PRO_DATA_KEY_COUNT;
+ a1logd(p->log,3,"%d bytes for keys in EEProm table %d\n",nokeys, extra);
+ if (nokeys < minkeys)
+ return I1PRO_DATA_KEY_COUNT_SMALL;
+ if (nokeys > maxkeys)
+ return I1PRO_DATA_KEY_COUNT_LARGE;
nokeys = (nokeys - 4)/6; /* Number of 6 byte entries */
- a1logd(p->log,3,"%d key/values in EEProm table %d\n",nokeys, extra);
+ a1logd(p->log,3,"%d keys & values in EEProm table %d\n",nokeys, extra);
/* We need current and next value to figure data size out */
bp = buf + dir + 4;
diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h
index 5a2cef2..582cc98 100644
--- a/spectro/i1pro_imp.h
+++ b/spectro/i1pro_imp.h
@@ -4,7 +4,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro implementation defines
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 20/12/2006
*
@@ -15,6 +17,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
If you make use of the instrument driver code here, please note
that it is the author(s) of the code who take responsibility
@@ -182,6 +188,9 @@ struct _i1proimp {
int uv_en; /* NZ to do UV reflective measurement */
/* ~~ change this to uv_mode of none, uv, strip1, 2pass */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
double intclkp; /* Integration clock period (typically 68 usec) */
int subclkdiv; /* Sub clock divider ratio */
int subtmode; /* Reading 127 subtract mode (version 301 or greater) */
@@ -363,10 +372,11 @@ void del_i1proimp(i1pro *p);
#define I1PRO_DATA_KEYNOTFOUND 0x05 /* a key value wasn't found */
#define I1PRO_DATA_WRONGTYPE 0x06 /* a key is the wrong type */
#define I1PRO_DATA_KEY_CORRUPT 0x07 /* key table seems to be corrupted */
-#define I1PRO_DATA_KEY_COUNT 0x08 /* key table count is too big or small */
-#define I1PRO_DATA_KEY_UNKNOWN 0x09 /* unknown key type */
-#define I1PRO_DATA_KEY_MEMRANGE 0x0a /* key data is out of range of EEProm */
-#define I1PRO_DATA_KEY_ENDMARK 0x0b /* And end section marker was missing */
+#define I1PRO_DATA_KEY_COUNT_SMALL 0x08 /* key table count is too small */
+#define I1PRO_DATA_KEY_COUNT_LARGE 0x09 /* key table count is too big */
+#define I1PRO_DATA_KEY_UNKNOWN 0x0a /* unknown key type */
+#define I1PRO_DATA_KEY_MEMRANGE 0x0b /* key data is out of range of EEProm */
+#define I1PRO_DATA_KEY_ENDMARK 0x0c /* And end section marker was missing */
/* HW errors */
#define I1PRO_HW_HIGHPOWERFAIL 0x10 /* Switch to high power mode failed */
@@ -464,6 +474,7 @@ i1pro_code i1pro_imp_calibrate(
i1pro *p,
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[100] /* Condition identifier (ie. white reference ID) */
);
@@ -475,6 +486,12 @@ i1pro_code i1pro_imp_measure(
instClamping clamp /* Clamp XYZ/Lab to be +ve */
);
+/* Do a dummy reflective read, to fix Lamp Drift. */
+i1pro_code i1pro_imp_lamp_fix(
+ i1pro *p,
+ double seconds /* Number of seconds to turn lamp on for */
+);
+
/* Measure the emissive refresh rate */
i1pro_code i1pro_imp_meas_refrate(
i1pro *p,
@@ -1052,6 +1069,7 @@ i1pro2_getmeaschar(
#define I1PRO2_MMF_LAMP 0x0100 /* Use the Incandescent Lamp as the illuminant */
#define I1PRO2_MMF_UV_LED 0x0200 /* Use the Ultra Violet LED as the illuminant */
#define I1PRO2_MMF_WL_LED 0x0300 /* Use the Wavelength Reference LED as the illuminant */
+
//#define I1PRO2_MMF_HIGHGAIN 0x0000 /* Rev E mode has no high gain mode ? */
#define I1PRO2_MMF_SCAN 0x0001 /* Scan mode bit, else spot mode */
#define I1PRO2_MMF_RULER_START 0x0004 /* Start ruler tracking in scan mode */
@@ -1404,5 +1422,9 @@ struct _i1data {
/* Constructor. Construct from the EEprom contents */
extern i1data *new_i1data(i1proimp *m);
+#ifdef __cplusplus
+ }
+#endif
+
#define I1PRO_IMP
#endif /* I1PRO_IMP */
diff --git a/spectro/icoms.c b/spectro/icoms.c
index b69b72a..eadecc9 100644
--- a/spectro/icoms.c
+++ b/spectro/icoms.c
@@ -1,5 +1,5 @@
- /* General instrument + serial I/O support */
+/* General instrument + serial I/O support */
/*
* Argyll Color Correction System
@@ -71,29 +71,35 @@ static void icompath_del(icompath *p) {
free(p);
}
-/* Delete the last path */
+/* Delete the last combined path */
+/* (Assume this is before icompaths_make_dslists() has been called) */
static void icompaths_del_last_path(
icompaths *p
) {
- if (p->npaths == 0)
+ icom_dtix ix = dtix_combined;
+
+ if (p->ndpaths[ix] == 0)
return;
- icompath_del(p->paths[p->npaths-1]);
- p->paths[p->npaths-1] = NULL;
- p->npaths--;
+ icompath_del(p->dpaths[ix][p->ndpaths[ix]-1]);
+ p->dpaths[ix][p->ndpaths[ix]-1] = NULL;
+ p->ndpaths[ix]--;
}
-/* Return the last path */
+/* Return the last combined path */
+/* (Assume this is before icompaths_make_dslists() has been called) */
static icompath *icompaths_get_last_path(
icompaths *p
) {
- if (p->npaths == 0)
+ icom_dtix ix = dtix_combined;
+
+ if (p->ndpaths[ix] == 0)
return NULL;
- return p->paths[p->npaths-1];
+ return p->dpaths[ix][p->ndpaths[ix]-1];
}
-/* Return the path corresponding to the port number, or NULL if out of range */
+/* Return the instrument path corresponding to the port number, or NULL if out of range */
static icompath *icompaths_get_path(
icompaths *p,
int port /* Enumerated port number, 1..n */
@@ -103,80 +109,188 @@ static icompath *icompaths_get_path(
- if (port <= 0 || port > p->npaths)
+ if (port <= 0 || port > p->ndpaths[dtix_inst])
+ return NULL;
+
+ return p->dpaths[dtix_inst][port-1];
+}
+
+/* Return the device path corresponding to the port number, or NULL if out of range */
+static icompath *icompaths_get_path_sel(
+ icompaths *p,
+ icom_type dctype, /* Device type list */
+ int port /* Enumerated port number, 1..n */
+) {
+ /* Check it is an enumeration */
+ if (dctype != dtix_combined
+ && dctype != dtix_inst
+ && dctype != dtix_3dlut
+ && dctype != dtix_vtpg
+ && dctype != dtix_printer)
+ return NULL;
+
+ if (dctype == dtix_inst)
+ return icompaths_get_path(p, port);
+
+ if (port <= 0 || port > p->ndpaths[dctype])
return NULL;
- return p->paths[port-1];
+ return p->dpaths[dctype][port-1];
}
-static void icompaths_clear(icompaths *p) {
+/* Clear a single device paths list */
+static void icompaths_clear(icompaths *p, icom_dtix ix) {
- /* Free any old list */
- if (p != NULL && p->paths != NULL) {
+ if (p->dpaths[ix] != NULL) {
int i;
- for (i = 0; i < p->npaths; i++) {
- icompath_del(p->paths[i]);
+ /* If underlying owner of icompaths */
+ if (ix == dtix_combined) {
+ for (i = 0; i < p->ndpaths[ix]; i++) {
+ icompath_del(p->dpaths[ix][i]);
+ }
+ }
+ free(p->dpaths[ix]);
+ p->dpaths[ix] = NULL;
+ p->ndpaths[ix] = 0;
+
+ /* Clear instrument alias */
+ if (ix == dtix_inst) {
+ p->npaths = 0;
+ p->paths = NULL;
}
- free(p->paths);
- p->npaths = 0;
- p->paths = NULL;
}
}
-/* Add an empty new path. */
+/* Clear all device paths */
+static void icompaths_clear_all(icompaths *p) {
+
+ if (p == NULL)
+ return;
+
+ /* Free any old instrument list */
+ icompaths_clear(p, dtix_inst);
+ icompaths_clear(p, dtix_3dlut);
+ icompaths_clear(p, dtix_vtpg);
+ icompaths_clear(p, dtix_printer);
+ icompaths_clear(p, dtix_combined);
+}
+
+/* Add the give path to the given list. */
+/* If the path is NULL, allocat an empty */
+/* one and add it to the combined list */
/* Return icom error */
-static int icompaths_add_path(icompaths *p) {
- if (p->paths == NULL) {
- if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
+static int icompaths_add_path(icompaths *p, int ix, icompath *xp) {
+ if (xp == NULL)
+ ix = dtix_combined;
+ if (p->dpaths[ix] == NULL) {
+ if ((p->dpaths[ix] = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: calloc failed!\n");
return ICOM_SYS;
}
} else {
icompath **npaths;
- if ((npaths = (icompath **)realloc(p->paths,
- sizeof(icompath *) * (p->npaths + 2))) == NULL) {
+ if ((npaths = (icompath **)realloc(p->dpaths[ix],
+ sizeof(icompath *) * (p->ndpaths[ix] + 2))) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: realloc failed!\n");
return ICOM_SYS;
}
- p->paths = npaths;
- p->paths[p->npaths+1] = NULL;
+ p->dpaths[ix] = npaths;
+ p->dpaths[ix][p->ndpaths[ix]+1] = NULL;
}
- if ((p->paths[p->npaths] = calloc(sizeof(icompath), 1)) == NULL) {
- a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
- return ICOM_SYS;
+ if (xp == NULL) {
+ if ((xp = calloc(sizeof(icompath), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
+ return ICOM_SYS;
+ }
+ }
+ p->dpaths[ix][p->ndpaths[ix]] = xp;
+ p->ndpaths[ix]++;
+ p->dpaths[ix][p->ndpaths[ix]] = NULL;
+ return ICOM_OK;
+}
+
+/* Based on each icompath's dctype, create aliase lists for everything */
+/* on the combined path based on each device type. */
+/* (We are only called after clearing all lists) */
+int icompaths_make_dslists(icompaths *p) {
+ int rv, i;
+
+ for (i = 0; i < p->ndpaths[dtix_combined]; i++) {
+ icompath *xp = p->dpaths[dtix_combined][i];
+
+ if (xp == NULL)
+ break;
+
+ a1logd(g_log, 8, "icompaths_make_dslists '%s' dctype 0x%x\n",xp->name,xp->dctype);
+
+ if (xp->dctype & icomt_instrument) {
+ if ((rv = icompaths_add_path(p, dtix_inst, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_3dlut) {
+ if ((rv = icompaths_add_path(p, dtix_3dlut, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_vtpg) {
+ if ((rv = icompaths_add_path(p, dtix_vtpg, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_printer) {
+ if ((rv = icompaths_add_path(p, dtix_printer, xp)) != ICOM_OK)
+ return rv;
+ }
}
- p->npaths++;
- p->paths[p->npaths] = NULL;
+
+ /* Maintain backwards compatible instrument list alias */
+ p->npaths = p->ndpaths[dtix_inst];
+ p->paths = p->dpaths[dtix_inst];
+
return ICOM_OK;
}
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-/* Add a serial path */
+/* Add a serial path. */
/* return icom error */
-static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_ser_attr sattr) {
+static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_type dctype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, ix, NULL)) != ICOM_OK)
return rv;
-
- if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
+
+ a1logd(g_log, 8, "icompaths_add_serial got '%s' dctype 0x%x\n",name,dctype);
+
+ /* Type of port, port attributes, device category */
+ xp->dctype |= icomt_cat_any; /* Assume any for now */
+ xp->dctype |= icomt_serial;
+ xp->dctype |= icomt_seriallike;
+ xp->dctype |= dctype;
+
+ if ((xp->name = strdup(name)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- if ((p->paths[p->npaths-1]->spath = strdup(spath)) == NULL) {
+ if ((xp->spath = strdup(spath)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- p->paths[p->npaths-1]->sattr = sattr;
+
+ a1logd(g_log, 8, "icompaths_add_serial returning '%s' dctype 0x%x\n",xp->name,xp->dctype);
return ICOM_OK;
}
-/* Modify a serial path to add the instrument type */
-int icompaths_set_serial_itype(icompath *p, instType itype) {
+/* Modify a serial path to add the device type */
+int icompaths_set_serial_itype(icompath *p, devType itype) {
char pname[400], *cp;
+ /* Convert device type to category */
+ p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
+
p->itype = itype;
/* Strip any existing description in brackets */
@@ -190,6 +304,9 @@ int icompaths_set_serial_itype(icompath *p, instType itype) {
return ICOM_SYS;
}
free(cp);
+
+ a1logd(g_log, 8, "icompaths_set_serial_itype '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
@@ -197,60 +314,81 @@ int icompaths_set_serial_itype(icompath *p, instType itype) {
#ifdef ENABLE_USB
-/* Set an icompath details */
+/* Set an icompath details. */
/* return icom error */
static
int icompath_set_usb(a1log *log, icompath *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype) {
+ int nep, struct usb_idevice *usbd, devType itype) {
int rv;
+
if ((p->name = strdup(name)) == NULL) {
a1loge(log, ICOM_SYS, "icompath: strdup failed!\n");
return ICOM_SYS;
}
+ a1logd(g_log, 8, "icompath_set_usb '%s' got dctype 0x%x\n",p->name,p->dctype);
+
+ p->dctype |= icomt_usb;
+ p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
+
p->nep = nep;
p->vid = vid;
p->pid = pid;
p->usbd = usbd;
p->itype = itype;
+ a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
/* Add a usb path. usbd is taken, others are copied. */
/* return icom error */
static int icompaths_add_usb(icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype) {
+ int nep, struct usb_idevice *usbd, devType itype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
return rv;
- return icompath_set_usb(p->log, p->paths[p->npaths-1], name, vid, pid, nep, usbd, itype);
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
- return ICOM_OK;
+ return icompath_set_usb(p->log, xp, name, vid, pid, nep, usbd, itype);
}
/* Add an hid path. hidd is taken, others are copied. */
/* return icom error */
static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct hid_idevice *hidd, instType itype) {
+ int nep, struct hid_idevice *hidd, devType itype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
return rv;
- if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
+
+ a1logd(g_log, 8, "icompaths_add_hid '%s' got dctype 0x%x\n",xp->name,xp->dctype);
+
+ xp->dctype |= icomt_hid;
+ xp->dctype = (xp->dctype & ~icomt_cat_mask) | inst_category(itype);
+
+ if ((xp->name = strdup(name)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- p->paths[p->npaths-1]->nep = nep;
- p->paths[p->npaths-1]->vid = vid;
- p->paths[p->npaths-1]->pid = pid;
- p->paths[p->npaths-1]->hidd = hidd;
- p->paths[p->npaths-1]->itype = itype;
+ xp->nep = nep;
+ xp->vid = vid;
+ xp->pid = pid;
+ xp->hidd = hidd;
+ xp->itype = itype;
+
+ a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",xp->name,xp->dctype);
return ICOM_OK;
}
@@ -258,18 +396,115 @@ static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigne
static void icompaths_del(icompaths *p) {
if (p != NULL) {
- icompaths_clear(p);
+ icompaths_clear_all(p);
p->log = del_a1log(p->log); /* Unreference it and set to NULL */
free(p);
}
}
-int icompaths_refresh_paths(icompaths *p); /* Defined in platform specific */
+/* Create and return a list of available serial ports or USB devices for this system. */
+/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
+/* to determine serial ports, and use libusb to discover USB devices. */
+/* return icom error */
+int icompaths_refresh_paths_sel(icompaths *p, icom_type mask) {
+ int rv, usbend = 0;
+ int i, j;
+
+ a1logd(p->log, 7, "icoms_refresh_paths: called with mask = %d\n",mask);
+
+ /* Clear any existing device paths */
+ p->clear(p);
+
+#ifdef ENABLE_USB
+ if (mask & icomt_hid) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for HID device\n");
+ if ((rv = hid_get_paths(p)) != ICOM_OK)
+ return rv;
+ }
+ if (mask & icomt_usb) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for USB device\n");
+ if ((rv = usb_get_paths(p)) != ICOM_OK)
+ return rv;
+ }
+ usbend = p->ndpaths[dtix_combined];
+ a1logd(p->log, 6, "icoms_refresh_paths: now got %d paths\n",usbend);
+#endif /* ENABLE_USB */
+
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for serial ports\n");
+ if ((rv = serial_get_paths(p, mask)) != ICOM_OK)
+ return rv;
+
+ }
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL */
+
+ /* Sort the COM keys so people don't get confused... */
+ /* Sort identified instruments ahead of unknown serial ports */
+ a1logd(p->log, 6, "icoms_refresh_paths: we now have %d devices and are about to sort them\n",p->ndpaths[dtix_combined]);
+
+ {
+ icompath **pl = p->dpaths[dtix_combined];
+ int np = p->ndpaths[dtix_combined];
+
+ for (i = usbend; i < (np-1); i++) {
+ for (j = i+1; j < np; j++) {
+ if ((pl[i]->itype == instUnknown && pl[j]->itype != instUnknown)
+ || (((pl[i]->itype == instUnknown && pl[j]->itype == instUnknown)
+ || (pl[i]->itype != instUnknown && pl[j]->itype != instUnknown))
+ && strcmp(pl[i]->name, pl[j]->name) > 0)) {
+ icompath *tt = pl[i];
+ pl[i] = pl[j];
+ pl[j] = tt;
+ }
+ }
+ }
+ }
+
+ /* Create the device specific lists */
+ if ((rv = icompaths_make_dslists(p)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_refresh_paths: icompaths_make_dslists failed with %d\n",rv);
+ return rv;
+ }
+
+ a1logd(p->log, 8, "icoms_refresh_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
+
+ return ICOM_OK;
+}
+
+/* (In implementation specific) */
+int serial_is_open(icoms *p);
+void serial_close_port(icoms *p);
+
+/* Close the port */
+static void icoms_close_port(icoms *p) {
+ if (p->is_open) {
+#ifdef ENABLE_USB
+ if (p->usbd) {
+ usb_close_port(p);
+ } else if (p->hidd) {
+ hid_close_port(p);
+ }
+#endif
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ if (serial_is_open(p)) {
+ serial_close_port(p);
+ }
+#endif /* ENABLE_SERIAL */
+ p->is_open = 0;
+ }
+}
+
+int icompaths_refresh_paths(icompaths *p) {
+ return icompaths_refresh_paths_sel(p, icomt_instrument | icomt_portattr_all);
+}
/* Allocate an icom paths and set it to the list of available devices */
+/* that match the icom_type mask. */
/* Return NULL on error */
-icompaths *new_icompaths(a1log *log) {
+icompaths *new_icompaths_sel(a1log *log, icom_type mask) {
icompaths *p;
if ((p = (icompaths *)calloc(sizeof(icompaths), 1)) == NULL) {
a1loge(log, ICOM_SYS, "new_icompath: calloc failed!\n");
@@ -278,11 +513,14 @@ icompaths *new_icompaths(a1log *log) {
p->log = new_a1log_d(log);
- p->clear = icompaths_clear;
+ p->clear = icompaths_clear_all;
p->refresh = icompaths_refresh_paths;
- p->del_last_path = icompaths_del_last_path;
- p->get_last_path = icompaths_get_last_path;
+ p->refresh_sel = icompaths_refresh_paths_sel;
p->get_path = icompaths_get_path;
+ p->get_path_sel = icompaths_get_path_sel;
+ p->del = icompaths_del;
+
+ /* ====== internal implementation ======= */
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
p->add_serial = icompaths_add_serial;
#endif /* ENABLE_SERIAL */
@@ -290,9 +528,11 @@ icompaths *new_icompaths(a1log *log) {
p->add_usb = icompaths_add_usb;
p->add_hid = icompaths_add_hid;
#endif /* ENABLE_USB */
- p->del = icompaths_del;
+ p->del_last_path = icompaths_del_last_path;
+ p->get_last_path = icompaths_get_last_path;
+ /* ====================================== */
- if (icompaths_refresh_paths(p)) {
+ if (icompaths_refresh_paths_sel(p, mask)) {
a1loge(log, ICOM_SYS, "new_icompaths: icompaths_refresh_paths failed!\n");
free(p);
return NULL;
@@ -301,6 +541,12 @@ icompaths *new_icompaths(a1log *log) {
return p;
}
+/* Allocate an icom paths and set it to the list of available instruments */
+/* Return NULL on error */
+icompaths *new_icompaths(a1log *log) {
+ return new_icompaths_sel(log, icomt_instrument | icomt_portattr_all);
+}
+
/* ----------------------------------------------------- */
@@ -321,7 +567,6 @@ static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc spath failed\n");
return ICOM_SYS;
}
- p->sattr = pp->sattr;
} else {
p->spath = NULL;
}
@@ -335,24 +580,36 @@ static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
if ((rv = hid_copy_hid_idevice(p, pp)) != ICOM_OK)
return rv;
#endif
+ p->dctype = pp->dctype;
p->itype = pp->itype;
+ a1logd(g_log, 8, "icom_copy_path_to_icom '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
-/* Return the port type */
-static icom_type icoms_port_type(
+/* Return the device category */
+/* (Returns bit flags) */
+static icom_type icoms_cat_type(
icoms *p
) {
+ return p->dctype & icomt_cat_mask;
+}
-#ifdef ENABLE_USB
- if (p->hidd != NULL)
- return icomt_hid;
- if (p->usbd != NULL)
- return icomt_usb;
-#endif
+/* Return the communication port type */
+/* (Can use equality tests on return value) */
+static icom_type icoms_port_type(
+icoms *p
+) {
+ return p->dctype & icomt_port_mask;
+}
- return icomt_serial;
+/* Return the communication port attributes */
+/* (Returns bit flags) */
+static icom_type icoms_port_attr(
+icoms *p
+) {
+ return p->dctype & icomt_attr_mask;
}
/* ----------------------------------------------------- */
@@ -365,10 +622,10 @@ icoms *p
# include "icoms_ux.c"
#endif
-/* write and read convenience function */
+/* write and read convenience function with read flush */
/* return icom error */
static int
-icoms_write_read(
+icoms_write_read_ex(
icoms *p,
char *wbuf, /* Write puffer */
int nwch, /* if > 0, number of characters to write, else nul terminated */
@@ -377,27 +634,33 @@ int bsize, /* Buffer size */
int *bread, /* Bytes read (not including forced '\000') */
char *tc, /* Terminating characers, NULL for none or char count mode */
int ntc, /* Number of terminating characters needed, or char count needed */
-double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
+double tout, /* Timeout for write and then read (i.e. max = 2 x tout) */
+int frbw /* nz to Flush Read Before Write */
) {
int rv = ICOM_OK;
a1logd(p->log, 8, "icoms_write_read: called\n");
if (p->write == NULL || p->read == NULL) { /* Neither serial nor USB ? */
- a1loge(p->log, ICOM_NOTS, "icoms_write_read: Neither serial nor USB device!\n");
+ a1loge(p->log, ICOM_NOTS, "icoms_write_read: No write and read functions set!\n");
return ICOM_NOTS;
}
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- /* Flush any stray chars if serial ?? */
- if (0 && p->usbd == NULL && p->hidd == NULL) {
- char tbuf[100];
+ /* Flush any stray chars if serial */
+ if (frbw && (p->dctype & icomt_serial)) {
+ char tbuf[500];
int debug = p->log->debug;
+ int bread;
if (debug < 8)
p->log->debug = 0;
- for (; rv == ICOM_OK;) /* Until we get a timeout */
- rv = p->read(p, tbuf, 100, NULL, NULL, 100, 0.01);
+ for (;;) {
+ bread = 0;
+ p->read(p, tbuf, 500, &bread, NULL, 500, 0.02);
+ if (bread == 0)
+ break;
+ }
p->log->debug = debug;
rv = ICOM_OK;
}
@@ -420,6 +683,23 @@ double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
return rv;
}
+/* write and read convenience function */
+/* return icom error */
+static int
+icoms_write_read(
+icoms *p,
+char *wbuf, /* Write puffer */
+int nwch, /* if > 0, number of characters to write, else nul terminated */
+char *rbuf, /* Read buffer */
+int bsize, /* Buffer size */
+int *bread, /* Bytes read (not including forced '\000') */
+char *tc, /* Terminating characers, NULL for none or char count mode */
+int ntc, /* Number of terminating characters needed, or char count needed */
+double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
+) {
+ return icoms_write_read_ex(p, wbuf, nwch, rbuf, bsize, bread, tc, ntc, tout, 0);
+}
+
/* Optional callback to client from device */
/* Default implementation is a NOOP */
static int icoms_interrupt(icoms *p,
@@ -428,6 +708,29 @@ static int icoms_interrupt(icoms *p,
return ICOM_OK;
}
+/* Destroy ourselves */
+static void
+icoms_del(icoms *p) {
+ a1logd(p->log, 8, "icoms_del: called\n");
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_del: closing port\n");
+ p->close_port(p);
+ }
+#ifdef ENABLE_USB
+ usb_del_usb(p);
+ hid_del_hid(p);
+#endif
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ if (p->spath != NULL)
+ free(p->spath);
+#endif
+ p->log = del_a1log(p->log);
+ if (p->name != NULL)
+ free(p->name);
+ p->log = del_a1log(p->log); /* unref */
+ free (p);
+}
+
/* icoms Constructor */
/* Return NULL on error */
icoms *new_icoms(
@@ -435,6 +738,9 @@ icoms *new_icoms(
a1log *log /* log to take reference from, NULL for default */
) {
icoms *p;
+
+ a1logd(log, 2, "new_icoms '%s' itype '%s' dctype 0x%x\n",ipath->name,inst_sname(ipath->itype),ipath->dctype);
+
if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL) {
a1loge(log, ICOM_SYS, "new_icoms: calloc failed!\n");
return NULL;
@@ -475,14 +781,19 @@ icoms *new_icoms(
p->close_port = icoms_close_port;
+ p->dev_cat = icoms_cat_type;
p->port_type = icoms_port_type;
+ p->port_attr = icoms_port_attr;
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ p->set_ser_port_ex = icoms_set_ser_port_ex;
p->set_ser_port = icoms_set_ser_port;
#endif /* ENABLE_SERIAL */
p->write = NULL; /* Serial open or set_methods will set */
p->read = NULL;
p->write_read = icoms_write_read;
+ p->write_read_ex = icoms_write_read_ex;
p->interrupt = icoms_interrupt;
p->del = icoms_del;
@@ -512,9 +823,9 @@ void good_beep() {
/* Emit a "bad" double beep */
void bad_beep() {
- /* 0msec delay, 800Hz for 200 msec */
+ /* 0 msec delay, 800Hz for 200 msec */
msec_beep(0, 800, 200);
- /* 500msec delay, 800Hz for 200 msec */
+ /* 350 msec delay, 800Hz for 200 msec */
msec_beep(350, 800, 200);
}
diff --git a/spectro/icoms.h b/spectro/icoms.h
index 2a282f0..be36cac 100644
--- a/spectro/icoms.h
+++ b/spectro/icoms.h
@@ -1,7 +1,7 @@
#ifndef ICOMS_H
- /* An abstracted instrument serial and USB communication class. */
+/* An abstracted instrument serial and USB communication class. */
/*
* Argyll Color Correction System
@@ -30,7 +30,7 @@
#include <windows.h>
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
#include <IOKit/usb/IOUSBLib.h>
#endif
@@ -40,6 +40,76 @@
#undef QUIET_MEMCHECKERS /* #define to memset coms read buffers before reading */
+/* USB open/handling/buf workaround flags */
+typedef enum {
+ icomuf_none = 0x0000,
+ icomuf_detach = 0x0001, /* Attempt to detach from system driver */
+ icomuf_no_open_clear = 0x0002, /* Don't send a clear_halt after opening the port */
+ icomuf_reset_before_close = 0x0004, /* Reset port before closing it */
+ /* ??? Could change to reset before open ??? */
+ icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */
+} icomuflags;
+
+typedef enum {
+ icomt_unknown = 0x0000,
+
+ /* Category of device */
+ icomt_instrument = 0x010000, /* Color measurement instrument (default) */
+ icomt_3dlut = 0x020000, /* A 3D cLUT box */
+ icomt_vtpg = 0x040000, /* A video test patern generator box */
+ icomt_printer = 0x080000, /* A printing device */
+
+ icomt_cat_any = 0x0f0000, /* Could be any device category */
+ icomt_cat_mask = 0xff0000, /* Mask for device category */
+
+ /* Type of underlying communication port */
+ /* (fastserio driver will have icomt_serial and icomt_usb set) */
+ icomt_serial = 0x000001, /* Serial port (i.e. has baud rate etc.) */
+ icomt_usb = 0x000002, /* USB port */
+ icomt_hid = 0x000004, /* HID USB port */
+ icomt_bt = 0x000008, /* Bluetooth (non-serial) */
+
+ icomt_port_mask = 0x0000ff, /* Mask for port type */
+
+ /* Attributes */
+ icomt_fastserial = 0x000100, /* Fast Serial (i.e. USB, fastserio, Bluetooth) */
+ icomt_btserial = 0x000200, /* Bluetooth serial port */
+ icomt_seriallike = 0x000400, /* Uses serial message methods, but */
+ /* may not be actual icomt_serial. */
+
+ icomt_attr_mask = 0x00ff00, /* Mask for port attributes */
+
+ icomt_portattr_mask = icomt_port_mask | icomt_attr_mask,
+
+ icomt_portattr_all = icomt_portattr_mask /* Scan for all port types */
+
+
+} icom_type;
+
+/* Status bits/return values */
+#define ICOM_OK 0x000000 /* No error */
+
+#define ICOM_NOTS 0x001000 /* Not supported */
+#define ICOM_SIZE 0x002000 /* Request/response size exceeded limits */
+#define ICOM_TO 0x004000 /* Timed out, but there may be bytes read/written */
+#define ICOM_SHORT 0x008000 /* No timeout but number of bytes wasn't read/written */
+#define ICOM_CANC 0x010000 /* Was cancelled */
+#define ICOM_SYS 0x020000 /* System error (ie. malloc, system call fail) */
+#define ICOM_VER 0x040000 /* Version error - need up to date kernel driver */
+
+#define ICOM_USBR 0x000100 /* Unspecified USB read error */
+#define ICOM_USBW 0x000200 /* Unspecified USB write error */
+#define ICOM_SERR 0x000400 /* Unspecified Serial read error */
+#define ICOM_SERW 0x000800 /* Unspecified Serial write error */
+
+#define ICOM_XRE 0x000040 /* Xmit shift reg empty */
+#define ICOM_XHE 0x000020 /* Xmit hold reg empty */
+#define ICOM_BRK 0x000010 /* Break detected */
+#define ICOM_FER 0x000008 /* Framing error */
+#define ICOM_PER 0x000004 /* Parity error */
+#define ICOM_OER 0x000002 /* Overun error */
+#define ICOM_DRY 0x000001 /* Recv data ready */
+
typedef struct _icompath icompath;
typedef struct _icompaths icompaths;
typedef struct _icoms icoms;
@@ -56,7 +126,7 @@ typedef struct {
int packetsize; /* The max packet size */
int type; /* 2 = bulk, 3 = interrupt */
int interface; /* interface number */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
int pipe; /* pipe number (1..N, OS X only) */
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@@ -72,27 +142,17 @@ typedef struct {
#endif /* ENABLE_USB */
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-
-/* Attributes of the serial port */
-typedef enum {
- icom_normal = 0x0000, /* Normal serial port */
- icom_fast = 0x0001, /* Fast port */
- icom_bt = 0x0002 /* Bluetooth serial port */
-} icom_ser_attr;
-
-#endif
-
/* - - - - - - - - - - - - - - - - - - - - */
/* Store information about a possible instrument communication path */
/* (Note a path doesn't have a reference to icompaths or its' log) */
-struct _icompath{
- instType itype; /* Type of instrument if known */
+struct _icompath {
+ devType itype; /* Type of device if known */
char *name; /* instance description */
+
+ icom_type dctype; /* Device and com. type */
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
char *spath; /* Serial device path */
- icom_ser_attr sattr; /* Virtual serial port that can be identified quickly */
#endif
#ifdef ENABLE_USB
int nep; /* Number of end points */
@@ -104,56 +164,93 @@ struct _icompath{
extern icompath icomFakeDevice; /* Declare fake device */
+/* Device type specific list index */
+typedef enum {
+ dtix_combined = 0, /* Combined list */
+ dtix_inst, /* Instrument */
+ dtix_3dlut,
+ dtix_vtpg,
+ dtix_printer,
+
+ dtix_number /* Number of entries */
+} icom_dtix;
+
/* The available instrument communication paths */
struct _icompaths {
- int npaths; /* Number of paths */
- icompath **paths; /* Paths if any */
a1log *log; /* Verbose, debuge & error logging */
- /* Re-populate the available instrument list */
+ /* Combined and device category specific path lists (read only). */
+ /* Paths may appear on more than one, if they are multi-function, */
+ /* or the category can't be determined without opening them. */
+ /* (dpaths[dtix_combined] is the owner of the icompath, */
+ /* and all the others are only populated after discovery.) */
+ icompath **dpaths[dtix_number]; /* Device paths if any */
+ int ndpaths[dtix_number]; /* Number of device paths */
+
+ /* Alias of dpaths[dtix_inst] for backwards compatibility, */
+ /* only set after discovery. */
+ icompath **paths; /* Device instrument if any */
+ int npaths; /* Number of instrument paths */
+
+ /* Re-discover and populate the available instrument list */
/* return icom error */
int (*refresh)(struct _icompaths *p);
+ /* Same as above, but just scan for selected types of devices and/or port types */
+ int (*refresh_sel)(struct _icompaths *p, icom_type mask);
+
+ /* Return the instrument path corresponding to the port number, or NULL if out of range */
+ icompath *(*get_path)(
+ struct _icompaths *p,
+ int port); /* Enumerated port number, 1..n */
+#define FAKE_DEVICE_PORT -98 /* Fake display & instrument */
+#define DEMO_DEVICE_PORT -99 /* Fake Demo instrument */
+
+ /* Return the device path corresponding to the port number, or NULL if out of range */
+ icompath *(*get_path_sel)(
+ struct _icompaths *p,
+ icom_type dctype, /* Device type list */
+ int port); /* Enumerated port number, 1..n */
+
+ /* Clear all the device paths */
+ void (*clear)(struct _icompaths *p);
+
+ /* We're done */
+ void (*del)(struct _icompaths *p);
+
+ /* ====== internal implementation ======= */
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- /* Add a serial path. path is copied. Return icom error */
- int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_ser_attr sattr);
+ /* Add a serial path to combined. path is copied. Return icom error */
+ int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_type dctype);
#endif /* ENABLE_SERIAL */
#ifdef ENABLE_USB
- /* Add a usb path. usbd is taken, others are copied. Return icom error */
+ /* Add a usb path to combined. usbd is taken, others are copied. Return icom error */
int (*add_usb)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype);
+ int nep, struct usb_idevice *usbd, devType itype);
- /* Add an hid path. hidd is taken, others are copied. Return icom error */
+ /* Add an hid path to combined. hidd is taken, others are copied. Return icom error */
int (*add_hid)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct hid_idevice *hidd, instType itype);
+ int nep, struct hid_idevice *hidd, devType itype);
#endif /* ENABLE_USB */
- /* Delete the last path */
+ /* Delete the last combined path */
void (*del_last_path)(struct _icompaths *p);
- /* Return the last path */
+ /* Return the last combined path */
icompath *(*get_last_path)(struct _icompaths *p);
- /* Return the path corresponding to the port number, or NULL if out of range */
- icompath *(*get_path)(
- struct _icompaths *p,
- int port); /* Enumerated port number, 1..n */
-#define FAKE_DEVICE_PORT -98 /* Fake display & instrument */
-#define DEMO_DEVICE_PORT -99 /* Fake Demo instrument */
-
- /* Clear all the paths */
- void (*clear)(struct _icompaths *p);
-
- /* We're done */
- void (*del)(struct _icompaths *p);
-
};
/* Allocate an icom paths and set it to the list of available devices */
+/* Use g_log as argument for default logging. */
/* Return NULL on error */
icompaths *new_icompaths(a1log *log);
+/* Same as above, but just scan for selected types of devices and/or port types */
+icompaths *new_icompaths_sel(a1log *log, icom_type mask);
+
/* - - - - - - - - - - - */
/* Serial related stuff */
@@ -161,7 +258,7 @@ icompaths *new_icompaths(a1log *log);
/* Flow control */
typedef enum {
fc_nc = 0, /* not configured/default */
- fc_none,
+ fc_None,
fc_XonXOff,
fc_Hardware, /* RTS CTS flow control */
fc_HardwareDTR /* DTR DSR flow control */
@@ -211,47 +308,6 @@ typedef enum {
length_8
} word_length;
-/* USB open/handling/buf workaround flags */
-typedef enum {
- icomuf_none = 0x0000,
- icomuf_detach = 0x0001, /* Attempt to detach from system driver */
- icomuf_no_open_clear = 0x0001, /* Don't send a clear_halt after opening the port */
- icomuf_reset_before_close = 0x0004, /* Reset port before closing it */
- icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */
-} icomuflags;
-
-/* Type of port driver */
-typedef enum {
- icomt_serial, /* Serial port */
- icomt_usbserial, /* Serial port using fastserio.c driver */
- icomt_usb, /* USB port */
- icomt_hid /* HID (USB) port */
-} icom_type;
-
-/* Status bits/return values */
-#define ICOM_OK 0x000000 /* No error */
-
-#define ICOM_NOTS 0x001000 /* Not supported */
-#define ICOM_SIZE 0x002000 /* Request/response size exceeded limits */
-#define ICOM_TO 0x004000 /* Timed out, but there may be bytes read/written */
-#define ICOM_SHORT 0x008000 /* No timeout but number of bytes wasn't read/written */
-#define ICOM_CANC 0x010000 /* Was cancelled */
-#define ICOM_SYS 0x020000 /* System error (ie. malloc, system call fail) */
-#define ICOM_VER 0x040000 /* Version error - need up to date kernel driver */
-
-#define ICOM_USBR 0x000100 /* Unspecified USB read error */
-#define ICOM_USBW 0x000200 /* Unspecified USB write error */
-#define ICOM_SERR 0x000400 /* Unspecified Serial read error */
-#define ICOM_SERW 0x000800 /* Unspecified Serial write error */
-
-#define ICOM_XRE 0x000040 /* Xmit shift reg empty */
-#define ICOM_XHE 0x000020 /* Xmit hold reg empty */
-#define ICOM_BRK 0x000010 /* Break detected */
-#define ICOM_FER 0x000008 /* Framing error */
-#define ICOM_PER 0x000004 /* Parity error */
-#define ICOM_OER 0x000002 /* Overun error */
-#define ICOM_DRY 0x000001 /* Recv data ready */
-
/* Interrupt callback type */
typedef enum {
icomi_data_available /* Data is available to be read */
@@ -270,8 +326,10 @@ struct _icoms {
/* Private: */
/* Copy of some of icompath contents: */
+ icom_type dctype; /* Device cat. and com. type */
+ devType itype; /* Type of device if known */
+
char *name; /* Device description */
- instType itype; /* Type of instrument if known */
int is_open; /* Flag, NZ if this port is open */
@@ -287,11 +345,9 @@ struct _icoms {
#if defined (NT)
HANDLE phandle; /* NT handle */
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined (UNIX)
int fd; /* Unix file descriptor */
#endif
- icom_ser_attr sattr; /* Serial port attributes, such as being fast */
-
flow_control fc;
baud_rate br;
parity py;
@@ -339,10 +395,31 @@ struct _icoms {
/* Public: */
- /* Return the port type */
+ /* Return the device category */
+ /* (Returns bit flags) */
+ icom_type (*dev_cat)(struct _icoms *p);
+
+ /* Return the communication port type */
+ /* (Can use equality tests on return value for normal ports, */
+ /* or bit flag for fastserio USB/serial port) */
icom_type (*port_type)(struct _icoms *p);
+ /* Return the communication port attributes */
+ /* (Returns bit flags) */
+ icom_type (*port_attr)(struct _icoms *p);
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ /* Select the serial communications port and characteristics - extended version */
+ /* return icom error */
+ int (*set_ser_port_ex)(
+ struct _icoms *p,
+ flow_control fc, /* Flow control */
+ baud_rate baud,
+ parity parity,
+ stop_bits stop_bits,
+ word_length word_length,
+ int delayms); /* Delay in ms after open */
+
/* Select the serial communications port and characteristics */
/* return icom error */
int (*set_ser_port)(
@@ -414,6 +491,20 @@ struct _icoms {
int ntc, /* Number of any terminating characters needed, or char count needed */
double tout); /* Timeout in seconds */
+ /* "Serial" write and read with read flush */
+ /* return icom error */
+ int (*write_read_ex)(
+ struct _icoms *p,
+ char *wbuf, /* Write puffer */
+ int nwch, /* if > 0, number of characters to write, else nul terminated */
+ char *rbuf, /* Read buffer */
+ int bsize, /* Buffer size. Make this larger than chars required! */
+ int *bread, /* Bytes read (not including forced '\000') */
+ char *tc, /* Terminating characers, NULL for none or char count mode */
+ int ntc, /* Number of any terminating characters needed, or char count needed */
+ double tout, /* Timeout in seconds */
+ int frbw); /* nz to Flush Read Before Write */
+
/* For a USB device, do a control message */
/* return icom error */
int (*usb_control)(struct _icoms *p,
@@ -504,6 +595,16 @@ char *icoms_fix(char *s);
/* Convert a limited binary buffer to a list of hex */
char *icoms_tohex(unsigned char *s, int len);
+/* Implementation declarations */
+
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
+int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
+int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
+ char *tc, int ntc, double tout);
+
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c
index 14258e9..b9e0d0c 100644
--- a/spectro/icoms_nt.c
+++ b/spectro/icoms_nt.c
@@ -1,5 +1,5 @@
-
- /* Windows NT serial I/O class */
+
+/* Windows NT serial I/O class */
/*
* Argyll Color Correction System
@@ -14,195 +14,171 @@
* see the License2.txt file for licencing details.
*/
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
#include <conio.h>
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
-#endif /* ENABLE_SERIAL */
-
-/* Create and return a list of available serial ports or USB instruments for this system. */
-/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
-/* to determine serial ports, and use libusb to discover USB instruments. */
-/* Create and return a list of available serial ports or USB instruments for this system */
-/* return icom error */
-int icompaths_refresh_paths(icompaths *p) {
- int rv, usbend = 0;
- int i, j;
+
+/* Add paths to serial connected device. */
+/* Return an icom error */
+int serial_get_paths(icompaths *p, icom_type mask) {
+ int i;
LONG stat;
HKEY sch; /* Serial coms handle */
- a1logd(p->log, 8, "icoms_get_paths: called\n");
+ a1logd(p->log, 7, "serial_get_paths: called with mask = %d\n",mask);
- /* Clear any existing paths */
- p->clear(p);
-
-#ifdef ENABLE_USB
- if ((rv = hid_get_paths(p)) != ICOM_OK)
- return rv;
- if ((rv = usb_get_paths(p)) != ICOM_OK)
- return rv;
-#endif /* ENABLE_USB */
- usbend = p->npaths;
-
- a1logd(p->log, 6, "icoms_get_paths: got %d paths, looking up the registry for serial ports\n",p->npaths);
-
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
// (Beware KEY_WOW64_64KEY ?)
#define MXKSIZE 500
#define MXVSIZE 300
- /* Look in the registry for serial ports */
- if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
- 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
- a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any serial ports\n");
- return ICOM_OK; /* Maybe they have USB ports */
- }
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
- /* Look at all the values in this key */
- a1logd(p->log, 8, "icoms_get_paths: looking through all the values in the SERIALCOMM key\n");
-
- for (i = 0; ; i++) {
- char valname[MXKSIZE], *vp;
- DWORD vnsize = MXKSIZE;
- DWORD vtype;
- char value[MXVSIZE];
- DWORD vsize = MXVSIZE;
- icom_ser_attr sattr = icom_normal;
-
- stat = RegEnumValue(
- sch, /* handle to key to enumerate */
- i, /* index of subkey to enumerate */
- valname, /* address of buffer for value name */
- &vnsize, /* address for size of value name buffer */
- NULL, /* reserved */
- &vtype, /* Address of value type */
- value, /* Address of value buffer */
- &vsize /* Address of value buffer size */
- );
- if (stat == ERROR_NO_MORE_ITEMS) {
- a1logd(p->log, 8, "icoms_get_paths: got ERROR_NO_MORE_ITEMS\n");
- break;
- }
- if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
- || stat != ERROR_SUCCESS) {
- a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
- break;
+ a1logd(p->log, 6, "serial_get_paths: looking up the registry for serial ports\n");
+ /* Look in the registry for serial ports */
+ if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
+ 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
+ a1logd(p->log, 1, "serial_get_paths: There don't appear to be any serial ports\n");
+ return ICOM_OK;
}
- valname[MXKSIZE-1] = '\000';
- value[MXVSIZE-1] = '\000';
- if (vtype != REG_SZ) {
- a1logw(p->log, "icoms_get_paths: RegEnumValue didn't return stringz type\n");
- continue;
- }
+ /* Look at all the values in this key */
+ a1logd(p->log, 8, "serial_get_paths: looking through all the values in the SERIALCOMM key\n");
+
+ for (i = 0; ; i++) {
+ char valname[MXKSIZE], *vp;
+ DWORD vnsize = MXKSIZE;
+ DWORD vtype;
+ char value[MXVSIZE];
+ DWORD vsize = MXVSIZE;
+ icom_type dctype = icomt_unknown;
+
+ stat = RegEnumValue(
+ sch, /* handle to key to enumerate */
+ i, /* index of subkey to enumerate */
+ valname, /* address of buffer for value name */
+ &vnsize, /* address for size of value name buffer */
+ NULL, /* reserved */
+ &vtype, /* Address of value type */
+ value, /* Address of value buffer */
+ &vsize /* Address of value buffer size */
+ );
+ if (stat == ERROR_NO_MORE_ITEMS) {
+ a1logd(p->log, 8, "serial_get_paths: got ERROR_NO_MORE_ITEMS\n");
+ break;
+ }
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "serial_get_paths: RegEnumValue failed with %d\n",stat);
+ break;
+ }
+ valname[MXKSIZE-1] = '\000';
+ value[MXVSIZE-1] = '\000';
- if ((vp = strrchr(valname, '\\')) == NULL)
- vp = valname;
- else
- vp++;
+ if (vtype != REG_SZ) {
+ a1logw(p->log, "serial_get_paths: RegEnumValue didn't return stringz type\n");
+ continue;
+ }
- /* See if it looks like a fast port */
- if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */
- sattr |= icom_fast;
- }
+ if ((vp = strrchr(valname, '\\')) == NULL)
+ vp = valname;
+ else
+ vp++;
- if (strncmp(vp, "BtPort", 6) == 0) { /* Blue tooth */
- sattr |= icom_fast;
- sattr |= icom_bt;
- }
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",vp);
+
+ /* See if it looks like a fast port */
+ if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */
+ dctype |= icomt_fastserial;
+ }
+
+ if (strncmp(vp, "USBSER", 6) == 0) { /* USB Serial port */
+ dctype |= icomt_fastserial;
+ }
+
+ if (strncmp(vp, "BtPort", 6) == 0 /* Blue tooth */
+ || strncmp(vp, "BthModem", 8) == 0) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the port to the list */
- p->add_serial(p, value, value, sattr);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' sattr 0x%x\n",value,sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+
+ // ~~ would be nice to add better description, similar
+ // to that of device manager, i.e. "Prolific USB-to-SerialBridge (COM6)"
+ /* Add the port to the list */
+ p->add_serial(p, value, value, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added '%s' path '%s' dctype 0x%x\n",vp, value,dctype);
+ }
#ifndef ENABLE_SERIAL
- }
+ }
#endif
- /* If fast, try and identify it */
- if (sattr & icom_fast) {
- icompath *path;
- icoms *icom;
- if ((path = p->get_last_path(p)) != NULL
- && (icom = new_icoms(path, p->log)) != NULL) {
- instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
- if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
- icom->del(icom);
+ /* If fast, try and identify it */
+ if (dctype & icomt_fastserial) {
+ icompath *path;
+ icoms *icom;
+ if ((path = p->get_last_path(p)) != NULL
+ && (icom = new_icoms(path, p->log)) != NULL) {
+ devType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
+ if (itype != instUnknown)
+ icompaths_set_serial_itype(path, itype); /* And set category */
+ icom->del(icom);
+ }
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
}
- }
- if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
- a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
- }
-#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL */
-
- /* Sort the COM keys so people don't get confused... */
- /* Sort identified instruments ahead of unknown serial ports */
- a1logd(p->log, 6, "icoms_get_paths: we now have %d entries and are about to sort them\n",p->npaths);
- for (i = usbend; i < (p->npaths-1); i++) {
- for (j = i+1; j < p->npaths; j++) {
- if ((p->paths[i]->itype == instUnknown && p->paths[j]->itype != instUnknown)
- || (((p->paths[i]->itype == instUnknown && p->paths[j]->itype == instUnknown)
- || (p->paths[i]->itype != instUnknown && p->paths[j]->itype != instUnknown))
- && strcmp(p->paths[i]->name, p->paths[j]->name) > 0)) {
- icompath *tt = p->paths[i];
- p->paths[i] = p->paths[j];
- p->paths[j] = tt;
- }
+ if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
+ a1logw(p->log, "serial_get_paths: RegCloseKey failed with %d\n",stat);
}
}
- a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
-
return ICOM_OK;
}
+/* -------------------------------------------------------------------- */
-/* Close the port */
-static void icoms_close_port(icoms *p) {
- if (p->is_open) {
-#ifdef ENABLE_USB
- if (p->usbd) {
- usb_close_port(p);
- } else if (p->hidd) {
- hid_close_port(p);
- }
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->phandle != NULL) {
- CloseHandle(p->phandle);
- }
-#endif /* ENABLE_SERIAL */
- p->is_open = 0;
- }
+/* Is the serial port actually open ? */
+int serial_is_open(icoms *p) {
+ return p->phandle != NULL;
}
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+/* Close the serial port */
+void serial_close_port(icoms *p) {
+
+ if (p->is_open && p->phandle != NULL) {
+ CloseHandle(p->phandle);
+ p->phandle = NULL;
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ }
+}
-static int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
-static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
- char *tc, int ntc, double tout);
+/* -------------------------------------------------------------------- */
#ifndef CBR_921600
# define CBR_921600 921600
#endif
-/* Set the serial port characteristics */
+/* Set the serial port characteristics - extended */
/* This always re-opens the port */
/* return an icom error */
static int
-icoms_set_ser_port(
+icoms_set_ser_port_ex(
icoms *p,
flow_control fc,
baud_rate baud,
parity parity,
stop_bits stop,
-word_length word)
-{
+word_length word,
+int delayms) { /* Delay after open in msec */
a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
" Port name = %s\n"
@@ -211,10 +187,13 @@ word_length word)
" Parity = %d\n"
" Stop bits = %d\n"
" Word length = %d\n"
- ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word);
+ " Open delay = %d ms\n"
+ ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word, delayms);
- if (p->is_open)
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_set_ser_port: closing port '%s'\n",p->name);
p->close_port(p);
+ }
if (p->port_type(p) == icomt_serial) {
DCB dcb;
@@ -234,7 +213,7 @@ word_length word)
/* Make sure the port is open */
if (!p->is_open) {
- char buf[50]; /* Temporary for COM device path */
+ char buf[100]; /* Temporary for COM device path */
a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
@@ -253,11 +232,18 @@ word_length word)
a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",buf,GetLastError());
return ICOM_SYS;
}
+
+ if (delayms < 160) /* Seems to need at least 80 msec with many drivers */
+ delayms = 160;
+
+ msec_sleep(delayms); /* For Bluetooth */
+
p->is_open = 1;
}
if (GetCommState(p->phandle, &dcb) == FALSE) {
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: reading state '%s' failed with LastError %d\n",p->spath,GetLastError());
return ICOM_SYS;
}
@@ -274,14 +260,17 @@ word_length word)
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE; /* Turn RTS on during connection */
-// dcb.fAbortOnError = TRUE; // Hmm. Stuffs up FTDI. Is it needed ?
- dcb.fAbortOnError = FALSE;
+ dcb.fAbortOnError = FALSE; /* Hmm. TRUE Stuffs up FTDI. Is it needed ? */
switch (p->fc) {
case fc_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
return ICOM_SYS;
+ case fc_None:
+ /* Use no flow control */
+ break;
case fc_XonXOff:
/* Use Xon/Xoff bi-directional flow control */
dcb.fOutX = TRUE;
@@ -307,6 +296,7 @@ word_length word)
switch (p->py) {
case parity_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
return ICOM_SYS;
case parity_none:
@@ -328,6 +318,7 @@ word_length word)
switch (p->sb) {
case stop_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
return ICOM_SYS;
case stop_1:
@@ -341,6 +332,7 @@ word_length word)
switch (p->wl) {
case length_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
return ICOM_SYS;
case length_5:
@@ -399,20 +391,24 @@ word_length word)
break;
default:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
return ICOM_SYS;
}
- PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+ PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
if (!SetCommState(p->phandle, &dcb)) {
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: SetCommState failed with LastError %d\n",
GetLastError());
return ICOM_SYS;
}
- PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+ PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
+
+ msec_sleep(50); /* Improves reliability of USB<->Serial converters */
p->write = icoms_ser_write;
p->read = icoms_ser_read;
@@ -423,6 +419,22 @@ word_length word)
return ICOM_OK;
}
+/* Set the serial port characteristics */
+/* This always re-opens the port */
+/* return an icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word)
+{
+ return icoms_set_ser_port_ex(p, fc, baud, parity, stop, word, 0);
+}
+
+
/* ---------------------------------------------------------------------------------*/
/* Serial write, read */
@@ -430,7 +442,7 @@ word_length word)
/* Data will be written up to the terminating nul */
/* Return relevant error status bits */
/* Set the icoms lserr value */
-static int
+int
icoms_ser_write(
icoms *p,
char *wbuf, /* null terminated unless nwch > 0 */
@@ -519,7 +531,7 @@ double tout)
/* Read characters into the buffer */
/* Return string will be terminated with a nul */
-static int
+int
icoms_ser_read(
icoms *p,
char *rbuf, /* Buffer to store characters read */
@@ -645,30 +657,5 @@ double tout /* Time out in seconds */
return p->lserr;
}
-#endif /* ENABLE_SERIAL */
-/* ---------------------------------------------------------------------------------*/
-
-
-/* Destroy ourselves */
-static void
-icoms_del(icoms *p) {
- a1logd(p->log, 8, "icoms_del: called\n");
- if (p->is_open) {
- a1logd(p->log, 8, "icoms_del: closing port\n");
- p->close_port(p);
- }
-#ifdef ENABLE_USB
- usb_del_usb(p);
- hid_del_hid(p);
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->spath != NULL)
- free(p->spath);
-#endif
- p->log = del_a1log(p->log);
- if (p->name != NULL)
- free(p->name);
- p->log = del_a1log(p->log); /* unref */
- free (p);
-}
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL*/
diff --git a/spectro/icoms_ux.c b/spectro/icoms_ux.c
index 7fb7359..9e79d7f 100644
--- a/spectro/icoms_ux.c
+++ b/spectro/icoms_ux.c
@@ -1,5 +1,5 @@
- /* Unix icoms and serial I/O class */
+/* Unix icoms and serial I/O class */
/*
* Argyll Color Correction System
@@ -18,6 +18,8 @@
TTBD:
*/
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
#include <sys/types.h> /* Include sys/select.h ? */
#include <sys/stat.h>
#include <fcntl.h>
@@ -27,62 +29,50 @@
/* select() defined, but not poll(), so emulate poll() */
#if defined(FD_CLR) && !defined(POLLIN)
-#include "pollem.h"
-#define poll_x pollem
+# include "pollem.h"
+# define poll_x pollem
#else
-#include <sys/poll.h> /* Else assume poll() is native */
-#define poll_x poll
+# include <sys/poll.h> /* Else assume poll() is native */
+# define poll_x poll
#endif
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
//#include <stdbool.h>
-#include <sys/sysctl.h>
-#include <sys/param.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/serial/IOSerialKeys.h>
-#include <IOKit/IOBSD.h>
-#include <mach/mach_init.h>
-#include <mach/task_policy.h>
-#endif /* __APPLE__ */
-
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
-#endif /* ENABLE_SERIAL */
+# include <sys/sysctl.h>
+# include <sys/param.h>
+# include <CoreFoundation/CoreFoundation.h>
+# include <IOKit/IOKitLib.h>
+# include <IOKit/serial/IOSerialKeys.h>
+# include <IOKit/IOBSD.h>
+# include <mach/mach_init.h>
+# include <mach/task_policy.h>
+#endif /* UNIX_APPLE */
-/* Create and return a list of available serial ports or USB instruments for this system */
-/* return icom error */
-int icompaths_refresh_paths(icompaths *p) {
- int rv, usbend = 0;
- int i,j;
- a1logd(p->log, 8, "icoms_get_paths: called\n");
+instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
- /* Clear any existing paths */
- p->clear(p);
+/* Add paths to serial connected device. */
+/* Return an icom error */
+int serial_get_paths(icompaths *p, icom_type mask) {
+ int rv;
-#ifdef ENABLE_USB
- if ((rv = hid_get_paths(p)) != ICOM_OK)
- return rv;
- if ((rv = usb_get_paths(p)) != ICOM_OK)
- return rv;
-#endif /* ENABLE_USB */
- usbend = p->npaths;
+ a1logd(p->log, 7, "serial_get_paths: called with mask %d\n",mask);
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Search the OSX registry for serial ports */
- {
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
kern_return_t kstat;
mach_port_t mp; /* Master IO port */
CFMutableDictionaryRef sdict; /* Serial Port dictionary */
io_iterator_t mit; /* Matching itterator */
io_object_t ioob; /* Serial object found */
+ a1logd(p->log, 6, "serial_get_paths: looking up serial ports services\n");
+
/* Get dictionary of serial ports */
if ((sdict = IOServiceMatching(kIOSerialBSDServiceValue)) == NULL) {
a1loge(p->log, ICOM_SYS, "IOServiceMatching returned a NULL dictionary\n");
- return ICOM_OK;
+ return ICOM_OK; /* Hmm. There are no serial ports ? */
}
/* Set value to match to RS232 type serial */
@@ -98,7 +88,7 @@ int icompaths_refresh_paths(icompaths *p) {
/* Find all the matching serial ports */
for (;;) {
char pname[200];
- icom_ser_attr sattr = icom_normal;
+ icom_type dctype = icomt_unknown;
CFTypeRef dfp; /* Device file path */
@@ -114,36 +104,50 @@ int icompaths_refresh_paths(icompaths *p) {
if (!CFStringGetCString(dfp, pname, 100, kCFStringEncodingASCII))
goto continue2;
- /* Ignore infra red port or Bluetooth, or any other noise */
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",pname);
+
+ /* Ignore infra red port or any other noise */
if (strstr(pname, "IrDA") != NULL
|| strstr(pname, "Dialup") != NULL
- || strstr(pname, "Bluetooth") != NULL)
+ || strstr(pname, "PDA-Sync") != NULL)
goto continue2;
/* Would be nice to identify FTDI serial ports more specifically ? */
if (strstr(pname, "usbserial") != NULL)
- sattr |= icom_fast;
+ dctype |= icomt_fastserial;
+
+ if (strstr(pname, "Bluetooth") != NULL
+ || strstr(pname, "JETI") != NULL) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the port to the list */
- p->add_serial(p, pname, pname, sattr);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",pname, sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+ /* Add the port to the list */
+ p->add_serial(p, pname, pname, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added path '%s' dctype 0x%x\n",pname, dctype);
+ }
#ifndef ENABLE_SERIAL
}
#endif
/* If fast, try and identify it */
- if (sattr & icom_fast) {
+ if (dctype & icomt_fastserial) {
icompath *path;
icoms *icom;
if ((path = p->get_last_path(p)) != NULL
&& (icom = new_icoms(path, p->log)) != NULL) {
instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
+ icompaths_set_serial_itype(path, itype); /* And set category */
icom->del(icom);
}
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
continue2:
CFRelease(dfp);
@@ -152,8 +156,9 @@ int icompaths_refresh_paths(icompaths *p) {
}
IOObjectRelease(mit); /* Release the itterator */
}
-#else
- /* Other UNIX like systems */
+
+#else /* Other UNIX like systems */
+
/* Many are crude and list every available device name, whether */
/* it's usable or not. Do any UNIX systems have a mechanism for listing */
/* serial ports ?? */
@@ -203,12 +208,16 @@ int icompaths_refresh_paths(icompaths *p) {
*/
/* Search for devices that match the pattern /dev/ttyS[0-9]* and /dev/ttyUSB* */
- /* We will assume that ttyUSB* ports includes FTDI ports */
- {
+ /* We will assume that ttyUSB* ports includes FTDI ports. */
+ /* Bluetooth ports are named ttyHS* or rfcomm* ?? */
+
+ if (mask & (icomt_serial | icomt_fastserial | icomt_bt)) {
DIR *dd;
struct dirent *de;
char *dirn = "/dev/";
+ a1logd(p->log, 6, "serial_get_paths: looking up serial port devices\n");
+
if ((dd = opendir(dirn)) == NULL) {
a1loge(p->log, ICOM_SYS, "failed to open directory \"%s\"\n",dirn);
return ICOM_OK;
@@ -217,10 +226,13 @@ int icompaths_refresh_paths(icompaths *p) {
for (;;) {
int fd;
char *dpath;
- icom_ser_attr sattr = icom_normal;
+ icom_type dctype = icomt_unknown;
- if ((de = readdir(dd)) == NULL)
+ if ((de = readdir(dd)) == NULL) {
break;
+ }
+
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",de->d_name);
if (!(
#if defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -231,27 +243,32 @@ int icompaths_refresh_paths(icompaths *p) {
/* Presumably Linux.. */
( strncmp(de->d_name, "ttyS", 4) == 0
&& de->d_name[4] >= '0' && de->d_name[4] <= '9')
- || ( strncmp(de->d_name, "ttyUSB", 5) == 0)
+ || ( strncmp(de->d_name, "ttyUSB", 6) == 0)
+ || ( strncmp(de->d_name, "ttyHS", 5) == 0)
+ || ( strncmp(de->d_name, "rfcomm", 6) == 0)
#endif
))
continue;
if ((dpath = (char *)malloc(strlen(dirn) + strlen(de->d_name) + 1)) == NULL) {
closedir(dd);
- a1loge(p->log, ICOM_SYS, "icompaths_refresh_paths() malloc failed!\n");
+ a1loge(p->log, ICOM_SYS, "icompaths_refresh_paths_sel() malloc failed!\n");
return ICOM_SYS;
}
strcpy(dpath, dirn);
strcat(dpath, de->d_name);
/* See if the serial port is real */
- if (strncmp(de->d_name, "ttyUSB", 5) != 0) {
+ if (strncmp(de->d_name, "ttyUSB", 6) != 0
+ && strncmp(de->d_name, "ttyHS", 5) != 0
+ && strncmp(de->d_name, "rfcomm", 6) != 0) {
/* Hmm. This is probably a bad idea - it can upset other */
/* programs that use the serial ports ? */
if ((fd = open(dpath, O_RDONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
- a1logd(p->log, 8, "icoms_get_paths: failed to open serial \"%s\" - not real\n",dpath);
+ a1logd(p->log, 8, "serial_get_paths: failed to open serial \"%s\" r/o - not real\n",dpath);
free(dpath);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
continue;
}
/* On linux we could do a
@@ -267,94 +284,83 @@ int icompaths_refresh_paths(icompaths *p) {
*/
close(fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ a1logd(p->log, 8, "serial_get_paths: open'd serial \"%s\" r/o - assume real\n",dpath);
}
- a1logd(p->log, 8, "icoms_get_paths: open'd serial \"%s\" - assume real\n",dpath);
- if (strncmp(de->d_name, "ttyUSB", 5) == 0)
- sattr |= icom_fast;
+ if (strncmp(de->d_name, "ttyUSB", 6) == 0
+ || strncmp(de->d_name, "ttyHS", 5) == 0
+ || strncmp(de->d_name, "rfcomm", 6) == 0)
+ dctype |= icomt_fastserial;
+
+ if (strncmp(de->d_name, "rfcomm", 6) == 0) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the path to the list */
- p->add_serial(p, dpath, dpath, 0);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",dpath,sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+ /* Add the port to the list */
+ p->add_serial(p, dpath, dpath, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added path '%s' dctype 0x%x\n",dpath, dctype);
+ }
#ifndef ENABLE_SERIAL
}
#endif
free(dpath);
/* If fast, try and identify it */
- if (sattr & icom_fast) {
+ if (dctype & icomt_fastserial) {
icompath *path;
icoms *icom;
if ((path = p->get_last_path(p)) != NULL
&& (icom = new_icoms(path, p->log)) != NULL) {
instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
+ icompaths_set_serial_itype(path, itype); /* And set category */
icom->del(icom);
}
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
}
closedir(dd);
}
-#endif /* ! __APPLE__ */
-#endif /* ENABLE_SERIAL */
-
- /* Sort the serial /dev keys so people don't get confused... */
- /* Sort identified instruments ahead of unknown serial ports */
- for (i = usbend; i < (p->npaths-1); i++) {
- for (j = i+1; j < p->npaths; j++) {
- if ((p->paths[i]->itype == instUnknown && p->paths[j]->itype != instUnknown)
- || (((p->paths[i]->itype == instUnknown && p->paths[j]->itype == instUnknown)
- || (p->paths[i]->itype != instUnknown && p->paths[j]->itype != instUnknown))
- && strcmp(p->paths[i]->name, p->paths[j]->name) > 0)) {
- icompath *tt = p->paths[i];
- p->paths[i] = p->paths[j];
- p->paths[j] = tt;
- }
- }
- }
+#endif /* ! UNIX_APPLE */
+
return ICOM_OK;
}
/* -------------------------------------------------------------------- */
-/* Close the port */
-static void icoms_close_port(icoms *p) {
- if (p->is_open) {
-#ifdef ENABLE_USB
- if (p->usbd) {
- usb_close_port(p);
- } else if (p->hidd) {
- hid_close_port(p);
- }
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->fd != -1) {
- close(p->fd);
- p->fd = -1;
- }
-#endif /* ENABLE_SERIAL */
- p->is_open = 0;
- }
+/* Is the serial port actually open ? */
+int serial_is_open(icoms *p) {
+ return p->fd != -1;
}
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+/* Close the serial port */
+void serial_close_port(icoms *p) {
-static int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
-static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
- char *tc, int ntc, double tout);
+ if (p->is_open && p->fd != -1) {
+ close(p->fd);
+ p->fd = -1;
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ }
+}
+/* -------------------------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# ifndef IOSSIOSPEED
# define IOSSIOSPEED _IOW('T', 2, speed_t)
# endif
#endif
-#if defined(__APPLE__) || defined(__OpenBSD__)
+#if defined(UNIX_APPLE) || defined(__OpenBSD__)
# ifndef B921600
# define B921600 921600
# endif
@@ -364,14 +370,14 @@ static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
/* This always re-opens the port */
/* return icom error */
static int
-icoms_set_ser_port(
+icoms_set_ser_port_ex(
icoms *p,
flow_control fc,
baud_rate baud,
parity parity,
stop_bits stop,
-word_length word
-) {
+word_length word,
+int delayms) { /* Delay after open in msec */
int rv;
struct termios tio;
speed_t speed = 0;
@@ -379,15 +385,18 @@ word_length word
a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
" Port name = %s\n"
" Flow control = %d\n"
- " Baud Rate = %d\n"
+ " Baud Rate = %s\n"
" Parity = %d\n"
" Stop bits = %d\n"
" Word length = %d\n"
- ,p->name ,fc ,baud ,parity ,stop ,word);
+ " Open delay = %d ms\n"
+ ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word, delayms);
- if (p->is_open) /* Close it and re-open it */
+ if (p->is_open) { /* Close it and re-open it */
+ a1logd(p->log, 8, "icoms_set_ser_port: closing port\n");
p->close_port(p);
+ }
if (p->port_type(p) == icomt_serial) {
@@ -410,10 +419,52 @@ word_length word
a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
if ((p->fd = open(p->spath, O_RDWR | O_NOCTTY )) < 0) {
- a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+ a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' r/w failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+
+ if (delayms < 160) /* Seems to need at least 80 msec for many drivers */
+ delayms = 160;
+
+ msec_sleep(delayms); /* For Bluetooth */
+
+#ifdef NEVER /* See what supplementary groups we are a member of */
+ {
+ int j, ngroups = 16;
+ gid_t *groups = (gid_t *)malloc (ngroups * sizeof(gid_t));
+ struct passwd *pw = getpwuid(getuid());
+
+ if (groups == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: malloc of sgroups failed\n");
+ goto fail;
+ }
+ if (pw == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: getpwuid failed\n");
+ goto fail;
+ }
+
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) < 0) {
+ groups = realloc(groups, ngroups * sizeof(gid_t));
+ if (groups == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: realloc of sgroups failed\n");
+ goto fail;
+ }
+ getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+ }
+ a1logd(p->log, 0, "icoms_set_ser_port: ngroups = %d\n", ngroups);
+ for (j = 0; j < ngroups; j++) {
+ struct group *gr = getgrgid(groups[j]);
+ if (gr != NULL)
+ a1logd(p->log, 0, "icoms_set_ser_port: %d: gid %d\n", j,groups[j]);
+ else
+ a1logd(p->log, 0, "icoms_set_ser_port: %d: gid %d (%s)\n", j,groups[j],gr->gr_name);
+ }
+ fail:;
+ }
+#endif
return ICOM_SYS;
}
+
/* O_NONBLOCK O_SYNC */
+
p->is_open = 1;
}
@@ -448,6 +499,7 @@ word_length word
switch (p->fc) {
case fc_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
return ICOM_SYS;
case fc_XonXOff:
@@ -459,7 +511,7 @@ word_length word
break;
case fc_Hardware:
/* Use RTS/CTS bi-directional flow control */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
tio.c_cflag |= CCTS_OFLOW;
tio.c_cflag |= CRTS_IFLOW;
#else
@@ -468,7 +520,7 @@ word_length word
break;
case fc_HardwareDTR:
/* Use DTR/DSR bi-directional flow control */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
tio.c_cflag |= CDSR_OFLOW;
tio.c_cflag |= CDTR_IFLOW;
#else
@@ -484,6 +536,7 @@ word_length word
switch (p->py) {
case parity_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
return ICOM_SYS;
break;
@@ -504,6 +557,7 @@ word_length word
switch (p->sb) {
case stop_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
return ICOM_SYS;
case stop_1:
@@ -516,6 +570,7 @@ word_length word
switch (p->wl) {
case length_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
return ICOM_SYS;
case length_5:
@@ -572,6 +627,7 @@ word_length word
break;
default:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
return ICOM_SYS;
}
@@ -589,11 +645,13 @@ word_length word
#endif
if ((rv = cfsetispeed(&tio, speed)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetispeed failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
if ((rv = cfsetospeed(&tio, speed)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetospeed failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
@@ -601,11 +659,13 @@ word_length word
/* Make change immediately */
if ((rv = tcsetattr(p->fd, TCSANOW, &tio)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: tcsetattr failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
tcflush(p->fd, TCIOFLUSH); /* Discard any current in/out data */
+ msec_sleep(50); /* Improves reliability of USB<->Serial converters */
p->write = icoms_ser_write;
p->read = icoms_ser_read;
@@ -616,6 +676,29 @@ word_length word
return ICOM_OK;
}
+/* Set the serial port characteristics */
+/* This always re-opens the port */
+/* return an icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word)
+{
+ return icoms_set_ser_port_ex(p, fc, baud, parity, stop, word, 0);
+}
+
+/* ------------------------------ */
+/* Could add read flush function, to discard all read data using
+
+ tcflush(fd, TCIFLUSH);
+
+*/
+
+
/* ---------------------------------------------------------------------------------*/
/* Serial write/read */
@@ -623,7 +706,7 @@ word_length word
/* Data will be written up to the terminating nul */
/* Return relevant error status bits */
/* Set the icoms lserr value */
-static int
+int
icoms_ser_write(
icoms *p,
char *wbuf, /* null terminated unless nwch > 0 */
@@ -699,6 +782,8 @@ double tout
retrv |= ICOM_TO;
}
+// tcdrain(p->fd);
+
a1logd(p->log, 8, "icoms_ser_write: took %d msec, returning ICOM err 0x%x\n",etime - stime,retrv);
p->lserr = retrv;
return p->lserr;
@@ -707,7 +792,7 @@ double tout
/* Read characters into the buffer */
/* Return string will be terminated with a nul */
/* return icom error */
-static int
+int
icoms_ser_read(
icoms *p,
char *rbuf, /* Buffer to store characters read */
@@ -826,30 +911,5 @@ double tout /* Time out in seconds */
return p->lserr;
}
-#endif /* ENABLE_SERIAL */
-
-/* ---------------------------------------------------------------------------------*/
-
-/* Destroy ourselves */
-static void
-icoms_del(icoms *p) {
- a1logd(p->log, 8, "icoms_del: called\n");
- if (p->is_open) {
- a1logd(p->log, 8, "icoms_del: closing port\n");
- p->close_port(p);
- }
-#ifdef ENABLE_USB
- usb_del_usb(p);
- hid_del_hid(p);
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->spath != NULL)
- free(p->spath);
-#endif
- p->log = del_a1log(p->log);
- if (p->name != NULL)
- free(p->name);
- p->log = del_a1log(p->log);
- free (p);
-}
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL*/
diff --git a/spectro/illumread.c b/spectro/illumread.c
index 381f6b6..58569e3 100644
--- a/spectro/illumread.c
+++ b/spectro/illumread.c
@@ -393,7 +393,7 @@ int main(int argc, char *argv[])
if (na == NULL) usage(NULL);
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -431,17 +431,17 @@ int main(int argc, char *argv[])
/* Special debug */
strcpy(tnp, "_i.sp");
- if (read_xspect(&i_sp, tname) == 0) {
+ if (read_xspect(&i_sp, NULL, tname) == 0) {
rd_i = 1;
printf("(Found '%s' file and loaded it)\n",tname);
}
strcpy(tnp, "_r.sp");
- if (read_xspect(&r_sp, tname) == 0) {
+ if (read_xspect(&r_sp, NULL, tname) == 0) {
rd_r = 1;
printf("(Found '%s' file and loaded it)\n",tname);
}
strcpy(tnp, "_p.sp");
- if (read_xspect(&p_sp, tname) == 0) {
+ if (read_xspect(&p_sp, NULL, tname) == 0) {
rd_p = 1;
/* Should read instrument type from debug_p.sp !! */
if (inst_illuminant(&insp, instI1Pro) != 0) /* Hack !! */
@@ -548,8 +548,8 @@ int main(int argc, char *argv[])
printf("Instrument lacks spectral measurement capability");
}
- if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd)
- && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) {
+ if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
+ && it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
if (verb) {
printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
refrmode = -1;
@@ -570,9 +570,9 @@ int main(int argc, char *argv[])
it->capabilities(it, &cap, &cap2, &cap3);
if (c == '1') {
- if (IMODETST(cap, inst_mode_emis_ambient)) {
+ if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
mode = inst_mode_emis_ambient;
- } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ } else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
} else {
printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
@@ -580,9 +580,9 @@ int main(int argc, char *argv[])
}
}
if (c == '2') {
- if (IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
mode = inst_mode_emis_tele;
- } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ } else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
} else {
printf("!!! Instrument doesn't have telephoto or emissive capability !!!\n");
@@ -592,7 +592,7 @@ int main(int argc, char *argv[])
if (c == '3') {
inst_opt_filter filt;
- if (IMODETST(cap, inst_mode_ref_spot)) {
+ if (it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
mode = inst_mode_ref_spot;
} else {
printf("!!! Instrument lacks reflective spot measurement capability !!!\n");
@@ -769,7 +769,7 @@ int main(int argc, char *argv[])
} else {
if (c == '1') {
- if (IMODETST(cap, inst_mode_emis_ambient)) {
+ if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
printf("\n(If applicable) set instrument to ambient measurenent mode, or place\n");
printf("ambient adapter on it, and position it so as to measure the illuminant directly.\n");
} else {
@@ -777,7 +777,7 @@ int main(int argc, char *argv[])
printf("and position it so as to measure the illuminant directly.\n");
}
} else if (c == '2') {
- if (IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
printf("\n(If applicable) set instrument to telephoto measurenent mode,\n");
printf("position it so as to measure the illuminant reflected from the paper.\n");
} else {
@@ -921,19 +921,19 @@ int main(int argc, char *argv[])
continue;
}
- if (c == '1') {
+ if (c == '1') { /* Illuminant */
i_sp = val.sp;
if (tmode && rd_i == 0) {
strcpy(tnp, "_i.sp");
- write_xspect(tname,&i_sp);
+ write_xspect(tname, inst_mrt_emission, &i_sp);
}
- } else if (c == '2') {
+ } else if (c == '2') { /* Illuminant reflected on paper */
r_sp = val.sp;
if (tmode && rd_r == 0) {
strcpy(tnp, "_r.sp");
- write_xspect(tname,&r_sp);
+ write_xspect(tname, inst_mrt_emission, &r_sp);
}
- } else if (c == '3') {
+ } else if (c == '3') { /* Paper reflectance */
p_sp = val.sp;
/* Get the illuminant spectrum too */
@@ -943,7 +943,7 @@ int main(int argc, char *argv[])
if (tmode && rd_p == 0) {
/* Should save instrument type/instrument illuminant spectrum !!! */
strcpy(tnp, "_p.sp");
- write_xspect(tname,&p_sp);
+ write_xspect(tname, inst_mrt_reflective, &p_sp);
}
}
@@ -1125,16 +1125,16 @@ int main(int argc, char *argv[])
for (i = 0; i < ill.spec_n; i++)
ill.spec[i] = aill.spec[i]/nacc;
- if(write_xspect(outname, &ill))
+ if(write_xspect(outname, inst_mrt_ambient, &ill))
printf("\nWriting file '%s' failed\n",outname);
else
printf("\nWriting file '%s' succeeded\n",outname);
if (tmode) {
strcpy(tnp, "_mpir.sp"); // Measured paper under illuminant spectrum
- write_xspect(tname,&bf.srop);
+ write_xspect(tname, inst_mrt_reflective, &bf.srop);
strcpy(tnp, "_cpir.sp"); // Computed paper under illuminant spectrum
- write_xspect(tname,&bf.cpsp);
+ write_xspect(tname, inst_mrt_reflective, &bf.cpsp);
}
}
@@ -1188,9 +1188,9 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.ill.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.ill, j);
- y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
- y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
- y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
}
xmax = bf.ill.spec_wl_long;
@@ -1212,10 +1212,10 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.cpsp.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.cpsp, j);
- y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
- y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
- y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
-// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
}
xmax = bf.cpsp.spec_wl_long;
@@ -1233,8 +1233,8 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.ill.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.ill, j);
- y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
- y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
}
xmax = bf.ill.spec_wl_long;
@@ -1248,9 +1248,9 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.cpsp.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.cpsp, j);
- y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
- y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
- y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
}
xmax = bf.cpsp.spec_wl_long;
diff --git a/spectro/inst.c b/spectro/inst.c
index 8976669..681ef0a 100644
--- a/spectro/inst.c
+++ b/spectro/inst.c
@@ -1,5 +1,5 @@
- /* Abstract instrument class implemenation */
+/* Abstract instrument class implemenation */
/*
* Argyll Color Correction System
@@ -373,6 +373,7 @@ static inst_code calibrate(
inst *p,
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, filter ID) */
return inst_unsupported;
}
@@ -585,7 +586,7 @@ static inst_config config_enum(inst *p, int ec) {
/* Delete things set/done by new_inst() */
static inst_code virtual_del(inst *p) {
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
osx_latencycritical_end();
#endif
@@ -612,7 +613,7 @@ void *cntx /* Context for callback */
return NULL;
}
- a1logd(log, 2, "new_inst: called with path '%s'\n",path->name);
+ a1logd(log, 2, "new_inst: called with path '%s' type '%s'\n",path->name,inst_sname(path->itype));
if ((icom = new_icoms(path, log)) == NULL) {
a1logd(log, 2, "new_inst: new_icoms failed to open it\n");
@@ -625,14 +626,19 @@ void *cntx /* Context for callback */
itype = icom->itype; /* Instrument type if its known from usb/hid */
#if defined(ENABLE_FAST_SERIAL)
- if (itype == instUnknown && !nocoms && (icom->sattr & icom_fast)) {
+ if (itype == instUnknown && !nocoms && (icom->dctype & icomt_fastserial)) {
itype = fast_ser_inst_type(icom, 1, uicallback, cntx); /* Else type from serial */
+ icom->dctype = (icom->dctype & ~icomt_cat_mask) | inst_category(itype);
+ a1logd(log, 8, "new_inst: fast set '%s' dctype 0x%x\n",icom->name,icom->dctype);
}
#endif /* ENABLE_FAST_SERIAL */
#if defined(ENABLE_SERIAL)
- if (itype == instUnknown && !nocoms)
+ if (itype == instUnknown && !nocoms) {
itype = ser_inst_type(icom, uicallback, cntx); /* Else type from serial */
+ icom->dctype = (icom->dctype & ~icomt_cat_mask) | inst_category(itype);
+ a1logd(log, 8, "new_inst: set '%s' dctype 0x%x\n",icom->name,icom->dctype);
+ }
#endif /* ENABLE_SERIAL */
@@ -657,7 +663,8 @@ void *cntx /* Context for callback */
#ifdef ENABLE_FAST_SERIAL
if (itype == instSpecbos1201
- || itype == instSpecbos)
+ || itype == instSpecbos
+ || itype == instSpectraval)
p = (inst *)new_specbos(icom, itype);
if (itype == instKleinK10)
p = (inst *)new_kleink10(icom, itype);
@@ -696,8 +703,10 @@ void *cntx /* Context for callback */
p = (inst *)new_huey(icom, itype);
else if (itype == instSmile)
p = (inst *)new_i1disp(icom, itype);
+#ifdef ENABLE_FAST_SERIAL
else if (itype == instSMCube)
p = (inst *)new_smcube(icom, itype);
+#endif
else if (itype == instHCFR)
p = (inst *)new_hcfr(icom, itype);
else if (itype == instColorHug
@@ -799,7 +808,7 @@ void *cntx /* Context for callback */
/* Set the provided user interaction callback */
p->set_uicallback(p, uicallback, cntx);
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
osx_latencycritical_start();
#endif
@@ -917,8 +926,10 @@ int doccmx /* Add matching installed ccmx files */
for (i = 0; ss_list[i].path != NULL; i++) {
- if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL) {
+ free_iccss(ss_list);
return inst_internal_error;
+ }
list[nlist-1].flags = inst_dtflags_ccss | inst_dtflags_ld | inst_dtflags_wr;
if (!ss_list[i].oem)
@@ -938,6 +949,7 @@ int doccmx /* Add matching installed ccmx files */
list[nlist-1].sets = ss_list[i].sets; ss_list[i].sets = NULL;
list[nlist-1].no_sets = ss_list[i].no_sets; ss_list[i].no_sets = 0;
}
+ free_iccss(ss_list);
}
/* Add any OEM and custom ccmx's */
@@ -963,8 +975,10 @@ int doccmx /* Add matching installed ccmx files */
continue;
}
- if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL) {
+ free_iccmx(ss_list);
return inst_internal_error;
+ }
list[nlist-1].flags = inst_dtflags_ccmx | inst_dtflags_ld | inst_dtflags_wr;
if (!ss_list[i].oem)
@@ -984,6 +998,7 @@ int doccmx /* Add matching installed ccmx files */
list[nlist-1].cc_cbid = ss_list[i].cc_cbid;
icmCpy3x3(list[nlist-1].mat, ss_list[i].mat);
}
+ free_iccmx(ss_list);
}
/* Copy candidate selectors to private isel[] list */
@@ -1047,6 +1062,39 @@ int doccmx /* Add matching installed ccmx files */
return inst_ok;
}
+/* --------------------------------------------------- */
+
+/* Delayed scan-ready prompt handler */
+static int delayed_scan_ready(void *pp) {
+ inst *p = (inst *)pp;
+
+ msec_sleep(p->scan_ready_delay);
+ a1logd(g_log,8, "delayed scan_ready activate\n");
+
+ if (p->eventcallback != NULL)
+ p->eventcallback(p->event_cntx, inst_event_scan_ready);
+ return 0;
+}
+
+/* Issue an inst_event_scan_ready event/prompt after a delay */
+void issue_scan_ready(inst *p, int delay) {
+ a1logd(g_log,8, "msec_scan_ready %d msec\n",delay);
+
+ if (p->eventcallback == NULL) /* Hmm. */
+ return;
+
+ if (delay > 0) {
+ if (p->scan_ready_thread != NULL)
+ p->scan_ready_thread->del(p->scan_ready_thread);
+ p->scan_ready_delay = delay;
+ if ((p->scan_ready_thread = new_athread(delayed_scan_ready, (void *)p)) == NULL)
+ a1logw(g_log, "msec_scan_ready: Delayed scan_ready failed to create thread\n");
+ } else {
+ a1logd(g_log,8, "msec_scan_ready activate\n");
+ p->eventcallback(p->event_cntx, inst_event_scan_ready);
+ }
+}
+
/* ============================================================= */
/* CCMX location support */
@@ -1089,6 +1137,7 @@ iccmx *list_iccmx(instType itype, int *no) {
free(rv[j].desc);
}
xdg_free(paths, npaths);
+ free(rv);
if (no != NULL) *no = -1;
return NULL;
}
@@ -1098,8 +1147,10 @@ iccmx *list_iccmx(instType itype, int *no) {
}
/* Skip any that don't match */
- if (itype != instUnknown && cs->inst != NULL && inst_enum(cs->inst) != itype)
+ if (itype != instUnknown && cs->inst != NULL && inst_enum(cs->inst) != itype) {
+ cs->del(cs);
continue;
+ }
a1logd(g_log, 5, "Reading '%s'\n",paths[i]);
if ((tech = cs->tech) == NULL)
@@ -1336,21 +1387,38 @@ instType fast_ser_inst_type(
void *cntx /* Context for callback */
) {
instType rv = instUnknown;
-#define BUFSZ (128 + 10)
+#define BUFSZ (2048 + 10)
char buf[BUFSZ];
- baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_9600, baud_nc };
+ baud_rate brt1[] = { baud_9600, baud_921600, baud_115200,
+ baud_38400, baud_nc }; /* HS - do K10/Spectrolino first */
+ baud_rate brt2[] = { baud_115200, baud_nc }; /* Bluetooth */
+
+ baud_rate *brt = brt1;
unsigned int etime;
unsigned int i;
+ int delayms = 0;
int se, len;
+ double tryto = 0.1; /* [0.1] Communication timout */
+// double tryto = 0.9; /* Communication timout (test) */
- if (p->port_type(p) != icomt_serial
- && p->port_type(p) != icomt_usbserial)
+ a1logd(p->log, 8, "fast_ser_inst_type: on '%s' dctype 0x%x\n",p->name,p->dctype);
+
+ if (!(p->dctype & icomt_seriallike)
+ && !(p->dctype & icomt_fastserial)) {
return p->itype;
+ }
/* The tick to give up on */
etime = msec_time() + (long)(2000.0 + 0.5);
+// etime = msec_time() + (long)(20000.0 + 0.5); /* (test) */
- a1logd(p->log, 1, "fser_inst_type: Trying different baud rates (%u msec to go)\n",etime - msec_time());
+ a1logd(p->log, 1, "fser_inst_type: Trying different baud rates (%u msec to go) Path %s%s\n",
+ etime - msec_time(),p->spath,(p->dctype & icomt_btserial) ? " [Bluetooth]" : "");
+
+ if (p->dctype & icomt_btserial) {
+ brt = brt2; /* Only try BT relevant baud rates. */
+ delayms = 600; /* Spectraval locks up otherwise. */
+ }
/* Until we time out, find the correct baud rate */
for (i = 0; msec_time() < etime; i++) {
@@ -1361,40 +1429,97 @@ instType fast_ser_inst_type(
}
a1logd(p->log, 5, "Trying %s baud\n",baud_rate_to_str(brt[i]));
- if ((se = p->set_ser_port(p, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
+ if ((se = p->set_ser_port_ex(p, fc_None, brt[i], parity_none,
+ stop_1, length_8, delayms)) != ICOM_OK) {
a1logd(p->log, 5, "fser_inst_type: set_ser_port failed with 0x%x\n",se);
- return instUnknown; /* Give up */
+ return instUnknown; /* Give up on port */
}
- if (brt[i] == baud_9600) {
- /* See if it's a Klein K10 */
+ /* Assume Klein K10 only uses 9600. */
+ /* We need to also assume that we might be talking to a Spectrolino, */
+ /* and avoid upsetting it. */
+ if ((p->dctype & icomt_btserial) == 0 && brt[i] == baud_9600) {
+ double sto = 0.2; /* Give 9600 a little more time */
+ int bread, len;
+
+ /* Try a spectrolino/spectroscan command first */
+ if (tryto > sto)
+ sto = tryto;
+ p->write_read_ex(p, ";D024\r\n", 0, buf, BUFSZ-1, &bread, "\r", 1, sto, 1);
+
+ if (bread == 0) {
+ a1logd(p->log, 5, "fser_inst_type: Spectroino command returned nothing\n");
+ goto not_k10;
+ }
+ buf[bread] = '\000';
+ len = strlen(buf);
+
+ a1logd(p->log, 5, "fser_inst_type: got %d bytes\n",len);
- if ((se = p->write_read(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ if (len < 4) {
+ a1logd(p->log, 5, "fser_inst_type: Reply was too short\n");
+ goto not_k10; /* Not K10, X-Rite or Spectrolino */
+ }
+
+ /* Is this a Spectrolino or Spectroscan error resonse ? */
+ if (len >= 5 && strncmp(buf, ":26", 3) == 0
+ || len >= 7 && strncmp(buf, ":D183", 5) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: Ignore Spectrolino\n");
+ return instUnknown; /* Not doing Spectrolino detection here */
+ }
+
+ /* Is this an X-Rite error value such as "<01>" ? */
+ if (buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
+ a1logd(p->log, 5, "fser_inst_type: Ignore X-Rite\n");
+ return instUnknown; /* Not doing X-Rite detection here */
+ }
+
+ /* The Klein K10 seems to respond with it's calibration list, preceeded by "D4" ? */
+ if (buf[0] != 'D' || buf[1] != '4') {
+ a1logd(p->log, 5, "fser_inst_type: Not Klein response\n");
+ goto not_k10;;
+ }
+
+ a1logd(p->log, 5, "fser_inst_type: Looks like it may be a Klein\n");
+
+ /* Confirm this is a Klein instrument */
+
+ /* The first response is the calibration list, and it may need flushing. */
+ /* (write_read_ex doesn't cope with time it takes to dump this.) */
+ for (;;) {
+ bread = 0;
+ p->read(p, buf, BUFSZ, &bread, NULL, BUFSZ, 0.1);
+ if (bread == 0)
+ break;
+ }
+
+ if ((se = p->write_read_ex(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, tryto, 1)) == inst_ok) {
+
+ /* Is this a Klein K1/K8/K10 response ? */
+ if (strncmp(buf, "P0K-1 ", 6) == 0
+ || strncmp(buf, "P0K-8 ", 6) == 0
+ || strncmp(buf, "P0K-10", 6) == 0
+ || strncmp(buf, "P0KV-10", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
+ rv = instKleinK10;
+ break;
+ }
+ }
+
+ not_k10:;
+
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
a1logd(p->log, 5, "fser_inst_type: User aborted\n");
return instUnknown;
- }
}
- continue;
- }
- len = strlen(buf);
-
- /* Is this a Klein K1/K8/K10 response ? */
- if (strncmp(buf, "P0K-1 ", 6) == 0
- || strncmp(buf, "P0K-8 ", 6) == 0
- || strncmp(buf, "P0K-10", 6) == 0
- || strncmp(buf, "P0KV-10", 7) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
- rv = instKleinK10;
- break;
}
}
- if (brt[i] == baud_38400)
- {
+
+ /* SwatchMate Cube only uses 38400 */
+ if ((p->dctype & icomt_btserial) == 0 && brt[i] == baud_38400) {
int bread;
/* See if it's a SwatchMate Cube. */
@@ -1403,56 +1528,81 @@ instType fast_ser_inst_type(
buf[1] = 0x00;
buf[2] = 0x02; /* Ping command */
buf[3] = 0x00;
- if ((se = p->write_read(p, buf, 4, buf, BUFSZ, &bread, NULL, 4, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 5, "fser_inst_type: User aborted\n");
- return instUnknown;
+ if ((se = p->write_read_ex(p, buf, 4, buf, BUFSZ, &bread, NULL, 4, tryto, 1)) == inst_ok) {
+ if (bread == 4) {
+ if (buf[0] == 0x7e && buf[1] == 0x20 && buf[2] == 0x02 && buf[3] == 0x00) {
+ a1logd(p->log, 5, "fser_inst_type: found SwatchMate Cube\n");
+ rv = instSMCube;
+ break;
}
}
- continue;
}
- if (bread == 4) {
- if (buf[0] == 0x7e && buf[1] == 0x20 && buf[2] == 0x02 && buf[3] == 0x00) {
- a1logd(p->log, 5, "fser_inst_type: found SwatchMate Cube\n");
- rv = instSMCube;
- break;
+
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 5, "fser_inst_type: User aborted\n");
+ return instUnknown;
}
}
}
- /* Bluetooth only uses baud_115200 */
- if ((p->sattr & icom_bt) == 0 || brt[i] == baud_115200) {
+
+ /* JETI specbos or spectraval. */
+ /* We are fudging the baud rate selection here - */
+ /* the 1211 RS and BT can't handle 921600, */
+ /* while the 15x1 can handle 230400 & 3000000, which we don't test for... */
+// if ((p->dctype & icomt_btserial) == 0 || brt[i] == baud_115200)
+ if (brt[i] == baud_38400 || brt[i] == baud_115200 || brt[i] == baud_921600)
+ {
+ int bread;
/* See if it's a JETI specbos */
- if ((se = p->write_read(p, "*idn?\r", 0, buf, BUFSZ, NULL, "\r", 1, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 5, "fser_inst_type: User aborted\n");
- return instUnknown;
- }
+ p->write_read_ex(p, "*idn?\r", 0, buf, BUFSZ, &bread, "\r", 1, tryto, 1);
+ if (bread > 0) {
+ len = strlen(buf);
+
+ /* JETI specbos returns "JETI_SBXXXX", where XXXX is the instrument type, */
+ /* except for the 1201 which returns "SB05" */
+ /* The spectraval 1501 returns JETI_SDCM3 NNNNNNN */
+
+ /* 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 (len > 9 && strncmp(buf, "AT+JSCR\r\n", 9) == 0) {
+ memmove(buf, buf+9, len-9);
+ len -= 9;
+ }
+
+ /* Is this a JETI specbos 1201 response ? */
+ if (strncmp(buf, "SB05", 4) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI specbos 1201\n");
+ rv = instSpecbos1201;
+ break;
+ }
+ /* Is this a JETI specbos XXXX response ? */
+ if (len >= 11 && strncmp(buf, "JETI_SB", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI specbos\n");
+ rv = instSpecbos;
+ break;
+ }
+ /* Is this a JETI spectraval response ? */
+ /* (Bluetooth returns "DCM3_JETI ... and other rubbish for some reason.) */
+ if ((len >= 10 && strncmp(buf, "JETI_SDCM3", 10) == 0)
+ || (len >= 9 && strncmp(buf, "DCM3_JETI", 9) == 0)
+ || (len >= 17 && strncmp(buf, "PECFIRM_JETI_1501", 17) == 0)
+ || (len >= 18 && strncmp(buf, "SPECFIRM_JETI_1501", 18) == 0)) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI spectraval\n");
+ rv = instSpectraval;
+ break;
}
- continue;
- }
- len = strlen(buf);
-
- /* JETI specbos returns "JETI_SBXXXX", where XXXX is the instrument type, */
- /* except for the 1201 which returns "SB05" */
-
- /* Is this a JETI specbos 1201 response ? */
- if (strncmp(buf, "SB05", 4) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found JETI specbos 1201\n");
- rv = instSpecbos1201;
- break;
}
- /* Is this a JETI specbos XXXX response ? */
- if (len >= 11 && strncmp(buf, "JETI_SB", 7) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found JETI specbos\n");
- rv = instSpecbos;
- break;
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 5, "fser_inst_type: User aborted\n");
+ return instUnknown;
+ }
}
}
}
@@ -1492,11 +1642,12 @@ static instType ser_inst_type(
#define BUFSZ (128 + 10)
char buf[BUFSZ];
baud_rate brt[] = { baud_9600, baud_19200, baud_4800, baud_2400,
- baud_1200, baud_38400, baud_57600, baud_115200,
- baud_600, baud_300, baud_110, baud_nc };
+ baud_1200, baud_38400, baud_57600, baud_115200,
+ baud_600, baud_300, baud_110, baud_nc };
unsigned int etime;
unsigned int bi, i;
int se, len, bread;
+ int klein = 0;
int xrite = 0;
int ss = 0;
int so = 0;
@@ -1517,7 +1668,7 @@ static instType ser_inst_type(
for (i = bi; msec_time() < etime; i++) {
if (brt[i] == baud_nc)
i = 0;
- if ((se = p->set_ser_port(p, fc_none, brt[i], parity_none,
+ if ((se = p->set_ser_port(p, fc_None, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
a1logd(p->log, 5, "ser_inst_type: set_ser_port failed with 0x%x\n",se);
return instUnknown; /* Give up */
@@ -1525,7 +1676,11 @@ static instType ser_inst_type(
a1logd(p->log, 5, "Trying %s baud\n",baud_rate_to_str(brt[i]));
bread = 0;
- if ((se = p->write_read(p, ";D024\r\n", 0, buf, BUFSZ, &bread, "\r", 1, 0.5)) != inst_ok) {
+
+ /* Try a spectrolino/spectroscan command first */
+ p->write_read_ex(p, ";D024\r\n", 0, buf, BUFSZ-1, &bread, "\r", 1, 0.5, 1);
+
+ if (bread == 0) {
/* Check for user abort */
if (uicallback != NULL) {
inst_code ev;
@@ -1534,15 +1689,24 @@ static instType ser_inst_type(
return instUnknown;
}
}
- if (bread == 0)
- continue;
+ continue;
}
+ buf[bread] = '\000';
len = strlen(buf);
// a1logd(p->log, 5, "len = %d\n",len);
if (len < 4)
continue;
+ /* The Klein K10 seems to respond with it's calibration list, preceeded by "D4" ? */
+ /* - don't know how reliable this is though. Another way may be to look for a */
+ /* response len > 100 characters ?? */
+ if (buf[0] == 'D' && buf[1] == '4') {
+// a1logd(p->log, 5, "klein\n");
+ klein = 1;
+ break;
+ }
+
/* Is this an X-Rite error value such as "<01>" ? */
if (buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
// a1logd(p->log, 5, "xrite\n");
@@ -1580,7 +1744,7 @@ static instType ser_inst_type(
/* SpectroScan */
if (ss) {
rv = instSpectroScan;
- if ((se = p->write_read(p, ";D030\r\n", 0, buf, BUFSZ, NULL, "\n", 1, 1.5)) == 0) {
+ if ((se = p->write_read_ex(p, ";D030\r\n", 0, buf, BUFSZ, NULL, "\n", 1, 1.5, 1)) == 0) {
if (strlen(buf) >= 41) {
hex2bin(&buf[5], 12);
// a1logd(p->log, 5, "spectroscan type = '%s'\n",buf);
@@ -1592,7 +1756,7 @@ static instType ser_inst_type(
if (xrite) {
/* Get the X-Rite model and version number */
- if ((se = p->write_read(p, "SV\r\n", 0, buf, BUFSZ, NULL, ">", 1, 2.5)) != 0)
+ if ((se = p->write_read_ex(p, "SV\r\n", 0, buf, BUFSZ, NULL, ">", 1, 2.5, 1)) != 0)
return instUnknown;
if (strlen(buf) >= 12) {
@@ -1613,6 +1777,31 @@ static instType ser_inst_type(
}
}
+ if (klein) {
+
+ /* The first response is the calibration list, and it may need flushing. */
+ /* (write_read_ex doesn't cope with time it takes to dump this.) */
+ for (;;) {
+ bread = 0;
+ p->read(p, buf, BUFSZ, &bread, NULL, BUFSZ, 0.1);
+ if (bread == 0)
+ break;
+ }
+
+ /* See if this is a Klein K10 or similar */
+ if ((se = p->write_read_ex(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, 1.5, 1)) != inst_ok)
+ return instUnknown;
+
+ /* Is this a Klein K1/K8/K10 response ? */
+ if (strncmp(buf, "P0K-1 ", 6) == 0
+ || strncmp(buf, "P0K-8 ", 6) == 0
+ || strncmp(buf, "P0K-10", 6) == 0
+ || strncmp(buf, "P0KV-10", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
+ rv = instKleinK10;
+ }
+ }
+
a1logd(p->log, 5, "ser_inst_type: Instrument type is '%s'\n", inst_name(rv));
p->close_port(p); /* Or should we leave it open ?? */
@@ -1732,6 +1921,25 @@ int sym_to_inst_mode(inst_mode *mode, const char *sym) {
return rv;
}
+/* ============================================================= */
+/* Utilities */
+
+/* Return a string for the xcalstd enum */
+char *xcalstd2str(xcalstd std) {
+ switch(std) {
+ case xcalstd_native:
+ return "NATIVE";
+ case xcalstd_xrdi:
+ return "XRDI";
+ case xcalstd_gmdi:
+ return "GMDI";
+ case xcalstd_xrga:
+ return "XRGA";
+ default:
+ break;
+ }
+ return "None";
+}
diff --git a/spectro/inst.h b/spectro/inst.h
index 736a879..01f579d 100644
--- a/spectro/inst.h
+++ b/spectro/inst.h
@@ -1,13 +1,15 @@
#ifndef INST_H
- /* instlib API definition. */
-
- /* See spotread.c, chartread.c, illumread.c & ccxxmake.c for examples of */
- /* the API usage. */
-
- /* Abstract base class for common color instrument interface */
- /* and other common instrument stuff. */
+/*
+ * instlib API definition.
+ *
+ * See spotread.c, chartread.c, illumread.c & ccxxmake.c for examples of
+ * the API usage.
+ *
+ * Abstract base class for common color instrument interface
+ * and other common instrument stuff.
+ */
/*
* Argyll Color Correction System
@@ -64,7 +66,7 @@
/* ------------------------------------------------- */
/* Structure for holding an instrument patch reading */
-#define ICOM_MAX_LOC_LEN 10
+#ifdef NEVER /* Declared in xicc/xspect.h */
/* Type of measurement result */
typedef enum { /* XYZ units, Spectral units */
@@ -78,6 +80,10 @@ typedef enum { /* XYZ units, Spectral units */
inst_mrt_frequency = 7 /* Hz */
} inst_meas_type;
+#endif // NEVER
+
+#define ICOM_MAX_LOC_LEN 10
+
struct _ipatch {
char loc[ICOM_MAX_LOC_LEN]; /* patch location */
@@ -95,11 +101,25 @@ struct _ipatch {
}; typedef struct _ipatch ipatch;
+/* ------------------------------------------------------ */
+/* Gretag/X-Rite specific reflective measurement standard */
+
+typedef enum {
+ xcalstd_none = -2, /* Not set */
+ xcalstd_native = -1, /* No conversion */
+ xcalstd_xrdi = 0, /* Historical X-Rite */
+ xcalstd_gmdi = 1, /* Historical Gretag-Macbeth */
+ xcalstd_xrga = 2, /* Current X-Rite */
+} xcalstd;
+
+/* Return a string for the xcalstd enum */
+char *xcalstd2str(xcalstd std);
+
/* ---------------------------------------- */
/* Instrument interface abstract base class */
-/* Abstract return codes in ms byte. */
-/* Instrument dependant codes in ls byte. */
+/* Abstract return codes in ms 8bits. */
+/* Instrument dependant codes in ls 16 bits. */
/* Note :- update inst_interp_error() in inst.c if anything here is changed. */
/* and also check all the instrument specific XXX_interp_code() routines too. */
typedef enum {
@@ -163,7 +183,7 @@ typedef enum {
typedef enum {
inst_mode_none = 0x00000000, /* No capability or mode */
- /* Mode of light measurement */
+ /* Light measurement mode */
inst_mode_reflection = 0x00000001, /* General reflection mode */
# define inst_mode_reflection_sym "REFL"
inst_mode_s_reflection = 0x00000002, /* General saved reflection mode */
@@ -174,7 +194,7 @@ typedef enum {
# define inst_mode_emission_sym "EMIS"
inst_mode_illum_mask = 0x0000000f, /* Mask of sample illumination sub mode */
- /* Access mode of measurement */
+ /* Action of measurement */
inst_mode_spot = 0x00000010, /* General spot measurement mode */
# define inst_mode_spot_sym "SPOT"
inst_mode_strip = 0x00000020, /* General strip measurement mode */
@@ -241,7 +261,9 @@ typedef enum {
| inst_mode_s_reflection,
inst_mode_trans_spot = inst_mode_spot /* Transmission spot measurement mode */
- | inst_mode_transmission,
+ | inst_mode_transmission, /* Normal Diffuse/90 */
+ inst_mode_trans_spot_a = inst_mode_ambient /* Transmission spot measurement mode */
+ | inst_mode_transmission, /* Alternate 90/diffuse */
inst_mode_trans_strip = inst_mode_strip /* Transmission strip measurement mode */
| inst_mode_transmission,
inst_mode_trans_xy = inst_mode_xy /* Transmission X-Y measurement mode */
@@ -267,6 +289,8 @@ typedef enum {
} inst_mode;
/* Test for a specific mode */
+/* (This isn't foolproof - it->check_mode() is better for modes */
+/* composed of more than one bit) */
#define IMODETST(mbits, mode) (((mbits) & (mode)) == (mode))
/* Test for a specific mode in capability and mode */
@@ -299,8 +323,11 @@ typedef enum {
inst2_emis_refr_meas = 0x00000080, /* Has an emissive refresh rate measurement func. */
inst2_prog_trig = 0x00000100, /* Progromatic trigger measure capability */
- inst2_user_trig = 0x00000200, /* User trigger measure capability */
- inst2_switch_trig = 0x00000400, /* Inst. switch trigger measure capability */
+ inst2_user_trig = 0x00000200, /* User trigger measure capability, */
+ /* i.e. via user button and uicallback. */
+ inst2_switch_trig = 0x00000400, /* Inst. switch trigger measure capability, */
+ /* i.e. instrument directly starts measurement */
+ /* via mechanical switch. */
inst2_user_switch_trig = 0x00000800, /* User or switch trigger measure capability */
inst2_bidi_scan = 0x00001000, /* Try and recognise patches scanned from either dir. */
@@ -356,6 +383,11 @@ typedef enum {
optional password
configuration specific calibrations. How are they marked ?
+
+
+ Also for ccss capable instruments:
+
+ write corresponding ccmx for given ccss.
*/
typedef enum {
@@ -446,7 +478,7 @@ typedef enum {
inst_opt_trig_prog = 0x000E, /* Trigger progromatically [No args] */
inst_opt_trig_user = 0x000F, /* Trigger from user via uicallback [No args] */
- inst_opt_trig_switch = 0x0010, /* Trigger using instrument switch [No args] */
+ inst_opt_trig_switch = 0x0010, /* Trigger directly using instrument switch [No args] */
inst_opt_trig_user_switch = 0x0011, /* Trigger from user via uicallback or switch (def) [No args] */
inst_opt_highres = 0x0012, /* Enable high res spectral mode indep. of set_mode() */
@@ -468,12 +500,24 @@ typedef enum {
inst_opt_get_min_int_time = 0x001D, /* Get the minimum integration time [*double time] */
inst_opt_set_min_int_time = 0x001E, /* Set the minimum integration time [double time] */
- inst_opt_opt_calibs_valid = 0x001F, /* Are optional calibrations valid [*int valid] */
- inst_opt_clear_opt_calibs = 0x0020 /* Clear all optional calibrations. */
+ inst_opt_opt_calibs_valid = 0x001F, /* Are optional (white/black/gloss etc.) calibrations */
+ /* valid? [*int valid] */
+ inst_opt_clear_opt_calibs = 0x0020, /* Clear all optional calibrations. */
+
+ inst_opt_get_cal_tile_sp = 0x0021, /* Return refl. white tile reference spectrum. */
+ /* for current filter. [*xspect tile] */
+
+ inst_opt_set_xcalstd = 0x0022, /* Set the X-Rite reflective calibration standard */
+ /* [xcalstd standard] */
+ inst_opt_get_xcalstd = 0x0023, /* Get the effective X-Rite ref. cal. standard */
+ /* [xcalstd *standard] */
+ inst_opt_lamp_remediate = 0x0024 /* Remediate i1Pro lamp [double seconds] */
+
} inst_opt_type;
/* Optional filter fitted to instrument (for inst_opt_set_filter) */
+/* Set this before calling init_coms() */
typedef enum {
inst_opt_filter_unknown = 0xffff, /* Unspecified filter */
inst_opt_filter_none = 0x0000, /* No filters fitted */
@@ -588,24 +632,42 @@ typedef enum {
} inst_cal_cond;
+/* Condition identifier message type. This can be useful in internationalizing the */
+/* string returned in id[] from calibrate() */
+typedef enum {
+ inst_calc_id_none = 0x00000000, /* No id */
+ inst_calc_id_ref_sn = 0x00000001, /* Calibration reference (ie. tile) serial number */
+
+ inst_calc_id_trans_low = 0x00010000, /* Trans. Ref. light is too low for accuracy warning */
+ inst_calc_id_trans_wl = 0x00020000, /* Trans. Ref. light is low at some wavelengths warning */
+ inst_calc_id_filt_unkn = 0x00100000, /* Request unknown filter */
+ inst_calc_id_filt_none = 0x00200000, /* Request no filter */
+ inst_calc_id_filt_pol = 0x00300000, /* Request polarizing filter */
+ inst_calc_id_filt_D65 = 0x00400000, /* Request D65 filter */
+ inst_calc_id_filt_UV = 0x00500000, /* Request UV cut filter */
+ inst_calc_id_filt_cust = 0x00600000 /* Request custom filter */
+} inst_calc_id_type;
+
/* Clamping state */
typedef enum {
instNoClamp = 0, /* Don't clamp XYZ/Lab to +ve */
instClamp = 1, /* Clamp XYZ/Lab to +ve */
} instClamping;
-/* User interaction callback function purpose */
+/* User interaction callback (uicallback()) function purpose */
typedef enum {
- inst_negcoms, /* Negotiating communications */
- inst_triggered, /* Measurement has been triggered by switch or user (not progromatic) */
- inst_armed, /* Armed and waiting for a measurement trigger */
- inst_measuring /* Busy measuring */
+ inst_negcoms, /* Negotiating communications - can abort */
+ inst_armed, /* Armed and waiting for a measurement trigger - can wait, trigger, abort */
+ inst_triggered, /* Measurement triggered by switch or user (not progromatic) - notice */
+ /* (Also triggered by switch driven calibration,i.e. DTP41) */
+ inst_measuring /* Busy measuring - can abort */
} inst_ui_purp;
/* Asynchronous event callback type */
typedef enum {
- inst_event_switch, /* Instrument measure/calibrate switch pressed */
- inst_event_mconf /* Change in measurement configuration (ie. sensor position) */
+ inst_event_switch, /* Instrument measure/calibrate switch pressed. */
+ inst_event_mconf, /* Change in measurement configuration (ie. sensor position) */
+ inst_event_scan_ready /* Ready for manual strip scan (i.e. issue audible prompt) */
} inst_event_type;
/* Instrument configuration/sensor position*/
@@ -641,7 +703,9 @@ typedef enum {
inst_code (*uicallback)(void *cntx, inst_ui_purp purp); \
void *uic_cntx; /* User interaction callback function */ \
void (*eventcallback)(void *cntx, inst_event_type event); \
- void *event_cntx; /* Event callback function */ \
+ void *event_cntx; /* Asynchronous event callback function */ \
+ athread *scan_ready_thread; /* msec_scan_ready() support */ \
+ int scan_ready_delay; /* msec_scan_ready() support */ \
\
/* Virtual delete. Cleans up things done by new_inst(). */ \
inst_code (*vdel)( \
@@ -819,15 +883,15 @@ typedef enum {
\
\
/* Read a set of strips (applicable to strip reader) */ \
- /* Obeys the trigger mode set, and may return user trigger code */ \
- /* (to hint that a user command may be available) */ \
+ /* Obeys the trigger mode set, and may return user trigger code, */ \
+ /* to hint that a user command may be available. */ \
/* Return the inst error code */ \
inst_code (*read_strip)( \
struct _inst *p, \
- char *name, /* Strip name (up to 7 chars) */ \
+ char *name, /* Strip name (up to 7 chars, for DTP51) */ \
int npatch, /* Number of patches in each pass */ \
- char *pname, /* Pass name (3 chars) */ \
- int sguide, /* Guide number (decrements by 5) */ \
+ char *pname, /* Pass name (3 chars, for DTP51) */ \
+ int sguide, /* Guide number (for DTP51, decrements by 5) */ \
double pwid, /* Patch width in mm (For DTP20/DTP41) */ \
double gwid, /* Gap width in mm (For DTP20/DTP41) */ \
double twid, /* Trailer width in mm (For DTP41T) */ \
@@ -836,9 +900,9 @@ typedef enum {
\
/* Read a single sample (applicable to spot instruments) */ \
/* Obeys the trigger mode set, and may return user trigger code */ \
- /* Values are in XYZ 0..100 for reflective transmissive, */ \
- /* aXYZ in cd/m^2 for emissive, amd Lux/3.1415926 for ambient. */ \
- /* Spectral will be analogous to the XYZ. */ \
+ /* Values are in XYZ % (0..100) for reflective & transmissive, */ \
+ /* cd/m^2 for emissive, and Lux for ambient. */ \
+ /* Spectral will be analogous to the XYZ (see inst_meas_type). */ \
/* By default values may be -ve due to noise (depending on instrument) */ \
/* Return the inst error code */ \
inst_code (*read_sample)( \
@@ -916,8 +980,10 @@ typedef enum {
struct _inst *p, \
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, filter ID) */ \
+ /* reference ID, filter ID, message string, */ \
+ /* etc.) */ \
\
/* Measure a display update, and instrument reaction time. It is */ \
/* assumed that a white to black change will be made to the */ \
@@ -1006,12 +1072,12 @@ typedef enum {
* For inst_negcoms, the return value of inst_user_abort \
* will abort the communication negotiation. \
* \
- * For inst_triggered, the return value of the callback is ignored. \
- * \
* For inst_armed return value should be one of: \
* inst_ok to do nothing, inst_user_abort to abort the measurement, \
* or inst_user_trig to trigger the measurement. \
* \
+ * For inst_triggered, the return value of the callback is ignored. \
+ * \
* For inst_measuring the return value should be one of: \
* inst_ok to do nothing, inst_user_abort to abort the measurement. \
* \
@@ -1022,10 +1088,11 @@ typedef enum {
void *cntx); \
\
/* Supply an aynchronous event callback function. \
- * This is called from a thread with the following possible events: \
+ * This is called from a different thread with the following possible events: \
* \
* inst_event_switch: Instrument measure/calibrate switch pressed \
* inst_event_mconf: The measurement configuration has changed (ie. sensor position) \
+ * inst_event_scan_ready: Ready for manual strip scan (i.e. issue audible prompt) \
* \
* NULL can be set to disable the callback. \
*/ \
@@ -1068,7 +1135,8 @@ extern inst *new_inst(
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Implementation functions used by drivers */
+/* Implementation functions used by instrument drivers */
+/* (Client code should not call these) */
/* Get a status or set or get an option (default implementation) */
inst_code inst_get_set_opt_def(
@@ -1090,6 +1158,10 @@ int doccmx /* Add matching installed ccmx files */
/* Free a display type list */
void inst_del_disptype_list(inst_disptypesel *list, int no);
+/* - - - - - - - - - - - - - - - - - - -- */
+
+/* Issue an inst_event_scan_ready event after a delay */
+void issue_scan_ready(inst *p, int delay);
/* - - - - - - - - - - - - - - - - - - -- */
/* CCMX support - ccmx instrument proxy */
diff --git a/spectro/instappsup.c b/spectro/instappsup.c
index d2ce7ff..fc550b4 100644
--- a/spectro/instappsup.c
+++ b/spectro/instappsup.c
@@ -1,5 +1,5 @@
- /* Instrument command line application support functions */
+/* Instrument command line application support functions */
/*
* Argyll Color Correction System
@@ -72,7 +72,6 @@ static inst_code def_uicallback(void *cntx, inst_ui_purp purp) {
return inst_user_trig;
}
- /* Change in measurement configuration */
} else if (purp == inst_measuring) {
return inst_ok;
}
@@ -173,8 +172,9 @@ inst_code inst_handle_calibrate(
int doimmediately /* If nz, don't wait for user, calibrate immediatley */
) {
inst_code rv = inst_ok, ev;
- int usermes = 0; /* User was given a message */
- char id[200]; /* Condition identifier */
+ int usermes = 0; /* User was given a message */
+ inst_calc_id_type idtype; /* Condition identifier type */
+ char id[200]; /* Condition identifier */
int ch;
a1logd(p->log,1,"inst_handle_calibrate called\n");
@@ -183,13 +183,15 @@ inst_code inst_handle_calibrate(
for (;;) {
a1logd(p->log,1,"About to call calibrate at top of loop\n");
- ev = p->calibrate(p, &calt, &calc, id);
+ ev = p->calibrate(p, &calt, &calc, &idtype, id);
a1logd(p->log,1,"Calibrate returned calt 0x%x, calc 0x%x, ev 0x%x\n",calt,calc,ev);
/* We're done */
if ((ev & inst_mask) == inst_ok) {
- if ((calc & inst_calc_cond_mask) == inst_calc_message)
+ if ((calc & inst_calc_cond_mask) == inst_calc_message) {
+ /* (Or could create our own message text based on value of idtype) */
printf("%s\n",id);
+ }
if (usermes)
printf("Calibration complete\n");
fflush(stdout);
@@ -249,7 +251,7 @@ inst_code inst_handle_calibrate(
break;
case inst_calc_man_ref_white:
- printf("Place the instrument on its reflective white reference %s,\n",id);
+ printf("Place the instrument on its reflective white reference S/N %s,\n",id);
printf(" and then hit any key to continue,\n");
break;
@@ -448,12 +450,12 @@ inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *ic
olen = strlen(oline); /* lenth of option part of line */
- for (i = 0; icmps != NULL && i < icmps->npaths; i++) {
+ for (i = 0; icmps != NULL && i < icmps->ndpaths[dtix_inst]; i++) {
inst *it;
inst2_capability cap;
int k;
- if ((it = new_inst(icmps->paths[i], 1, g_log, NULL, NULL)) == NULL) {
+ if ((it = new_inst(icmps->dpaths[dtix_inst][i], 1, g_log, NULL, NULL)) == NULL) {
notall = 1;
continue;
}
diff --git a/spectro/instlib.ksh b/spectro/instlib.ksh
index 88796f8..8b0303f 100644
--- a/spectro/instlib.ksh
+++ b/spectro/instlib.ksh
@@ -42,6 +42,7 @@ RSPL_FILES="
SPECTRO_FILES="
License2.txt
+ spotread.c
Makefile.OSX
Makefile.UNIX
Makefile.WNT
@@ -49,6 +50,8 @@ SPECTRO_FILES="
pollem.c
conv.h
conv.c
+ sa_conv.h
+ sa_conv.c
aglob.c
aglob.h
hidio.h
@@ -56,13 +59,13 @@ SPECTRO_FILES="
icoms.h
inst.h
inst.c
- disptechs.h
- disptechs.c
insttypes.c
insttypes.h
insttypeinst.h
instappsup.c
instappsup.h
+ disptechs.h
+ disptechs.c
dtp20.c
dtp20.h
dtp22.c
@@ -101,6 +104,11 @@ SPECTRO_FILES="
specbos.c
kleink10.h
kleink10.c
+ ex1.c
+ ex1.h
+ smcube.h
+ smcube.c
+ cubecal.h
oemarch.c
oemarch.h
oeminst.c
@@ -118,10 +126,14 @@ SPECTRO_FILES="
usbio_nt.c
usbio_ox.c
usbio_lx.c
- usbio_bsd.c
+ rspec.h
+ rspec.c
xdg_bds.c
xdg_bds.h
- spotread.c
+ base64.h
+ base64.c
+ xrga.h
+ xrga.c
"
FILES=" $H_FILES $CGATS_FILES $NUMLIB_FILES $RSPL_FILES $XICC_FILES $SPECTRO_FILES "
@@ -138,7 +150,7 @@ for j in $FILES
do
if [ ! -e ${j} ] ; then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${j} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
- NOTFOUND="$NOTFOUND ${tt}"
+ NOTFOUND="$NOTFOUND ${j}"
else
cp ${j} _zipdir/instlib/${j##*/}
echo instlib/${j##*/} >> _ziplist
diff --git a/spectro/insttypeinst.h b/spectro/insttypeinst.h
index ad8047d..081d130 100644
--- a/spectro/insttypeinst.h
+++ b/spectro/insttypeinst.h
@@ -9,6 +9,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#ifdef ENABLE_SERIAL
# include "dtp22.h"
diff --git a/spectro/insttypes.c b/spectro/insttypes.c
index 5a660a8..760d678 100644
--- a/spectro/insttypes.c
+++ b/spectro/insttypes.c
@@ -1,5 +1,5 @@
- /* Instrument supported types utilities */
+/* Instrument supported types utilities */
/*
* Argyll Color Correction System
@@ -37,6 +37,65 @@
/* Utility functions */
+/* Given a device type, return the corrsponding */
+/* category */
+extern icom_type inst_category(instType itype) {
+ switch (itype) {
+
+ /* Color measurement instruments */
+ case instDTP22:
+ case instDTP41:
+ case instDTP51:
+ case instSpectrolino:
+ case instSpectroScan:
+ case instSpectroScanT:
+ case instSpectrocam:
+ case instSpecbos1201:
+ case instSpecbos:
+ case instSpectraval:
+ case instKleinK10:
+ case instSMCube:
+ case instDTP20:
+ case instDTP92:
+ case instDTP94:
+ case instI1Disp1:
+ case instI1Disp2:
+ case instI1Disp3:
+ case instI1Monitor:
+ case instI1Pro:
+ case instI1Pro2:
+ case instColorMunki:
+ case instHCFR:
+ case instSpyder1:
+ case instSpyder2:
+ case instSpyder3:
+ case instSpyder4:
+ case instSpyder5:
+ case instHuey:
+ case instSmile:
+ case instEX1:
+ case instColorHug:
+ case instColorHug2:
+
+
+ return icomt_instrument;
+
+ /* 3D cLUT box */
+
+ /* Video test patern generator box */
+
+ /* Printers */
+ case devEpsonR1800:
+ return icomt_printer;
+
+ case instFakeDisp:
+ return icomt_unknown; // ???
+
+ }
+
+ return icomt_cat_any;
+}
+
/* Return the short instrument identification name (static string) */
char *inst_sname(instType itype) {
switch (itype) {
@@ -94,6 +153,8 @@ char *inst_sname(instType itype) {
return "specbos 1201";
case instSpecbos:
return "specbos";
+ case instSpectraval:
+ return "spectraval";
case instKleinK10:
return "K-10";
case instEX1:
@@ -104,6 +165,7 @@ char *inst_sname(instType itype) {
return "ColorHug";
case instColorHug2:
return "ColorHug2";
+
default:
break;
}
@@ -167,6 +229,8 @@ char *inst_name(instType itype) {
return "JETI specbos 1201";
case instSpecbos:
return "JETI specbos";
+ case instSpectraval:
+ return "JETI spectraval";
case instKleinK10:
return "Klein K-10";
case instEX1:
@@ -177,6 +241,7 @@ char *inst_name(instType itype) {
return "Hughski ColorHug";
case instColorHug2:
return "Hughski ColorHug2";
+
default:
break;
}
@@ -258,6 +323,8 @@ instType inst_enum(char *name) {
return instSpecbos1201;
else if (strcmp(name, "JETI specbos") == 0)
return instSpecbos;
+ else if (strcmp(name, "JETI spectraval") == 0)
+ return instSpectraval;
else if (strcmp(name, "Klein K-10") == 0)
return instKleinK10;
else if (strcmp(name, "Image Engineering EX1") == 0)
@@ -445,6 +512,7 @@ int inst_illuminant(xspect *sp, instType itype) {
case instSpecbos1201:
case instSpecbos:
+ case instSpectraval:
return 1; /* Not applicable */
case instKleinK10:
@@ -456,6 +524,7 @@ int inst_illuminant(xspect *sp, instType itype) {
case instSMCube:
return 1; /* Not applicable */
+
case instColorHug:
case instColorHug2:
return 1; /* Not applicable */
diff --git a/spectro/insttypes.h b/spectro/insttypes.h
index ab80cd2..8306bc8 100644
--- a/spectro/insttypes.h
+++ b/spectro/insttypes.h
@@ -1,7 +1,7 @@
#ifndef INSTTYPES_H
- /* Instrument suported types utilities. */
+/* Device and Instrument suported types definitions. */
/*
* Argyll Color Correction System
@@ -23,9 +23,11 @@
/* ----------------------------- */
-/* Possible types of instruments */
+/* Possible types of devices and instruments */
typedef enum {
- instUnknown = 0, /* Undefined Instrument */
+ devUnknown = 0, /* Undefined Device */
+
+ /* Color measurement instruments */
instDTP22, /* Xrite DTP22 (Digital Swatchbook) */
instDTP41, /* Xrite DTP41 */
instDTP51, /* Xrite DTP51 */
@@ -35,6 +37,7 @@ typedef enum {
instSpectrocam, /* Avantes Spectrocam */
instSpecbos1201, /* JETI specbos 1201 */
instSpecbos, /* JETI specbos XXXX */
+ instSpectraval, /* JETI spectraval 1501, 1511 */
instKleinK10, /* Klein K10-A */
instSMCube, /* SwatchMate Cube */
instDTP20, /* Xrite DTP20 (Pulse) */
@@ -62,12 +65,33 @@ typedef enum {
instFakeDisp = 9998, /* Fake display & instrument device id */
-} instType;
+ /* 3D cLUT box */
+ // 20000
+
+ /* Video test patern generator box */
+ // 30000
+
+ /* Printers */
+ devEpsonR1800 = 40000 /* Epson R1800 printer */
-struct _icoms; /* Forward declaration */
+} devType;
+
+/* Aliases for backwards compatibility */
+#define instUnknown devUnknown
+typedef devType instType;
+typedef devType cLUTType;
+typedef devType vtpgType;
+typedef devType printerType;
+
+struct _icoms; /* Forward declarations */
+enum _icom_type;
/* Utility functions in libinsttypes */
+/* Given a device type, return the corrsponding */
+/* category */
+//extern _icom_type inst_category(instType itype);
+
/* Given its instrument type, return the matching */
/* short instrument name (static string), */
extern char *inst_sname(instType itype);
diff --git a/spectro/iusb.h b/spectro/iusb.h
index a254ec0..94047cf 100644
--- a/spectro/iusb.h
+++ b/spectro/iusb.h
@@ -10,6 +10,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Device and/or Interface Class codes */
#define IUSB_CLASS_PER_INTERFACE 0x00 /* for DeviceClass */
#define IUSB_CLASS_AUDIO 0x01
@@ -127,5 +131,9 @@
#define IUSB_DEVICE_STATUS_REMOTE_WAKEUP 0x0002
#define IUSB_ENDPOINT_STATUS_HALT 0x0001
+#ifdef __cplusplus
+ }
+#endif
+
#define _IUSB_H_
#endif /* _IUSB_H_ */
diff --git a/spectro/kleink10.c b/spectro/kleink10.c
index 9599972..3d67b6c 100644
--- a/spectro/kleink10.c
+++ b/spectro/kleink10.c
@@ -369,8 +369,7 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
amutex_lock(p->lock);
- if (p->icom->port_type(p->icom) != icomt_serial
- && p->icom->port_type(p->icom) != icomt_usbserial) {
+ if (!(p->icom->port_type(p->icom) & icomt_serial)) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "k10_init_coms: wrong communications type for device!\n");
return inst_coms_fail;
@@ -386,7 +385,8 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
if (brt[i] == baud_nc) {
i = 0;
}
- a1logd(p->log, 5, "k10_init_coms: trying baud ix %d\n",brt[i]);
+ a1logd(p->log, 5, "k10_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(p->icom, fc_HardwareDTR, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
amutex_unlock(p->lock);
@@ -397,7 +397,7 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Check instrument is responding */
if (((ev = k10_command(p, "P0\r", buf, MAX_MES_SIZE, NULL, 21, ec_ec, 0.5)) & inst_mask)
!= inst_coms_fail) {
- break; /* We've got coms or user abort */
+ goto got_coms; /* We've got coms or user abort */
}
/* Check for user abort */
@@ -411,11 +411,12 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
}
- if (msec_time() >= etime) { /* We haven't established comms */
- amutex_unlock(p->lock);
- a1logd(p->log, 2, "k10_init_coms: failed to establish coms\n");
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "k10_init_coms: failed to establish coms\n");
+ return inst_coms_fail;
+
+ got_coms:;
/* Check the response */
if (ev != inst_ok) {
@@ -2255,6 +2256,7 @@ inst_code k10_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) */
) {
kleink10 *p = (kleink10 *)pp;
@@ -2267,6 +2269,7 @@ 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 = k10_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -2738,8 +2741,7 @@ double mtx[3][3]
* error if it hasn't been initialised.
*/
static inst_code
-k10_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+k10_get_set_opt(inst *pp, inst_opt_type m, ...) {
kleink10 *p = (kleink10 *)pp;
char buf[MAX_MES_SIZE];
int se;
@@ -2753,6 +2755,11 @@ k10_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
/* Get target light state */
if (m == inst_opt_get_target_state) {
va_list args;
@@ -2821,12 +2828,17 @@ k10_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
- return inst_unsupported;
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/kleink10.h b/spectro/kleink10.h
index 4dcc334..136476a 100644
--- a/spectro/kleink10.h
+++ b/spectro/kleink10.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define K10_INTERNAL_ERROR 0xff01 /* Internal software error */
#define K10_TIMEOUT 0xff02 /* Communication timeout */
@@ -116,6 +120,9 @@ struct _kleink10 {
/* Constructor */
extern kleink10 *new_kleink10(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define KLEINK10_H
#endif /* KLEINK10_H */
diff --git a/spectro/linear.cal b/spectro/linear.cal
new file mode 100644
index 0000000..b5e06c0
--- /dev/null
+++ b/spectro/linear.cal
@@ -0,0 +1,272 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Wed Sep 28 02:35:54 2016"
+DEVICE_CLASS "DISPLAY"
+COLOR_REP "RGB"
+
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.00000 0.00000 0.00000 0.00000
+0.00392157 0.00392157 0.00392157 0.00392157
+0.00784314 0.00784314 0.00784314 0.00784314
+0.0117647 0.0117647 0.0117647 0.0117647
+0.0156863 0.0156863 0.0156863 0.0156863
+0.0196078 0.0196078 0.0196078 0.0196078
+0.0235294 0.0235294 0.0235294 0.0235294
+0.0274510 0.0274510 0.0274510 0.0274510
+0.0313725 0.0313725 0.0313725 0.0313725
+0.0352941 0.0352941 0.0352941 0.0352941
+0.0392157 0.0392157 0.0392157 0.0392157
+0.0431373 0.0431373 0.0431373 0.0431373
+0.0470588 0.0470588 0.0470588 0.0470588
+0.0509804 0.0509804 0.0509804 0.0509804
+0.0549020 0.0549020 0.0549020 0.0549020
+0.0588235 0.0588235 0.0588235 0.0588235
+0.0627451 0.0627451 0.0627451 0.0627451
+0.0666667 0.0666667 0.0666667 0.0666667
+0.0705882 0.0705882 0.0705882 0.0705882
+0.0745098 0.0745098 0.0745098 0.0745098
+0.0784314 0.0784314 0.0784314 0.0784314
+0.0823529 0.0823529 0.0823529 0.0823529
+0.0862745 0.0862745 0.0862745 0.0862745
+0.0901961 0.0901961 0.0901961 0.0901961
+0.0941176 0.0941176 0.0941176 0.0941176
+0.0980392 0.0980392 0.0980392 0.0980392
+0.101961 0.101961 0.101961 0.101961
+0.105882 0.105882 0.105882 0.105882
+0.109804 0.109804 0.109804 0.109804
+0.113725 0.113725 0.113725 0.113725
+0.117647 0.117647 0.117647 0.117647
+0.121569 0.121569 0.121569 0.121569
+0.125490 0.125490 0.125490 0.125490
+0.129412 0.129412 0.129412 0.129412
+0.133333 0.133333 0.133333 0.133333
+0.137255 0.137255 0.137255 0.137255
+0.141176 0.141176 0.141176 0.141176
+0.145098 0.145098 0.145098 0.145098
+0.149020 0.149020 0.149020 0.149020
+0.152941 0.152941 0.152941 0.152941
+0.156863 0.156863 0.156863 0.156863
+0.160784 0.160784 0.160784 0.160784
+0.164706 0.164706 0.164706 0.164706
+0.168627 0.168627 0.168627 0.168627
+0.172549 0.172549 0.172549 0.172549
+0.176471 0.176471 0.176471 0.176471
+0.180392 0.180392 0.180392 0.180392
+0.184314 0.184314 0.184314 0.184314
+0.188235 0.188235 0.188235 0.188235
+0.192157 0.192157 0.192157 0.192157
+0.196078 0.196078 0.196078 0.196078
+0.200000 0.200000 0.200000 0.200000
+0.203922 0.203922 0.203922 0.203922
+0.207843 0.207843 0.207843 0.207843
+0.211765 0.211765 0.211765 0.211765
+0.215686 0.215686 0.215686 0.215686
+0.219608 0.219608 0.219608 0.219608
+0.223529 0.223529 0.223529 0.223529
+0.227451 0.227451 0.227451 0.227451
+0.231373 0.231373 0.231373 0.231373
+0.235294 0.235294 0.235294 0.235294
+0.239216 0.239216 0.239216 0.239216
+0.243137 0.243137 0.243137 0.243137
+0.247059 0.247059 0.247059 0.247059
+0.250980 0.250980 0.250980 0.250980
+0.254902 0.254902 0.254902 0.254902
+0.258824 0.258824 0.258824 0.258824
+0.262745 0.262745 0.262745 0.262745
+0.266667 0.266667 0.266667 0.266667
+0.270588 0.270588 0.270588 0.270588
+0.274510 0.274510 0.274510 0.274510
+0.278431 0.278431 0.278431 0.278431
+0.282353 0.282353 0.282353 0.282353
+0.286275 0.286275 0.286275 0.286275
+0.290196 0.290196 0.290196 0.290196
+0.294118 0.294118 0.294118 0.294118
+0.298039 0.298039 0.298039 0.298039
+0.301961 0.301961 0.301961 0.301961
+0.305882 0.305882 0.305882 0.305882
+0.309804 0.309804 0.309804 0.309804
+0.313725 0.313725 0.313725 0.313725
+0.317647 0.317647 0.317647 0.317647
+0.321569 0.321569 0.321569 0.321569
+0.325490 0.325490 0.325490 0.325490
+0.329412 0.329412 0.329412 0.329412
+0.333333 0.333333 0.333333 0.333333
+0.337255 0.337255 0.337255 0.337255
+0.341176 0.341176 0.341176 0.341176
+0.345098 0.345098 0.345098 0.345098
+0.349020 0.349020 0.349020 0.349020
+0.352941 0.352941 0.352941 0.352941
+0.356863 0.356863 0.356863 0.356863
+0.360784 0.360784 0.360784 0.360784
+0.364706 0.364706 0.364706 0.364706
+0.368627 0.368627 0.368627 0.368627
+0.372549 0.372549 0.372549 0.372549
+0.376471 0.376471 0.376471 0.376471
+0.380392 0.380392 0.380392 0.380392
+0.384314 0.384314 0.384314 0.384314
+0.388235 0.388235 0.388235 0.388235
+0.392157 0.392157 0.392157 0.392157
+0.396078 0.396078 0.396078 0.396078
+0.400000 0.400000 0.400000 0.400000
+0.403922 0.403922 0.403922 0.403922
+0.407843 0.407843 0.407843 0.407843
+0.411765 0.411765 0.411765 0.411765
+0.415686 0.415686 0.415686 0.415686
+0.419608 0.419608 0.419608 0.419608
+0.423529 0.423529 0.423529 0.423529
+0.427451 0.427451 0.427451 0.427451
+0.431373 0.431373 0.431373 0.431373
+0.435294 0.435294 0.435294 0.435294
+0.439216 0.439216 0.439216 0.439216
+0.443137 0.443137 0.443137 0.443137
+0.447059 0.447059 0.447059 0.447059
+0.450980 0.450980 0.450980 0.450980
+0.454902 0.454902 0.454902 0.454902
+0.458824 0.458824 0.458824 0.458824
+0.462745 0.462745 0.462745 0.462745
+0.466667 0.466667 0.466667 0.466667
+0.470588 0.470588 0.470588 0.470588
+0.474510 0.474510 0.474510 0.474510
+0.478431 0.478431 0.478431 0.478431
+0.482353 0.482353 0.482353 0.482353
+0.486275 0.486275 0.486275 0.486275
+0.490196 0.490196 0.490196 0.490196
+0.494118 0.494118 0.494118 0.494118
+0.498039 0.498039 0.498039 0.498039
+0.501961 0.501961 0.501961 0.501961
+0.505882 0.505882 0.505882 0.505882
+0.509804 0.509804 0.509804 0.509804
+0.513725 0.513725 0.513725 0.513725
+0.517647 0.517647 0.517647 0.517647
+0.521569 0.521569 0.521569 0.521569
+0.525490 0.525490 0.525490 0.525490
+0.529412 0.529412 0.529412 0.529412
+0.533333 0.533333 0.533333 0.533333
+0.537255 0.537255 0.537255 0.537255
+0.541176 0.541176 0.541176 0.541176
+0.545098 0.545098 0.545098 0.545098
+0.549020 0.549020 0.549020 0.549020
+0.552941 0.552941 0.552941 0.552941
+0.556863 0.556863 0.556863 0.556863
+0.560784 0.560784 0.560784 0.560784
+0.564706 0.564706 0.564706 0.564706
+0.568627 0.568627 0.568627 0.568627
+0.572549 0.572549 0.572549 0.572549
+0.576471 0.576471 0.576471 0.576471
+0.580392 0.580392 0.580392 0.580392
+0.584314 0.584314 0.584314 0.584314
+0.588235 0.588235 0.588235 0.588235
+0.592157 0.592157 0.592157 0.592157
+0.596078 0.596078 0.596078 0.596078
+0.600000 0.600000 0.600000 0.600000
+0.603922 0.603922 0.603922 0.603922
+0.607843 0.607843 0.607843 0.607843
+0.611765 0.611765 0.611765 0.611765
+0.615686 0.615686 0.615686 0.615686
+0.619608 0.619608 0.619608 0.619608
+0.623529 0.623529 0.623529 0.623529
+0.627451 0.627451 0.627451 0.627451
+0.631373 0.631373 0.631373 0.631373
+0.635294 0.635294 0.635294 0.635294
+0.639216 0.639216 0.639216 0.639216
+0.643137 0.643137 0.643137 0.643137
+0.647059 0.647059 0.647059 0.647059
+0.650980 0.650980 0.650980 0.650980
+0.654902 0.654902 0.654902 0.654902
+0.658824 0.658824 0.658824 0.658824
+0.662745 0.662745 0.662745 0.662745
+0.666667 0.666667 0.666667 0.666667
+0.670588 0.670588 0.670588 0.670588
+0.674510 0.674510 0.674510 0.674510
+0.678431 0.678431 0.678431 0.678431
+0.682353 0.682353 0.682353 0.682353
+0.686275 0.686275 0.686275 0.686275
+0.690196 0.690196 0.690196 0.690196
+0.694118 0.694118 0.694118 0.694118
+0.698039 0.698039 0.698039 0.698039
+0.701961 0.701961 0.701961 0.701961
+0.705882 0.705882 0.705882 0.705882
+0.709804 0.709804 0.709804 0.709804
+0.713725 0.713725 0.713725 0.713725
+0.717647 0.717647 0.717647 0.717647
+0.721569 0.721569 0.721569 0.721569
+0.725490 0.725490 0.725490 0.725490
+0.729412 0.729412 0.729412 0.729412
+0.733333 0.733333 0.733333 0.733333
+0.737255 0.737255 0.737255 0.737255
+0.741176 0.741176 0.741176 0.741176
+0.745098 0.745098 0.745098 0.745098
+0.749020 0.749020 0.749020 0.749020
+0.752941 0.752941 0.752941 0.752941
+0.756863 0.756863 0.756863 0.756863
+0.760784 0.760784 0.760784 0.760784
+0.764706 0.764706 0.764706 0.764706
+0.768627 0.768627 0.768627 0.768627
+0.772549 0.772549 0.772549 0.772549
+0.776471 0.776471 0.776471 0.776471
+0.780392 0.780392 0.780392 0.780392
+0.784314 0.784314 0.784314 0.784314
+0.788235 0.788235 0.788235 0.788235
+0.792157 0.792157 0.792157 0.792157
+0.796078 0.796078 0.796078 0.796078
+0.800000 0.800000 0.800000 0.800000
+0.803922 0.803922 0.803922 0.803922
+0.807843 0.807843 0.807843 0.807843
+0.811765 0.811765 0.811765 0.811765
+0.815686 0.815686 0.815686 0.815686
+0.819608 0.819608 0.819608 0.819608
+0.823529 0.823529 0.823529 0.823529
+0.827451 0.827451 0.827451 0.827451
+0.831373 0.831373 0.831373 0.831373
+0.835294 0.835294 0.835294 0.835294
+0.839216 0.839216 0.839216 0.839216
+0.843137 0.843137 0.843137 0.843137
+0.847059 0.847059 0.847059 0.847059
+0.850980 0.850980 0.850980 0.850980
+0.854902 0.854902 0.854902 0.854902
+0.858824 0.858824 0.858824 0.858824
+0.862745 0.862745 0.862745 0.862745
+0.866667 0.866667 0.866667 0.866667
+0.870588 0.870588 0.870588 0.870588
+0.874510 0.874510 0.874510 0.874510
+0.878431 0.878431 0.878431 0.878431
+0.882353 0.882353 0.882353 0.882353
+0.886275 0.886275 0.886275 0.886275
+0.890196 0.890196 0.890196 0.890196
+0.894118 0.894118 0.894118 0.894118
+0.898039 0.898039 0.898039 0.898039
+0.901961 0.901961 0.901961 0.901961
+0.905882 0.905882 0.905882 0.905882
+0.909804 0.909804 0.909804 0.909804
+0.913725 0.913725 0.913725 0.913725
+0.917647 0.917647 0.917647 0.917647
+0.921569 0.921569 0.921569 0.921569
+0.925490 0.925490 0.925490 0.925490
+0.929412 0.929412 0.929412 0.929412
+0.933333 0.933333 0.933333 0.933333
+0.937255 0.937255 0.937255 0.937255
+0.941176 0.941176 0.941176 0.941176
+0.945098 0.945098 0.945098 0.945098
+0.949020 0.949020 0.949020 0.949020
+0.952941 0.952941 0.952941 0.952941
+0.956863 0.956863 0.956863 0.956863
+0.960784 0.960784 0.960784 0.960784
+0.964706 0.964706 0.964706 0.964706
+0.968627 0.968627 0.968627 0.968627
+0.972549 0.972549 0.972549 0.972549
+0.976471 0.976471 0.976471 0.976471
+0.980392 0.980392 0.980392 0.980392
+0.984314 0.984314 0.984314 0.984314
+0.988235 0.988235 0.988235 0.988235
+0.992157 0.992157 0.992157 0.992157
+0.996078 0.996078 0.996078 0.996078
+1.000000 1.000000 1.000000 1.000000
+END_DATA
diff --git a/spectro/madvrwin.c b/spectro/madvrwin.c
index e131e5e..305a240 100644
--- a/spectro/madvrwin.c
+++ b/spectro/madvrwin.c
@@ -215,8 +215,11 @@ static ramdac *madvrwin_get_ramdac(dispwin *p) {
debugr("madvrwin_get_ramdac failed on malloc()\n");
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+
r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -506,8 +509,15 @@ int ddebug /* >0 to print debug statements to stderr */
dispwin_set_default_delays(p);
- p->pdepth = 8; /* Assume this */
- p->edepth = 16;
+ p->fdepth = 8; /* Assume this */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+#ifdef ENABLE_RAMDAC
+ p->nent = (1 << p->ndepth);
+#else
+ p->nent = 0; /* No ramdac */
+#endif
+ p->edepth = 16; /* Assumed */
if (initMadVR(p)) {
debugr2((errout,"Failed to locate MadVR .dll or functions\n"));
@@ -515,7 +525,7 @@ int ddebug /* >0 to print debug statements to stderr */
return NULL;
}
- if (!madVR_BlindConnect(0, 1000)) {
+ if (!madVR_BlindConnect(1, 1000)) {
debugr2((errout,"Failed to connect to MadVR\n"));
free(p);
return NULL;
diff --git a/spectro/munki.c b/spectro/munki.c
index df54cd9..16cd863 100644
--- a/spectro/munki.c
+++ b/spectro/munki.c
@@ -71,8 +71,15 @@ static inst_code
munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
munki *p = (munki *) pp;
int se;
+#if defined(UNIX_X11)
+ /* Some Linux drivers fail to start every second time the device is opened */
+ /* if no clear halt is done on open, and some do the opposite. So */
+ /* reset after close to avoid the problem in all cases. */
+ icomuflags usbflags = icomuf_no_open_clear | icomuf_reset_before_close;
+#else
icomuflags usbflags = icomuf_none;
-#ifdef __APPLE__
+#endif
+#ifdef UNIX_APPLE
/* If the ColorMunki software has been installed, then there will */
/* be a daemon process that has the device open. Kill that process off */
/* so that we can open it here, before it re-spawns. */
@@ -82,10 +89,10 @@ munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
NULL
};
int retries = 20;
-#else /* !__APPLE__ */
+#else /* !UNIX_APPLE */
char **pnames = NULL;
int retries = 0;
-#endif /* !__APPLE__ */
+#endif /* !UNIX_APPLE */
a1logd(p->log, 2, "munki_init_coms: called\n");
@@ -98,6 +105,8 @@ munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Set config, interface, write end point, read end point, read quanta */
/* ("serial" end points aren't used - the Munki uses USB control messages) */
+ /* (The ColorMunki on Linux only starts every second time if we use the */
+ /* icomuf_no_open_clear flag.) */
if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames))
!= ICOM_OK) {
a1logd(p->log, 1, "munki_init_coms: failed ICOM err 0x%x\n",se);
@@ -368,6 +377,7 @@ static inst_code munki_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) */
) {
munki *p = (munki *)pp;
@@ -378,7 +388,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- rv = munki_imp_calibrate(p, calt, calc, id);
+ rv = munki_imp_calibrate(p, calt, calc, idtype, id);
return munki_interp_code(p, rv);
}
@@ -455,7 +465,7 @@ munki_interp_error(inst *pp, munki_code ec) {
case MUNKI_RD_TOOMANYPATCHES:
return "Too many patches";
case MUNKI_RD_NOTENOUGHSAMPLES:
- return "Not enough samples per patch";
+ return "Not enough samples per patch - Slow Down!";
case MUNKI_RD_NOFLASHES:
return "No flashes recognized";
case MUNKI_RD_NOAMBB4FLASHES:
@@ -797,6 +807,39 @@ munki_get_set_opt(inst *pp, inst_opt_type m, ...) {
return munki_interp_code(p, munki_set_scan_toll(p, toll_ratio));
}
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ imp->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (imp->target_calstd == xcalstd_native)
+ *standard = imp->native_calstd; /* If not overridden */
+ else
+ *standard = imp->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
if (!p->gotcoms)
return inst_no_coms;
if (!p->inited)
@@ -915,6 +958,33 @@ munki_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
+ /* Return the white calibration tile spectrum */
+ /* (We always return the normal rez. reference values) */
+ if (m == inst_opt_get_cal_tile_sp) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xspect *sp;
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ if (imp->white_ref1 == NULL)
+ return inst_no_init;
+
+ sp->spec_n = imp->nwav1;
+ sp->spec_wl_short = imp->wl_short1;
+ sp->spec_wl_long = imp->wl_long1;
+ sp->norm = 100.0;
+
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] = imp->white_ref1[i] * 100.0;
+
+ return inst_ok;
+ }
+
/* Use default implementation of other inst_opt_type's */
{
inst_code rv;
diff --git a/spectro/munki_imp.c b/spectro/munki_imp.c
index 6f49d0d..eae2837 100644
--- a/spectro/munki_imp.c
+++ b/spectro/munki_imp.c
@@ -146,6 +146,7 @@
#include "munki.h"
#include "munki_imp.h"
+#include "xrga.h"
/* - - - - - - - - - - - - - - - - - - */
@@ -478,12 +479,27 @@ munki_code munki_imp_init(munki *p) {
unsigned char buf[4];
int calsize = 0, rucalsize;
unsigned char *calbuf; /* EEProm contents */
+ char *envv;
a1logd(p->log,2,"munki_init:\n");
if (p->itype != instColorMunki)
return MUNKI_UNKNOWN_MODEL;
+
+ m->native_calstd = xcalstd_xrga;
+ m->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ m->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ m->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ m->target_calstd = xcalstd_gmdi;
+ }
+
#ifdef ENABLE_SPOS_CHECK
m->nosposcheck = 0;
#else
@@ -523,7 +539,7 @@ munki_code munki_imp_init(munki *p) {
return ev;
/* Dump the eeprom contents as a block */
- if (p->log->debug >= 7) {
+ if (p->log->debug >= 9) {
int base, size;
a1logd(p->log,7, "EEPROM contents:\n");
@@ -960,6 +976,7 @@ munki_code munki_imp_calibrate(
munki *p,
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) */
) {
munki_code ev = MUNKI_OK;
@@ -1670,24 +1687,28 @@ if (ss->idark_int_time[j] != s->idark_int_time[j])
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_cal_smode) {
*calc = inst_calc_man_cal_smode;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_dark) { /* Transmissive dark */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_cal_smode) {
*calc = inst_calc_man_cal_smode;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_vwhite) { /* Transmissive white for emulated trans. */
+ *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;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_emis_int_time) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) {
*calc = inst_calc_emis_white;
@@ -1709,10 +1730,13 @@ if (ss->idark_int_time[j] != s->idark_int_time[j])
if (m->transwarn) {
*calc = inst_calc_message;
- if (m->transwarn & 2)
+ if (m->transwarn & 2) {
+ *idtype = inst_calc_id_trans_low;
strcpy(id, "Warning: Transmission light source is too low for accuracy!");
- else
+ } else {
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ }
m->transwarn = 0;
return MUNKI_OK;
}
@@ -2259,8 +2283,13 @@ munki_code munki_imp_measure(
/* Indicate to the user that they can now scan the instrument, */
/* after a little delay that allows for the instrument reaction time. */
if (s->scan) {
- /* 100msec delay, 1KHz for 200 msec */
- msec_beep(0 + (int)(invsampt * 1000.0 + 0.9), 1000, 200);
+ int delay = 100 + (int)(invsampt * 1000.0 + 0.9);
+ if (p->eventcallback != NULL) {
+ issue_scan_ready((inst *)p, delay);
+ } else {
+ /* delay then 1KHz for 200 msec */
+ msec_beep(delay, 1000, 200);
+ }
}
/* Retry loop in case a display read is saturated */
@@ -5716,9 +5745,10 @@ munki_code munki_extract_patches_multimeas(
if (pat[k].use == 0)
continue;
- nno = (pat[k].no * 3)/4;
-// nno = (pat[k].no * 2)/3; // experimental tighter trim
- trim = (pat[k].no - nno)/2;
+// nno = (pat[k].no * 3 + 0)/4; /* Trim to 75% & round down */
+ nno = (pat[k].no * 2 + 0)/3; /* Trim to 66% & round down [def] */
+// nno = (pat[k].no * 2 + 0)/4; /* Trim to 50% & round down */
+ trim = (pat[k].no - nno + 1)/2;
pat[k].ss += trim;
pat[k].no = nno;
@@ -6257,6 +6287,8 @@ void munki_scale_specrd(
#define DO_CCDNORM /* [def] Normalise CCD values to original */
#define DO_CCDNORMAVG /* [und???] Normalise averages rather than per CCD bin */
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
#ifdef NEVER
/* Plot the matrix coefficients */
@@ -6918,7 +6950,7 @@ munki_code munki_create_hr(munki *p, int ref) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
-#ifndef NEVER
+#ifdef BOX_INTEGRATE
/* Integrate in 0.05 nm increments from filter shape */
{
int nn;
@@ -7924,6 +7956,11 @@ munki_code munki_conv2XYZ(
}
conv->del(conv);
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, nvals, xcalstd_nonpol, m->target_calstd, m->native_calstd, clamp);
+
+
return MUNKI_OK;
}
diff --git a/spectro/munki_imp.h b/spectro/munki_imp.h
index ea9451f..f639395 100644
--- a/spectro/munki_imp.h
+++ b/spectro/munki_imp.h
@@ -177,6 +177,9 @@ struct _munkiimp {
double intclkp; /* Integration clock period (computed from tickdur) */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
/* Current state of hardware (~~99 are all these used ??) */
double c_inttime; /* Integration period (=inttime + deadtime) */
int c_measmodeflags; /* Measurement mode flags (set by trigger() */
@@ -418,6 +421,7 @@ munki_code munki_imp_calibrate(
munki *p,
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[100] /* Condition identifier (ie. white reference ID) */
);
diff --git a/spectro/oemarch.c b/spectro/oemarch.c
index a9bbda1..be9abf3 100644
--- a/spectro/oemarch.c
+++ b/spectro/oemarch.c
@@ -38,6 +38,8 @@
#include <sys/param.h>
#include <sys/mount.h>
#include <ctype.h>
+#include <sys/types.h>
+#include <pwd.h>
#endif /* UNIX */
#ifndef SALONEINSTLIB
#include "copyright.h"
@@ -96,7 +98,7 @@ oem_target oemtargs = {
{ NULL }
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
{ /* Installed files */
{ "/Applications/Spyder2express 2.2/Spyder2express.app/Contents/MacOSClassic/Spyder.lib", targ_spyd2_pld },
{ "/Applications/Spyder2pro 2.2/Spyder2pro.app/Contents/MacOSClassic/Spyder.lib", targ_spyd2_pld },
@@ -122,20 +124,29 @@ oem_target oemtargs = {
{ "/Installer/ColorMunkiDisplaySetup.exe", targ_i1d3_edr },
{ NULL }
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#ifdef UNIX_X11
{ /* Installed files */
{ NULL }
},
- { /* Volume names the CDROM may have */
+ { /* Volume names the CDROM may have. */
+ /* (It's a pity the linux developers have no idea what a stable API looks like...) */
+ { "/run/media/$USER/ColorVision", targ_spyd2_pld | targ_spyd_cal },
+ { "/run/media/$USER/Datacolor", targ_spyd2_pld | targ_spyd_cal },
+ { "/run/media/$USER/i1Profiler", targ_i1d3_edr },
+ { "/run/media/$USER/ColorMunki Displ", targ_i1d3_edr },
+
{ "/media/ColorVision", targ_spyd2_pld | targ_spyd_cal },
{ "/media/Datacolor", targ_spyd2_pld | targ_spyd_cal },
{ "/media/i1Profiler", targ_i1d3_edr },
{ "/media/ColorMunki Displ", targ_i1d3_edr },
+
{ "/mnt/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/mnt/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
+
{ "/media/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/media/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
+
{ "/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ NULL }
@@ -152,14 +163,14 @@ oem_target oemtargs = {
#endif /* UNIX_X11 */
};
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
/* Global: */
char *oemamount_path = NULL;
#endif
/* Cleanup function for transfer on Apple OS X */
void oem_umiso() {
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
if (oemamount_path != NULL) {
char sbuf[MAXNAMEL+1 + 100];
sprintf(sbuf, "umount \"%s\"",oemamount_path);
@@ -167,7 +178,7 @@ void oem_umiso() {
sprintf(sbuf, "rmdir \"%s\"",oemamount_path);
system(sbuf);
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
}
static xfile *locate_volume(int verb);
@@ -561,7 +572,7 @@ static xfile *locate_volume(int verb) {
}
#endif /* NT */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
{
int j;
char tname[MAXNAMEL+1] = { '\000' };
@@ -626,7 +637,7 @@ static xfile *locate_volume(int verb) {
}
}
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
{
@@ -635,15 +646,49 @@ static xfile *locate_volume(int verb) {
/* See if we can see what we're looking for on one of the volumes */
/* It would be nice to be able to read the volume name ! */
for (j = 0;;j++) {
- if (oemtargs.volnames[j].path == NULL)
+ char *vol, *cp;
+
+ vol = oemtargs.volnames[j].path;
+
+ if (vol == NULL)
break;
- if (access(oemtargs.volnames[j].path, 0) == 0) {
- if (verb) printf("found '%s'\n",oemtargs.volnames[j].path);
- new_add_xf(&xf, oemtargs.volnames[j].path, NULL, 0,
- file_vol, oemtargs.volnames[j].ttype);
- break;
+ /* Some linux paths include the real user name */
+ if ((cp = strstr(vol, "$USER")) != NULL) {
+ char *ivol = vol;
+ char *usr;
+ int len;
+
+ /* Media gets mounted as console user, */
+ /* so we need to know what that is. */
+ /* (Hmm. this solves access problem when
+ running as root, but not saving resulting
+ file to $HOME/.local/etc */
+ if ((usr = getenv("SUDO_USER")) == NULL) {
+ if ((usr = getenv("USER")) == NULL)
+ error("$USER is empty");
+ }
+
+ len = strlen(ivol) - 5 + strlen(usr) + 1;
+
+ if ((vol = malloc(len)) == NULL)
+ error("Malloc of volume path length %d failed",len);
+
+ strncpy(vol, ivol, cp-ivol);
+ vol[cp-ivol]= '\000';
+ strcat(vol, usr);
+ strcat(vol, cp + 5);
+ }
+
+ if (access(vol, 0) == 0) {
+ if (verb) printf("found '%s'\n",vol);
+ new_add_xf(&xf, vol, NULL, 0, file_vol, oemtargs.volnames[j].ttype);
+ if (vol != oemtargs.volnames[j].path)
+ free(vol);
+ break;
}
+ if (vol != oemtargs.volnames[j].path)
+ free(vol);
}
}
#endif /* UNIX */
@@ -1407,7 +1452,7 @@ static xfile *edr_convert(xfile **pxf, xfile *xi, int verb) {
char *ccssname;
char *edrname;
unsigned char *buf;
- int len;
+ size_t len;
if (c->buf_write_ccss(c, &buf, &len)) {
error("Failed to create ccss for '%s' error '%s'",xi->name,c->err);
}
@@ -2622,7 +2667,8 @@ static xfile *ai_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb) {
if (verb) printf("Extracted '%s' length %ld\n",xf->name,xf->len);
-save_xfile(xf, "temp.cab", NULL, verb);
+// /* Save diagnostic file */
+// save_xfile(xf, "temp.cab", NULL, verb);
return xf;
}
diff --git a/spectro/oeminst.c b/spectro/oeminst.c
index bce7a67..726a54c 100644
--- a/spectro/oeminst.c
+++ b/spectro/oeminst.c
@@ -20,6 +20,7 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
+#include "ui.h"
#else /* SALONEINSTLIB */
#include <fcntl.h>
#include "sa_config.h"
@@ -33,7 +34,6 @@
#include "disptechs.h"
#include "ccmx.h"
#include "ccss.h"
-#include "ui.h"
void usage(void) {
fprintf(stderr,"Install OEM data files, Version %s\n",ARGYLL_VERSION_STR);
@@ -43,7 +43,7 @@ void usage(void) {
fprintf(stderr," -n Don't install, show where files would be installed\n");
fprintf(stderr," -c Don't install, save files to current directory\n");
fprintf(stderr," -S d Specify the install scope u = user (def.), l = local system]\n");
- fprintf(stderr," infile setup.exe CD install file(s) or .dll(s) containing install files\n");
+ fprintf(stderr," infile Manufacturers setup.exe install file(s) or .dll(s) containing install files\n");
fprintf(stderr," infile.[edr|ccss|ccmx] EDR file(s) to translate and install or CCSS or CCMX files to install\n");
fprintf(stderr," If no file is provided, oeminst will look for the install CD.\n");
exit(1);
diff --git a/spectro/pollem.c b/spectro/pollem.c
index f7578c8..855702b 100644
--- a/spectro/pollem.c
+++ b/spectro/pollem.c
@@ -1,5 +1,5 @@
- /* Unix serial I/O class poll() emulation. */
+/* Unix serial I/O class poll() emulation. */
/*
* Argyll Color Correction System
diff --git a/spectro/pollem.h b/spectro/pollem.h
index f8a86ee..bd879e1 100644
--- a/spectro/pollem.h
+++ b/spectro/pollem.h
@@ -1,7 +1,7 @@
#ifndef POLLEN_H
- /* Unix serial I/O class poll() emulation. */
+/* Unix serial I/O class poll() emulation. */
/*
* Argyll Color Correction System
diff --git a/spectro/rspec.c b/spectro/rspec.c
index e0e0194..6a7f8c7 100644
--- a/spectro/rspec.c
+++ b/spectro/rspec.c
@@ -28,6 +28,7 @@
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include <fcntl.h>
#if defined(UNIX)
# include <utime.h>
#else
@@ -43,7 +44,9 @@
#include "sa_config.h"
#include "numsup.h"
#endif /* !SALONEINSTLIB */
-#include "plot.h"
+#ifndef SALONEINSTLIB
+# include "plot.h"
+#endif
#include "xspect.h"
#include "insttypes.h"
#include "conv.h"
@@ -51,6 +54,9 @@
#include "inst.h"
#include "rspec.h"
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
+
/* -------------------------------------------------- */
#if defined(__APPLE__) && defined(__POWERPC__)
@@ -250,6 +256,7 @@ void del_rspec(rspec *p) {
/* Plot the first rspec */
void plot_rspec1(rspec *p) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double yy[RSPEC_MAXSAMP];
@@ -264,10 +271,12 @@ void plot_rspec1(rspec *p) {
yy[i] = p->samp[0][i];
}
do_plot(xx, yy, NULL, NULL, no);
+#endif
}
/* Plot the first rspec of 2 */
void plot_rspec2(rspec *p1, rspec *p2) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double y1[RSPEC_MAXSAMP];
@@ -286,9 +295,11 @@ void plot_rspec2(rspec *p1, rspec *p2) {
y2[i] = p2->samp[0][i];
}
do_plot(xx, y1, y2, NULL, no);
+#endif
}
void plot_ecal(rspec_inf *inf) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double yy[RSPEC_MAXSAMP];
@@ -303,6 +314,7 @@ void plot_ecal(rspec_inf *inf) {
yy[i] = inf->ecal[i];
}
do_plot(xx, yy, NULL, NULL, no);
+#endif
}
@@ -710,7 +722,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
a1logd(inf->log, 4,"rspec_make_resample_filters: maxcoeffs = %d\n",maxcoeffs);
- /* Figure out integration step size */
+ /* Figure out box integration step size */
#ifdef FAST_HIGH_RES_SETUP
finc = twidth/50.0;
if (rawspace/finc < 10.0)
@@ -754,6 +766,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
+#ifdef BOX_INTEGRATE
/* Integrate in finc nm increments from filter shape */
/* using triangular integration. */
{
@@ -778,6 +791,9 @@ void rspec_make_resample_filters(rspec_inf *inf) {
lw = cw;
}
}
+#else
+ we = fabs(w2 - w1) * kernel(twidth, rwl);
+#endif
if (inf->fnocoef[j] >= maxcoeffs)
error("rspec_make_resample_filters: run out of high res filter space\n");
@@ -846,6 +862,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
/* Plot the wave resampling filters */
void plot_resample_filters(rspec_inf *inf) {
+#ifndef SALONEINSTLIB
double *xx, *ss;
double **yy;
int i, j, k, sx;
@@ -877,6 +894,7 @@ void plot_resample_filters(rspec_inf *inf) {
do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], inf->nraw);
free_dvector(xx, 0, inf->nraw-1);
free_dmatrix(yy, 0, 2, 0, inf->nraw-1);
+#endif
}
/* ================================================== */
diff --git a/spectro/sa_conv.c b/spectro/sa_conv.c
new file mode 100644
index 0000000..84286ba
--- /dev/null
+++ b/spectro/sa_conv.c
@@ -0,0 +1,865 @@
+
+#ifdef SALONEINSTLIB
+
+/*
+ * A very small subset of icclib, copied to here.
+ * This is just enough to support the standalone instruments
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/97
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include "sa_config.h"
+#include "numsup.h"
+#include "sa_conv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+sa_XYZNumber sa_D50 = {
+ 0.9642, 1.0000, 0.8249
+};
+
+sa_XYZNumber sa_D65 = {
+ 0.9505, 1.0000, 1.0890
+};
+
+sa_XYZNumber sa_D50_100 = {
+ 96.42, 100.00, 82.49
+};
+
+sa_XYZNumber sa_D65_100 = {
+ 95.05, 100.00, 108.90
+};
+
+unsigned int sa_CSSig2nchan(icColorSpaceSignature sig) {
+ switch(sig) {
+ case icSigXYZData:
+ return 3;
+ case icSigLabData:
+ return 3;
+ case icSigLuvData:
+ return 3;
+ case icSigYCbCrData:
+ return 3;
+ case icSigYxyData:
+ return 3;
+ case icSigRgbData:
+ return 3;
+ case icSigGrayData:
+ return 1;
+ case icSigHsvData:
+ return 3;
+ case icSigHlsData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ case icSigCmyData:
+ return 3;
+ case icSig2colorData:
+ return 2;
+ case icSig3colorData:
+ return 3;
+ case icSig4colorData:
+ return 4;
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 5;
+ case icSig6colorData:
+ case icSigMch6Data:
+ return 6;
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 7;
+ case icSig8colorData:
+ case icSigMch8Data:
+ return 8;
+ case icSig9colorData:
+ return 9;
+ case icSig10colorData:
+ return 10;
+ case icSig11colorData:
+ return 11;
+ case icSig12colorData:
+ return 12;
+ case icSig13colorData:
+ return 13;
+ case icSig14colorData:
+ return 14;
+ case icSig15colorData:
+ return 15;
+
+#ifdef NEVER
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return 1;
+ case icmSigLData:
+ return 1;
+ case icmSigL8Data:
+ return 1;
+ case icmSigLV2Data:
+ return 1;
+ case icmSigLV4Data:
+ return 1;
+ case icmSigPCSData:
+ return 3;
+ case icmSigLab8Data:
+ return 3;
+ case icmSigLabV2Data:
+ return 3;
+ case icmSigLabV4Data:
+ return 3;
+#endif /* NEVER */
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+void sa_SetUnity3x3(double mat[3][3]) {
+ int i, j;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ if (i == j)
+ mat[j][i] = 1.0;
+ else
+ mat[j][i] = 0.0;
+ }
+ }
+
+}
+
+void sa_Cpy3x3(double dst[3][3], double src[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src1[j][k] * src2[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+
+/* Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+static double sa_Det3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define SA__SMALL_NUMBER 1.e-8
+
+int sa_Inverse3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = sa_Det3x3(in);
+
+ if ( fabs(det) < SA__SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+#undef SA__SMALL_NUMBER
+#undef det2x2
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Transpose a 3x3 matrix */
+void sa_Transpose3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ if (out != in) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = in[j][i];
+ } else {
+ double tt[3][3];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ tt[i][j] = in[j][i];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = tt[i][j];
+ }
+}
+
+/* Scale a 3 vector by the given ratio */
+void sa_Scale3(double out[3], double in[3], double rat) {
+ out[0] = in[0] * rat;
+ out[1] = in[1] * rat;
+ out[2] = in[2] * rat;
+}
+
+/* Clamp a 3 vector to be +ve */
+void sa_Clamp3(double out[3], double in[3]) {
+ int i;
+ for (i = 0; i < 3; i++)
+ out[i] = in[i] < 0.0 ? 0.0 : in[i];
+}
+
+/* Return the normal Delta E given two Lab values */
+double sa_LabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* Return the CIE94 Delta E color difference measure, squared */
+double sa_CIE94sq(double Lab0[3], double Lab1[3]) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double c12;
+
+ {
+ double dl, da, db;
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ }
+
+ {
+ double c1, c2, dc;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ /* delta chromanance squared */
+ dc = c1 - c2;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+ {
+ double sc, sh;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.045 * c12;
+ sh = 1.0 + 0.015 * c12;
+ return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
+ }
+}
+
+/* Return the CIE94 Delta E color difference measure */
+double sa_CIE94(double Lab0[3], double Lab1[3]) {
+ return sqrt(sa_CIE94sq(Lab0, Lab1));
+}
+
+/* Return the CIE94 Delta E color difference measure for two XYZ values */
+double sa_XYZCIE94(sa_XYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ sa_XYZ2Lab(w, lab0, in0);
+ sa_XYZ2Lab(w, lab1, in1);
+ return sqrt(sa_CIE94sq(lab0, lab1));
+}
+
+/* CIE XYZ to perceptual CIE 1976 L*a*b* */
+void
+sa_XYZ2Lab(sa_XYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/w->X;
+ y = Y/w->Y;
+ z = Z/w->Z;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+void sa_Lab2XYZ(sa_XYZNumber *w, double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ fy = (L + 16.0)/116.0;
+ fx = a/500.0 + fy;
+ fz = fy - b/200.0;
+
+ if (fy > 24.0/116.0)
+ y = pow(fy,3.0);
+ else
+ y = (fy - 16.0/116.0)/7.787036979;
+
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * w->X;
+ out[1] = y * w->Y;
+ out[2] = z * w->Z;
+}
+
+
+void sa_Yxy2XYZ(double *out, double *in) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-9) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ sum = Y/y;
+ out[0] = x * sum;
+ out[1] = Y;
+ out[2] = z * sum;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Object for computing RFC 1321 MD5 checksums. */
+/* Derived from Colin Plumb's 1993 public domain code. */
+
+/* Reset the checksum */
+static void sa_MD5_reset(sa_MD5 *p) {
+ p->tlen = 0;
+
+ p->sum[0] = 0x67452301;
+ p->sum[1] = 0xefcdab89;
+ p->sum[2] = 0x98badcfe;
+ p->sum[3] = 0x10325476;
+
+ p->fin = 0;
+}
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, pp, xtra, s) \
+ data = (pp)[0] + ((pp)[3] << 24) + ((pp)[2] << 16) + ((pp)[1] << 8); \
+ w += f(x, y, z) + data + xtra; \
+ w = (w << s) | (w >> (32-s)); \
+ w += x;
+
+/* Add another 64 bytes to the checksum */
+static void sa_MD5_accume(sa_MD5 *p, ORD8 *in) {
+ ORD32 data, a, b, c, d;
+
+ a = p->sum[0];
+ b = p->sum[1];
+ c = p->sum[2];
+ d = p->sum[3];
+
+ MD5STEP(F1, a, b, c, d, in + (4 * 0), 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 1), 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 2), 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 3), 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 4), 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 5), 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 6), 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 7), 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 8), 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 9), 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 10), 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 11), 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 12), 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 13), 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 14), 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 15), 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in + (4 * 1), 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 6), 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 11), 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 0), 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 5), 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 10), 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 15), 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 4), 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 9), 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 14), 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 3), 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 8), 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 13), 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 2), 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 7), 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 12), 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in + (4 * 5), 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 8), 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 11), 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 14), 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 1), 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 4), 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 7), 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 10), 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 13), 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 0), 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 3), 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 6), 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 9), 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 12), 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 15), 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 2), 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in + (4 * 0), 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 7), 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 14), 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 5), 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 12), 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 3), 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 10), 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 1), 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 8), 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 15), 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 6), 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 13), 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 4), 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 11), 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 2), 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 9), 0xeb86d391, 21);
+
+ p->sum[0] += a;
+ p->sum[1] += b;
+ p->sum[2] += c;
+ p->sum[3] += d;
+}
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef MD5STEP
+
+/* Add some bytes */
+static void sa_MD5_add(sa_MD5 *p, ORD8 *ibuf, unsigned int len) {
+ unsigned int bs;
+
+ if (p->fin)
+ return; /* This is actually an error */
+
+ bs = p->tlen; /* Current bytes added */
+ p->tlen = bs + len; /* Update length after adding this buffer */
+ bs &= 0x3f; /* Bytes already in buffer */
+
+ /* Deal with any existing partial bytes in p->buf */
+ if (bs) {
+ ORD8 *np = (ORD8 *)p->buf + bs; /* Next free location in partial buffer */
+
+ bs = 64 - bs; /* Free space in partial buffer */
+
+ if (len < bs) { /* Not enought new to make a full buffer */
+ memmove(np, ibuf, len);
+ return;
+ }
+
+ memmove(np, ibuf, bs); /* Now got one full buffer */
+ sa_MD5_accume(p, np);
+ ibuf += bs;
+ len -= bs;
+ }
+
+ /* Deal with input data 64 bytes at a time */
+ while (len >= 64) {
+ sa_MD5_accume(p, ibuf);
+ ibuf += 64;
+ len -= 64;
+ }
+
+ /* Deal with any remaining bytes */
+ memmove(p->buf, ibuf, len);
+}
+
+/* Finalise the checksum and return the result. */
+static void sa_MD5_get(sa_MD5 *p, ORD8 chsum[16]) {
+ int i;
+ unsigned count;
+ ORD32 bits1, bits0;
+ ORD8 *pp;
+
+ if (p->fin == 0) {
+
+ /* Compute number of bytes processed mod 64 */
+ count = p->tlen & 0x3f;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ pp = p->buf + count;
+ *pp++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64, allowing 8 bytes for length in bits. */
+ if (count < 8) { /* Not enough space for padding and length */
+
+ memset(pp, 0, count);
+ sa_MD5_accume(p, p->buf);
+
+ /* Now fill the next block with 56 bytes */
+ memset(p->buf, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(pp, 0, count - 8);
+ }
+
+ /* Compute number of bits */
+ bits1 = 0x7 & (p->tlen >> (32 - 3));
+ bits0 = p->tlen << 3;
+
+ /* Append number of bits */
+ p->buf[64 - 8] = bits0 & 0xff;
+ p->buf[64 - 7] = (bits0 >> 8) & 0xff;
+ p->buf[64 - 6] = (bits0 >> 16) & 0xff;
+ p->buf[64 - 5] = (bits0 >> 24) & 0xff;
+ p->buf[64 - 4] = bits1 & 0xff;
+ p->buf[64 - 3] = (bits1 >> 8) & 0xff;
+ p->buf[64 - 2] = (bits1 >> 16) & 0xff;
+ p->buf[64 - 1] = (bits1 >> 24) & 0xff;
+
+ sa_MD5_accume(p, p->buf);
+
+ p->fin = 1;
+ }
+
+ /* Return the result, lsb to msb */
+ pp = chsum;
+ for (i = 0; i < 4; i++) {
+ *pp++ = p->sum[i] & 0xff;
+ *pp++ = (p->sum[i] >> 8) & 0xff;
+ *pp++ = (p->sum[i] >> 16) & 0xff;
+ *pp++ = (p->sum[i] >> 24) & 0xff;
+ }
+}
+
+
+/* Delete the instance */
+static void sa_MD5_del(sa_MD5 *p) {
+
+ /* This object */
+ if (p != NULL)
+ free(p);
+}
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error */
+sa_MD5 *new_sa_MD5() {
+ sa_MD5 *p;
+
+ if ((p = (sa_MD5 *)calloc(1,sizeof(sa_MD5))) == NULL)
+ return NULL;
+
+ p->reset = sa_MD5_reset;
+ p->add = sa_MD5_add;
+ p->get = sa_MD5_get;
+ p->del = sa_MD5_del;
+
+ p->reset(p);
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A sub-set of ludecomp code from numlib */
+
+int sa_lu_decomp(double **a, int n, int *pivx, double *rip) {
+ int i, j;
+ double *rscale, RSCALE[10];
+
+ if (n <= 10)
+ rscale = RSCALE;
+ else
+ rscale = dvector(0, n-1);
+
+ for (i = 0; i < n; i++) {
+ double big;
+ for (big = 0.0, j=0; j < n; j++) {
+ double temp;
+ temp = fabs(a[i][j]);
+ if (temp > big)
+ big = temp;
+ }
+ if (fabs(big) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+ rscale[i] = 1.0/big;
+ }
+
+ for (*rip = 1.0, j = 0; j < n; j++) {
+ double big;
+ int k, bigi = 0;
+
+ for (i = 0; i < j; i++) {
+ double sum;
+ sum = a[i][j];
+ for (k = 0; k < i; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ }
+
+ for (big = 0.0, i = j; i < n; i++) {
+ double sum, temp;
+ sum = a[i][j];
+ for (k = 0; k < j; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ temp = rscale[i] * fabs(sum);
+ if (temp >= big) {
+ big = temp;
+ bigi = i;
+ }
+ }
+
+ if (j != bigi) {
+ {
+ double *temp;
+ temp = a[bigi];
+ a[bigi] = a[j];
+ a[j] = temp;
+ }
+ *rip = -(*rip);
+ rscale[bigi] = rscale[j];
+ }
+
+ pivx[j] = bigi;
+ if (fabs(a[j][j]) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+
+ if (j != (n-1)) {
+ double temp;
+ temp = 1.0/a[j][j];
+ for (i = j+1; i < n; i++)
+ a[i][j] *= temp;
+ }
+ }
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 0;
+}
+
+void sa_lu_backsub(double **a, int n, int *pivx, double *b) {
+ int i, j;
+ int nvi;
+
+ for (nvi = -1, i = 0; i < n; i++) {
+ int px;
+ double sum;
+
+ px = pivx[i];
+ sum = b[px];
+ b[px] = b[i];
+ if (nvi >= 0) {
+ for (j = nvi; j < i; j++)
+ sum -= a[i][j] * b[j];
+ } else {
+ if (sum != 0.0)
+ nvi = i;
+ }
+ b[i] = sum;
+ }
+
+ for (i = (n-1); i >= 0; i--) {
+ double sum;
+ sum = b[i];
+ for (j = i+1; j < n; j++)
+ sum -= a[i][j] * b[j];
+ b[i] = sum/a[i][i];
+ }
+}
+
+int sa_lu_invert(double **a, int n) {
+ int i, j;
+ double rip;
+ int *pivx, PIVX[10];
+ double **y;
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+ if (sa_lu_decomp(a, n, pivx, &rip)) {
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ y = dmatrix(0, n-1, 0, n-1);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ y[i][j] = a[i][j];
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++)
+ a[i][j] = 0.0;
+ a[i][i] = 1.0;
+ sa_lu_backsub(y, n, pivx, a[i]);
+ }
+
+ free_dmatrix(y, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+
+ return 0;
+}
+
+int sa_lu_psinvert(double **out, double **in, int m, int n) {
+ int rv = 0;
+ double **tr;
+ double **sq;
+
+ tr = dmatrix(0, n-1, 0, m-1);
+ matrix_trans(tr, in, m, n);
+
+ if (m > n) {
+ sq = dmatrix(0, n-1, 0, n-1);
+ if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
+ if ((rv = sa_lu_invert(sq, n)) == 0) {
+ rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
+ }
+ }
+ free_dmatrix(sq, 0, n-1, 0, n-1);
+ } else {
+ sq = dmatrix(0, m-1, 0, m-1);
+ if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
+ if ((rv = sa_lu_invert(sq, m)) == 0) {
+ rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
+ }
+ }
+ free_dmatrix(sq, 0, m-1, 0, m-1);
+ }
+
+ free_dmatrix(tr, 0, n-1, 0, m-1);
+ return rv;
+}
+
+
+#endif /* SALONEINSTLIB */
+
+
diff --git a/spectro/sa_conv.h b/spectro/sa_conv.h
new file mode 100644
index 0000000..0f7e635
--- /dev/null
+++ b/spectro/sa_conv.h
@@ -0,0 +1,233 @@
+#ifndef SA_CONV_H
+
+#ifdef SALONEINSTLIB
+/*
+ * A very small subset of icclib and numlib for the standalone instrument lib.
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/2/9
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from icoms.h
+ */
+
+#if defined (NT)
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# if defined _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+#endif
+
+#if defined (UNIX)
+# include <unistd.h>
+# include <glob.h>
+# include <pthread.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A subset of icclib */
+
+#ifndef MAX_CHAN
+# define MAX_CHAN 15
+#endif
+
+typedef enum {
+ sa_SigXYZData = 0x58595A20L, /* 'XYZ ' */
+ sa_SigLabData = 0x4C616220L, /* 'Lab ' */
+ sa_SigLuvData = 0x4C757620L, /* 'Luv ' */
+ sa_SigYCbCrData = 0x59436272L, /* 'YCbr' */
+ sa_SigYxyData = 0x59787920L, /* 'Yxy ' */
+ sa_SigRgbData = 0x52474220L, /* 'RGB ' */
+ sa_SigGrayData = 0x47524159L, /* 'GRAY' */
+ sa_SigHsvData = 0x48535620L, /* 'HSV ' */
+ sa_SigHlsData = 0x484C5320L, /* 'HLS ' */
+ sa_SigCmykData = 0x434D594BL, /* 'CMYK' */
+ sa_SigCmyData = 0x434D5920L, /* 'CMY ' */
+
+ sa_Sig2colorData = 0x32434C52L, /* '2CLR' */
+ sa_Sig3colorData = 0x33434C52L, /* '3CLR' */
+ sa_Sig4colorData = 0x34434C52L, /* '4CLR' */
+ sa_Sig5colorData = 0x35434C52L, /* '5CLR' */
+ sa_Sig6colorData = 0x36434C52L, /* '6CLR' */
+ sa_Sig7colorData = 0x37434C52L, /* '7CLR' */
+ sa_Sig8colorData = 0x38434C52L, /* '8CLR' */
+ sa_Sig9colorData = 0x39434C52L, /* '9CLR' */
+ sa_Sig10colorData = 0x41434C52L, /* 'ACLR' */
+ sa_Sig11colorData = 0x42434C52L, /* 'BCLR' */
+ sa_Sig12colorData = 0x43434C52L, /* 'CCLR' */
+ sa_Sig13colorData = 0x44434C52L, /* 'DCLR' */
+ sa_Sig14colorData = 0x45434C52L, /* 'ECLR' */
+ sa_Sig15colorData = 0x46434C52L, /* 'FCLR' */
+
+ sa_SigMch5Data = 0x4D434835L, /* 'MCH5' Colorsync ? */
+ sa_SigMch6Data = 0x4D434836L, /* 'MCH6' Hexachrome: CMYKOG */
+ sa_SigMch7Data = 0x4D434837L, /* 'MCH7' Colorsync ? */
+ sa_SigMch8Data = 0x4D434838L, /* 'MCH8' Colorsync ? */
+ sa_SigNamedData = 0x6e6d636cL, /* 'nmcl' ??? */
+
+ sa_MaxEnumData = -1
+} sa_ColorSpaceSignature;
+
+typedef enum {
+ sa_SigInputClass = 0x73636E72L, /* 'scnr' */
+ sa_SigDisplayClass = 0x6D6E7472L, /* 'mntr' */
+ sa_SigOutputClass = 0x70727472L, /* 'prtr' */
+ sa_SigLinkClass = 0x6C696E6BL, /* 'link' */
+ sa_SigAbstractClass = 0x61627374L, /* 'abst' */
+ sa_SigColorSpaceClass = 0x73706163L, /* 'spac' */
+ sa_SigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */
+ sa_MaxEnumClass = -1
+} sa_ProfileClassSignature;
+
+typedef struct {
+ double X;
+ double Y;
+ double Z;
+} sa_XYZNumber;
+
+unsigned int sa_CSSig2nchan(sa_ColorSpaceSignature sig);
+extern sa_XYZNumber sa_D50;
+extern sa_XYZNumber sa_D65;
+extern sa_XYZNumber sa_D50_100;
+extern sa_XYZNumber sa_D65_100;
+void sa_SetUnity3x3(double mat[3][3]);
+void sa_Cpy3x3(double out[3][3], double mat[3][3]);
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]);
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
+int sa_Inverse3x3(double out[3][3], double in[3][3]);
+void sa_Transpose3x3(double out[3][3], double in[3][3]);
+void sa_Scale3(double out[3], double in[3], double rat);
+double sa_LabDE(double *in0, double *in1);
+double sa_CIE94sq(double *in0, double *in1);
+void sa_Lab2XYZ(sa_XYZNumber *w, double *out, double *in);
+void sa_XYZ2Lab(sa_XYZNumber *w, double *out, double *in);
+void sa_Yxy2XYZ(double *out, double *in);
+
+#define icColorSpaceSignature sa_ColorSpaceSignature
+#define icSigXYZData sa_SigXYZData
+#define icSigLabData sa_SigLabData
+#define icSigLuvData sa_SigLuvData
+#define icSigYCbCrData sa_SigYCbCrData
+#define icSigYxyData sa_SigYxyData
+#define icSigRgbData sa_SigRgbData
+#define icSigGrayData sa_SigGrayData
+#define icSigHsvData sa_SigHsvData
+#define icSigHlsData sa_SigHlsData
+#define icSigCmykData sa_SigCmykData
+#define icSigCmyData sa_SigCmyData
+#define icSig2colorData sa_Sig2colorData
+#define icSig3colorData sa_Sig3colorData
+#define icSig4colorData sa_Sig4colorData
+#define icSig5colorData sa_Sig5colorData
+#define icSig6colorData sa_Sig6colorData
+#define icSig7colorData sa_Sig7colorData
+#define icSig8colorData sa_Sig8colorData
+#define icSig9colorData sa_Sig9colorData
+#define icSig10colorData sa_Sig10colorData
+#define icSig11colorData sa_Sig11colorData
+#define icSig12colorData sa_Sig12colorData
+#define icSig13colorData sa_Sig13colorData
+#define icSig14colorData sa_Sig14colorData
+#define icSig15colorData sa_Sig15colorData
+#define icSigMch5Data sa_SigMch5Data
+#define icSigMch6Data sa_SigMch6Data
+#define icSigMch7Data sa_SigMch7Data
+#define icSigMch8Data sa_SigMch8Data
+#define icSigNamedData sa_SigNamedData
+#define icMaxEnumData sa_MaxEnumData
+
+#define icProfileClassSignature sa_ProfileClassSignature
+#define icSigInputClass sa_SigInputClass
+#define icSigDisplayClass sa_SigDisplayClass
+#define icSigOutputClass sa_SigOutputClass
+#define icSigLinkClass sa_SigLinkClass
+#define icSigAbstractClass sa_SigAbstractClass
+#define icSigColorSpaceClass sa_SigColorSpaceClass
+#define icSigNamedColorClass sa_SigNamedColorClass
+
+#define icmCSSig2nchan sa_CSSig2nchan
+
+#define icmXYZNumber sa_XYZNumber
+#define icmD50 sa_D50
+#define icmD65 sa_D65
+#define icmD50_100 sa_D50_100
+#define icmD65_100 sa_D65_100
+
+#define icmSetUnity3x3 sa_SetUnity3x3
+#define icmCpy3x3 sa_Cpy3x3
+#define icmMulBy3x3 sa_MulBy3x3
+#define icmMul3x3_2 sa_Mul3x3_2
+#define icmInverse3x3 sa_Inverse3x3
+#define icmTranspose3x3 sa_Transpose3x3
+
+#define icmCpy3(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
+ (d_ary)[2] = (s_ary)[2])
+#define icmScale3 sa_Scale3
+#define icmClamp3 sa_Clamp3
+
+#define icmAry2XYZ(xyz, ary) ((xyz).X = (ary)[0], (xyz).Y = (ary)[1], (xyz).Z = (ary)[2])
+
+#define icmLabDE sa_LabDE
+#define icmCIE94sq sa_CIE94sq
+#define icmXYZ2Lab sa_XYZ2Lab
+#define icmLab2XYZ sa_Lab2XYZ
+#define icmYxy2XYZ sa_Yxy2XYZ
+
+/* A helper object that computes MD5 checksums */
+struct _sa_MD5 {
+ /* Private: */
+ int fin; /* Flag, nz if final has been called */
+ ORD32 sum[4]; /* Current/final checksum */
+ unsigned int tlen; /* Total length added in bytes */
+ ORD8 buf[64]; /* Partial buffer */
+
+ /* Public: */
+ void (*reset)(struct _sa_MD5 *p); /* Reset the checksum */
+ void (*add)(struct _sa_MD5 *p, ORD8 *buf, unsigned int len); /* Add some bytes */
+ void (*get)(struct _sa_MD5 *p, ORD8 chsum[16]); /* Finalise and get the checksum */
+ void (*del)(struct _sa_MD5 *p); /* We're done with the object */
+
+}; typedef struct _sa_MD5 sa_MD5;
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error. */
+extern sa_MD5 *new_sa_MD5(void);
+
+#define icmMD5 sa_MD5
+#define new_icmMD5 new_sa_MD5
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A subset of numlib */
+
+int sa_lu_psinvert(double **out, double **in, int m, int n);
+
+#define lu_psinvert sa_lu_psinvert
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* SALONEINSTLIB */
+
+#define SA_CONV_H
+#endif /* SA_CONV_H */
diff --git a/spectro/smcube.c b/spectro/smcube.c
index 8a788ec..c450d48 100644
--- a/spectro/smcube.c
+++ b/spectro/smcube.c
@@ -68,9 +68,10 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
-#else /* !SALONEINSTLIB */
+#else /* SALONEINSTLIB */
#include "sa_config.h"
#include "numsup.h"
+#include "sa_conv.h"
#endif /* !SALONEINSTLIB */
#include "xspect.h"
#include "insttypes.h"
@@ -210,12 +211,13 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
a1logd(p->log, 2, "smcube_init_coms: About to init Serial I/O\n");
- if (p->icom->port_type(p->icom) != icomt_serial
- && p->icom->port_type(p->icom) != icomt_usbserial) {
- a1logd(p->log, 1, "smcube_init_coms: wrong communications type for device!\n");
+ if (!(p->icom->dctype & icomt_seriallike)
+ && !(p->icom->dctype & icomt_fastserial)) {
+ a1logd(p->log, 1, "smcube_init_coms: wrong communications type for device! (dctype 0x%x)\n",p->icom->dctype);
return inst_coms_fail;
}
+ /* Communications has already been established */
if (p->bt) {
amutex_lock(p->lock);
@@ -234,8 +236,8 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
amutex_unlock(p->lock);
+ /* We need to setup communications */
} else {
-
amutex_lock(p->lock);
/* The tick to give up on */
@@ -248,7 +250,8 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
if (brt[i] == baud_nc) {
i = 0;
}
- a1logd(p->log, 5, "smcube_init_coms: trying %s baud\n",baud_rate_to_str(brt[i]));
+ a1logd(p->log, 4, "smcube_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(p->icom, fc_Hardware, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
amutex_unlock(p->lock);
@@ -260,7 +263,7 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
buf[0] = 0x7e, buf[1] = 0x00, buf[2] = 0x02, buf[3] = 0x00; /* Ping command */
if (((ev = smcube_command(p, buf, 4, buf, 4, DEFTO)) & inst_mask)
!= inst_coms_fail) {
- break; /* We've got coms or user abort */
+ goto got_coms; /* We've got coms or user abort */
}
/* Check for user abort */
@@ -274,11 +277,12 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
}
- if (msec_time() >= etime) { /* We haven't established comms */
- amutex_unlock(p->lock);
- a1logd(p->log, 2, "smcube_init_coms: failed to establish coms\n");
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "smcube_init_coms: failed to establish coms\n");
+ return inst_coms_fail;
+
+ got_coms:;
/* Check the response */
if (buf[0] != 0x7e || buf[1] != 0x20 || buf[2] != 0x02 || buf[3] != 0x00) {
@@ -609,6 +613,7 @@ inst_code smcube_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) */
) {
smcube *p = (smcube *)pp;
@@ -621,6 +626,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *id = inst_calc_id_none;
id[0] = '\000';
if ((ev = smcube_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1056,8 +1062,7 @@ static void set_optcalibs_default(smcube *p) {
* error if it hasn't been initialised.
*/
static inst_code
-smcube_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+smcube_get_set_opt(inst *pp, inst_opt_type m, ...) {
smcube *p = (smcube *)pp;
inst_code ev = inst_ok;
@@ -1114,13 +1119,17 @@ smcube_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- /* Get/Sets that require instrument coms. */
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
- return inst_unsupported;
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/smcube.h b/spectro/smcube.h
index 7283635..06aee9d 100644
--- a/spectro/smcube.h
+++ b/spectro/smcube.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define SMCUBE_INTERNAL_ERROR 0xff01 /* Internal software error */
#define SMCUBE_TIMEOUT 0xff02 /* Communication timeout */
@@ -67,7 +71,7 @@
struct _smcube {
INST_OBJ_BASE
- int bt; /* Bluetooth coms rather than USB/serial */
+ int bt; /* Bluetooth coms rather than USB/serial flag */
amutex lock; /* Command lock */
@@ -114,6 +118,9 @@ struct _smcube {
/* Constructor */
extern smcube *new_smcube(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define SMCUBE_H
#endif /* SMCUBE_H */
diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c
index 322ab05..d77c334 100644
--- a/spectro/spec2cie.c
+++ b/spectro/spec2cie.c
@@ -1,7 +1,7 @@
/*
* Argyll Color Correction System
- * Spectral .ti3 file converter
+ * Spectral .ti3 or .sp file converter
*
* Copyright 2005 Gerhard Fuernkranz
* All rights reserved.
@@ -26,17 +26,17 @@
* under the GNU GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*
- * This program takes the spectral data in a .ti3 file, converts them
+ * This program takes the spectral data in a .ti3 or .sp file, converts them
* to XYZ and Lab and fills the XYZ_[XYZ] and LAB_[LAB] columns in the
- * output .ti3 file with the computed XYZ and Lab values. If the columns
+ * output .ti3 or .sp file with the computed XYZ and Lab values. If the columns
* XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
* added to the output file.
*
- * All other colums are copied from the input to the output .ti3 file.
+ * All other colums are copied from the input to the output .ti3 or .sp file.
*
* If the -f option is used, the FWA corrected spectral reflectances
- * are written to the output .ti3 file, instead of simply copying the
- * spectral reflectances from the input .ti3 file. In this case, the
+ * are written to the output .ti3 or .sp file, instead of simply copying the
+ * spectral reflectances from the input .ti3 or .sp file. In this case, the
* XYZ_[XYZ] and D50 LAB_[LAB] values are computed from the FWA corrected
* reflectances as well.
*/
@@ -50,10 +50,11 @@
Calibration tables aren't being passed through either ??
- L*a*b* is always D50.
-
This is intended for conversion of reflective measurements to XYZ -
there is no illuminant for emissive values.
+
+ L*a*b* is always D50.
+
*/
#define ALLOW_PLOT
@@ -74,33 +75,33 @@
#include "inst.h"
#ifdef ALLOW_PLOT
#include "plot.h"
-#endif
#include "ui.h"
+#endif
void
usage (void)
{
- fprintf (stderr, "Convert spectral .ti3 file, Version %s\n", ARGYLL_VERSION_STR);
+ fprintf (stderr, "Convert spectral .ti3 or .sp file, Version %s\n", ARGYLL_VERSION_STR);
fprintf (stderr, "Author: Gerhard Fuernkranz, licensed under the AGPL Version 3\n");
fprintf (stderr, "\n");
- fprintf (stderr, "Usage: spec2cie [options] input.ti3 output.ti3\n");
- fprintf (stderr, " -v Verbose mode\n");
- fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 file:\n");
- fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " (only used in conjunction with -f)\n");
- fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
- fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
- fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
- fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
- fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
- fprintf (stderr, " -n Don't output spectral values\n");
+ fprintf (stderr, "Usage: spec2cie [options] input.[ti3|sp] output.[ti3|sp]\n");
+ fprintf (stderr, " -v Verbose mode\n");
+ fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 or .sp file:\n");
+ fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " (only used in conjunction with -f)\n");
+ fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
+ fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
+ fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
+ fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
+ fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
+ fprintf (stderr, " -n Don't output spectral values\n");
#ifdef ALLOW_PLOT
- fprintf (stderr, " -p Plot each values spectrum\n");
+ fprintf (stderr, " -p Plot each values spectrum\n");
#endif
- fprintf (stderr, " input.ti3 Measurement file\n");
- fprintf (stderr, " output.ti3 Converted measurement file\n");
+ fprintf (stderr, " input.[ti3|sp] Measurement file\n");
+ fprintf (stderr, " output.[ti3|sp] Converted measurement file\n");
exit (1);
}
@@ -116,6 +117,7 @@ main(int argc, char *argv[])
cgats *ocg; /* output cgats structure */
cgats_set_elem *elems;
+ int isspect = 0; /* nz if SPECT file rathe than TI3 */
int isemis = 0; /* nz if this is an emissive reference */
int isdisp = 0; /* nz if this is a display device */
int isdnormed = 0; /* Has display data been normalised to 100 ? */
@@ -126,12 +128,18 @@ main(int argc, char *argv[])
int fwacomp = 0; /* FWA compensation */
int doplot = 0; /* Plot each patches spectrum */
char* illum_str = "D50";
- icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant, if set. */
xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
- icxIllumeType illum = icxIT_none; /* Spectral defaults */
- xspect cust_illum; /* Custom CIE illumination spectrum */
- icxIllumeType inst_illum = icxIT_none; /* Spectral defaults */
+ /* if tillum == icxIT_custom */
+ icxIllumeType illum = icxIT_none; /* CIE calc. illuminant spectrum, and FWA inst. */
+ /* illuminant if tillum not set. */
+ xspect cust_illum; /* Custom CIE illumination spectrum if illum == icxIT_custom */
+ double *ill_wp = NULL; /* If illum is not D50, illum white point XYZ */
+ double _ill_wp[3]; /* (What ill_wp points at if it is not NULL) */
+ icxIllumeType inst_illum = icxIT_none; /* Actual instrument illumination */
xspect inst_cust_illum; /* Custom actual instrument illumination spectrum */
+ /* if inst_illum == icxIT_custom */
+
icxObserverType observ = icxOT_none;
xspect cust_observ[3]; /* Custom observer CMF's */
@@ -211,9 +219,18 @@ main(int argc, char *argv[])
inst_illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
inst_illum = icxIT_custom;
- if (read_xspect (&inst_cust_illum, na) != 0)
+ if (read_xspect (&inst_cust_illum, &mt,na) != 0)
usage ();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Instrument illuminant '%s' is wrong measurement type",na);
}
}
@@ -243,14 +260,24 @@ main(int argc, char *argv[])
} else if (strcmp(na, "F10") == 0) {
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Target illuminant '%s' is wrong measurement type",na);
}
}
}
/* CIE tristimulous spectral Illuminant type */
+ /* (and FWA simulated instrument illuminant if tillum == icxIT_none) */
else if (argv[fa][1] == 'i') {
fa = nfa;
if (na == NULL)
@@ -281,9 +308,18 @@ main(int argc, char *argv[])
illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
illum = icxIT_custom;
- if (read_xspect (&cust_illum, na) != 0)
+ if (read_xspect (&cust_illum, &mt, na) != 0)
usage ();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("CIE illuminant '%s' is wrong measurement type",na);
}
}
@@ -334,23 +370,32 @@ main(int argc, char *argv[])
/* Open and look at the .ti3 profile patches file */
- icg = new_cgats (); /* Create a CGATS structure */
+ icg = new_cgats (); /* Create a CGATS structure */
icg->add_other (icg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (icg, "SPECT"); /* Spectral file */
- ocg = new_cgats (); /* Create a CGATS structure */
+ ocg = new_cgats (); /* Create a CGATS structure */
ocg->add_other (ocg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (ocg, "SPECT"); /* Spectral file */
if (icg->read_name (icg, in_ti3_name))
error ("CGATS file read error: %s", icg->err);
- if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
- error ("Input file isn't a CTI3 format file");
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other
+ || (icg->t[0].oi != 0 && icg->t[0].oi != 1))
+ error ("Input file isn't a CTI3 or SPECT format file");
+
+ if (icg->t[0].oi == 1)
+ isspect = 1;
+
if (icg->ntables < 1)
error ("Input file doesn't contain at least one table");
/* add table to output file */
-
- ocg->add_table(ocg, tt_other, 0);
+ if (isspect)
+ ocg->add_table(ocg, tt_other, 1);
+ else
+ ocg->add_table(ocg, tt_other, 0);
/* copy keywords */
@@ -370,19 +415,39 @@ main(int argc, char *argv[])
}
}
- if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
- error ("Input file doesn't contain keyword DEVICE_CLASS");
-
- /* Reflective options when not a reflective profile type */
- if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
- || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
- isemis = 1;
- if (illum != icxIT_none)
- error("-i illuminant can't be used for emissive reference type");
- if (fwacomp)
- error("-f FWA compensation can't be used for emissive reference type");
- fwacomp = 0;
- tillum = icxIT_none;
+ if (isspect) {
+ if ((dti = icg->find_kword (icg, 0, "MEAS_TYPE")) < 0)
+ error ("Input file doesn't contain keyword MEAS_TYPE");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"EMISSION") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISSION_FLASH") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT_FLASH") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
+
+ } else {
+ if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
}
/* Set defaults */
@@ -392,26 +457,30 @@ main(int argc, char *argv[])
if (observ == icxOT_none)
observ = icxOT_CIE_1931_2;
- /* Figure out what sort of device it is */
+ /* See if the display CIE data has been normalised to Y = 100 */
{
int ti;
- char *tos;
-
- if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
- isdisp = 1;
- }
- /* See if the display CIE data has been normalised to Y = 100 */
if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
|| strcmp(icg->t[0].kdata[ti],"NO") == 0) {
isdnormed = 0;
} else {
isdnormed = 1;
}
+ }
+
+ /* Figure out what sort of device it is */
+ if (icg->find_kword(icg, 0, "COLOR_REP") >= 0) {
+ int ti;
+ char *tos;
if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
error("Input file doesn't contain keyword COLOR_REP");
+ if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
+ isdisp = 1;
+ }
+
if ((tos = strchr(icg->t[0].kdata[ti], '_')) == NULL)
tos = icg->t[0].kdata[ti];
@@ -513,7 +582,7 @@ main(int argc, char *argv[])
/* Read in the CGATs fields */
{
- int sidx; /* Sample ID index */
+// int sidx; /* Sample ID index */
int ti, ii;
int Xi, Yi, Zi, Li, ai, bi; /* CGATS indexes for each field */
int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
@@ -528,10 +597,12 @@ main(int argc, char *argv[])
xspect mwsp; /* FWA compensated medium white spectrum */
double mwXYZ[3]; /* Media white XYZ */
+#ifdef NEVER
if ((sidx = icg->find_field (icg, 0, "SAMPLE_ID")) < 0)
error ("Input file doesn't contain field SAMPLE_ID");
if (icg->t[0].ftype[sidx] != nqcs_t)
error ("Field SAMPLE_ID is wrong type");
+#endif
/* Using spectral data */
@@ -628,14 +699,28 @@ main(int argc, char *argv[])
error("Out of memory");
}
+ /* If CIE calculation illuminant is not standard, compute it's white point */
+ if (illum != icxIT_D50) {
+ ill_wp = _ill_wp;
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(ill_wp, observ, cust_observ, illum, 0.0, &cust_illum) != 0)
+ error("icx_ill_sp2XYZ returned error");
+ }
+
/* Create a spectral conversion object */
- if ((sp2cie = new_xsp2cie (illum,
- illum == icxIT_none ? NULL : &cust_illum,
- observ, cust_observ, icSigXYZData, icxClamp)) == NULL)
+ if ((sp2cie = new_xsp2cie(illum, &cust_illum, observ, cust_observ,
+ icSigXYZData, icxClamp)) == NULL)
{
error ("Creation of spectral conversion object failed");
}
+ if (fwacomp && devspace == icmSigDefaultData) {
+ // In theory could fake white spectra by accumulating max of
+ // all values as an alternative.
+ error ("No device values, so can't locate white patch for FWA compensation");
+ }
+
if (fwacomp) {
double nw = 0.0; /* Number of media white patches */
@@ -741,6 +826,8 @@ main(int argc, char *argv[])
}
}
+ /* Enable FWA, and use tillump as instrument illuminant if */
+ /* it is set, else use observer illuminant set by new_xsp2cie(). */
/* (Note that sp and mwsp.norm is set to 100.0) */
if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
error ("Set FWA on sp2cie failed");
@@ -755,6 +842,15 @@ main(int argc, char *argv[])
sp2cie->sconvert (sp2cie, &rmwsp, mwXYZ, &mwsp);
}
+ /* If CIE conversion illuminant is non-standard, add it to the output */
+ if (ill_wp != NULL) {
+ char buf[100];
+
+ sprintf(buf,"%f %f %f", ill_wp[0], ill_wp[1], ill_wp[2]);
+ ocg->add_kword(ocg, 0, "ILLUMINANT_WHITE_POINT_XYZ",buf, NULL);
+ }
+
+ /* Transform patches from spectral to CIE */
for (i = 0; i < npat; i++) {
xspect corr_sp;
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 <stdio.h>
@@ -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 */
diff --git a/spectro/specbos.h b/spectro/specbos.h
index e926c42..5c89fd5 100644
--- a/spectro/specbos.h
+++ b/spectro/specbos.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define SPECBOS_INTERNAL_ERROR 0xff01 /* Internal software error */
#define SPECBOS_TIMEOUT 0xff02 /* Communication timeout */
@@ -122,11 +126,15 @@
struct _specbos {
INST_OBJ_BASE
+ int bt; /* Bluetooth coms rather than USB/serial flag */
+
amutex lock; /* Command lock */
- int model; /* JETI specbos model number */
+ int model; /* JETI specbos/spectraval model number */
/* 1201 */
/* 1211 */
+ /* 1501 */
+ /* 1511 - has display */
int noXYZ; /* nz if firmware doesn't support fetch*XYZ */
int badCal; /* nz if its been calibrated with a reduced WL range by 3rd party */
@@ -147,6 +155,10 @@ struct _specbos {
double wl_short;
double wl_long;
+ xspect trans_white; /* Synthetic transmission mode white reference */
+ xsp2cie *conv; /* transmission spectral to XYZ conversion */
+ int doing_cal; /* Flag - doing internal calibration measure */
+
/* Other state */
athread *th; /* Diffuser position monitoring thread */
volatile int th_term; /* nz to terminate thread */
@@ -159,6 +171,9 @@ struct _specbos {
/* Constructor */
extern specbos *new_specbos(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define SPECBOS_H
#endif /* SPECBOS_H */
diff --git a/spectro/spotread.c b/spectro/spotread.c
index baf1c76..c5ac955 100644
--- a/spectro/spotread.c
+++ b/spectro/spotread.c
@@ -64,7 +64,7 @@
#include "ccss.h"
#include "ccmx.h"
#include "instappsup.h"
-#ifdef ENABLE_USB
+#if !defined(NOT_ALLINSTS) || defined(EN_SPYD2)
# include "spyd2.h"
#endif
@@ -285,10 +285,12 @@ usage(char *diag, ...) {
for (i = 0; ; i++) {
if (paths[i] == NULL)
break;
+#if !defined(NOT_ALLINSTS) || defined(EN_SPYD2)
if ((paths[i]->itype == instSpyder1 && setup_spyd2(0) == 0)
|| (paths[i]->itype == instSpyder2 && setup_spyd2(1) == 0))
fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
else
+#endif
fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
}
} else
@@ -329,6 +331,7 @@ usage(char *diag, ...) {
fprintf(stderr," 6 D65\n");
fprintf(stderr," u U.V. Cut\n");
fprintf(stderr," -E extrafilterfile Apply extra filter compensation file\n");
+ fprintf(stderr," -A N|A|X|G XRGA conversion (default N)\n");
fprintf(stderr," -x Display Yxy instead of Lab\n");
fprintf(stderr," -h Display LCh instead of Lab\n");
fprintf(stderr," -V Show running average and std. devation from ref.\n");
@@ -344,10 +347,17 @@ usage(char *diag, ...) {
if (cap2 & inst2_ccss) {
fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
}
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -R fname.sp Preset reference to spectrum\n");
+#endif
fprintf(stderr," -Y r|n Override refresh, non-refresh display mode\n");
fprintf(stderr," -Y R:rate Override measured refresh rate with rate Hz\n");
fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+ fprintf(stderr," -Y l|L Test for i1Pro Lamp Drift (l), and remediate it (L)\n");
// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -Y W:fname.sp Save white tile ref. spectrum to file\n");
+#endif /* !SALONEINSTLIB */
fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
fprintf(stderr," logfile Optional file to save reading results as text\n");
@@ -373,7 +383,9 @@ int main(int argc, char *argv[]) {
int tele = 0; /* 1 = Use telephoto emissive sub-mode. */
int ambient = 0; /* 1 = Use ambient emissive mode, 2 = ambient flash mode */
int highres = 0; /* Use high res mode if available */
+ int lampdrift = 0; /* i1Pro Lamp Drift test (1) & fix (2) */
int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ xcalstd calstd = xcalstd_none; /* X-Rite calibration standard */
int refrmode = -1; /* -1 = default, 0 = non-refresh mode, 1 = refresh mode */
double refrate = 0.0; /* 0.0 = default, > 0.0 = override refresh rate */
int nadaptive = 0; /* Use non-apative mode if available */
@@ -387,6 +399,8 @@ int main(int argc, char *argv[]) {
char outname[MAXNAMEL+1] = "\000"; /* Output logfile name */
char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
char filtername[MAXNAMEL+1] = "\000"; /* Filter compensation */
+ char wtilename[MAXNAMEL+1] = "\000"; /* White file spectrum */
+ char psetrefname[MAXNAMEL+1] = "\000"; /* Preset reference spectrum */
FILE *fp = NULL; /* Logfile */
icompaths *icmps = NULL;
int comport = COMPORT; /* COM port used */
@@ -529,12 +543,21 @@ int main(int argc, char *argv[]) {
tillum_set = spec = 1;
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
tillum_set = spec = 1;
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage("Failed to read custom target illuminant spectrum in file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Target illuminant '%s' is wrong measurement type",na);
}
-#endif /* SALONEINSTLIB */
+#endif /* !SALONEINSTLIB */
/* Spectral Illuminant type for XYZ computation */
} else if (argv[fa][1] == 'i') {
@@ -566,10 +589,19 @@ int main(int argc, char *argv[]) {
illum_set = spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
illum_set = spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage("Unable to read custom illuminant file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Custom illuminant '%s' is wrong measurement type",na);
}
#else /* SALONEINSTLIB */
} else
@@ -600,7 +632,7 @@ int main(int argc, char *argv[]) {
emiss = 0;
trans = 1;
tele = 0;
- ambient = 0;
+ ambient = 0; /* Default normal diffuse/90 geometry trans. */
/* Request emissive measurement */
} else if (argv[fa][1] == 'e' || argv[fa][1] == 'd') {
@@ -642,10 +674,14 @@ int main(int argc, char *argv[]) {
/* Request ambient measurement */
} else if (argv[fa][1] == 'a') {
- emiss = 1;
- trans = 0;
- tele = 0;
- ambient = 1;
+ if (trans) {
+ ambient = 1; /* Alternate 90/diffuse geometry */
+ } else {
+ emiss = 1;
+ trans = 0;
+ tele = 0;
+ ambient = 1;
+ }
/* Request ambient flash measurement */
} else if (argv[fa][1] == 'f') {
@@ -675,6 +711,21 @@ int main(int argc, char *argv[]) {
if (na == NULL) usage("Paramater expected following -E");
strncpy(filtername,na,MAXNAMEL-1); filtername[MAXNAMEL-1] = '\000';
+ /* XRGA conversion */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -A");
+ if (na[0] == 'N')
+ calstd = xcalstd_none;
+ else if (na[0] == 'A')
+ calstd = xcalstd_xrga;
+ else if (na[0] == 'X')
+ calstd = xcalstd_xrdi;
+ else if (na[0] == 'G')
+ calstd = xcalstd_gmdi;
+ else
+ usage("Paramater after -A '%c' not recognized",na[0]);
+
/* Show Yxy */
} else if (argv[fa][1] == 'x') {
doYxy = 1;
@@ -725,6 +776,15 @@ int main(int argc, char *argv[]) {
if (na == NULL) usage("Parameter expected after -K");
strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+#ifndef SALONEINSTLIB
+ /* Preset reference spectrum */
+ } else if (argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL)
+ usage("-R fname.sp syntax incorrect");
+ strncpy(psetrefname,na,MAXNAMEL-1); psetrefname[MAXNAMEL-1] = '\000';
+#endif
+
/* Extra flags */
} else if (argv[fa][1] == 'Y') {
if (na == NULL)
@@ -742,9 +802,25 @@ int main(int argc, char *argv[]) {
refrate = atof(na+2);
if (refrate < 5.0 || refrate > 150.0)
usage("-Y R:rate %f Hz not in valid range",refrate);
+
+#ifndef SALONEINSTLIB
+ /* Save white tile reference spectrum to a file */
+ } else if (na[0] == 'W') {
+ if (na[1] != ':')
+ usage("-Y W:fname.sp syntax incorrect");
+ strncpy(wtilename,&na[2],MAXNAMEL-1); wtilename[MAXNAMEL-1] = '\000';
+#endif /* !SALONEINSTLIB */
+
+ /* i1Pro lamp drift test & fix */
+ } else if (na[0] == 'l') {
+ lampdrift = 1;
+ } else if (na[0] == 'L') {
+ lampdrift = 2;
+
/* ~~~ i1pro2 test code ~~~ */
} else if (na[0] == 'U') {
uvmode = 1;
+
} else {
usage("-Y parameter '%c' not recognised",na[0]);
}
@@ -755,7 +831,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage("Parameter expected after -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -850,6 +926,135 @@ int main(int argc, char *argv[]) {
return -1;
}
+ /* Check i1Pro lamp drift, and remediate if it is too large */
+ /* (Hmm. If cooltime is too long, drift appears to be worse
+ after remediation. It's not clear why, but it returns
+ to expected values once instrument has truly cooled down (i.e. 2+min ?)
+ */
+ if (lampdrift) {
+ int pass = 0;
+ double remtime = 0.0;
+ int cooltime = 30;
+
+ if (it->itype != instI1Pro
+ && it->itype != instI1Pro2) {
+ printf("LampDrift is only applicable to i1Pro instrument");
+ }
+
+ /* Disable initial calibration of machine if selected */
+ if (nocal != 0) {
+ if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ printf("Setting no-initial calibrate failed with '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+
+ if ((rv = it->get_set_opt(it, inst_opt_trig_prog)) != inst_ok)
+ error("Setting trigger mode failed with error :'%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+
+ for (pass = 0; pass < 2; pass++) {
+ ipatch val;
+ double dl, maxdl = -100.0, de, maxde = -100.0;
+ int ii;
+
+ printf("\nDoing Lamp Drift check - place instrument on calibration tile\n");
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
+ inst_code ev;
+
+ printf("\nNeed a calibration before continuing\n");
+
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, doone);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ error("Got abort or error from calibration");
+ }
+ }
+
+#ifndef NEVER
+ /* Ensure lamp has cooled down */
+ printf("\nAllowing lamp to cool\n");
+ for (i = cooltime; i > 0; i--) {
+ msec_sleep(1000);
+ printf("\r%d ",i); fflush(stdout);
+ }
+ printf("\r0 \n");
+#endif
+
+ printf("\nChecking Lamp Drift\n");
+ /* Measure 1 spot and save as ref */
+ if ((rv = it->read_sample(it, "SPOT", &val, instNoClamp)) != inst_ok) {
+ error("Read sample failed with '%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ if (val.XYZ_v == 0) error("Instrument didn't return XYZ value");
+ icmXYZ2Lab(&icmD50_100, rLab, val.XYZ);
+
+ // Until measurement is stable, or 30 measurements
+ // Read and save max DE
+
+ /* 30 trials, or no new biggest in 4 measurements */
+ for (ii = 100, i = 0; i < 40 && (i < 10 || (i - ii) < 6) ; i++) {
+ if ((rv = it->read_sample(it, "SPOT", &val, instNoClamp)) != inst_ok) {
+ error("Read sample failed with '%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ if (val.XYZ_v == 0) error("Instrument didn't return XYZ value");
+ icmXYZ2Lab(&icmD50_100, Lab, val.XYZ);
+
+ dl = Lab[0] - rLab[0];
+ de = icmLabDE(Lab, rLab);
+
+ /* Keep going while dl is rising */
+ if (dl > maxdl) {
+ maxdl = dl;
+ ii = i;
+ }
+ if (de > maxde) {
+ maxde = de;
+ printf("\r%1.3f DE",de); fflush(stdout);
+ }
+ }
+
+ // Print DE
+// printf("\nLamp Drift Delta E = %f\n",maxde);
+
+ if (lampdrift == 1) {
+ printf("\nDrift test complete - %s\n", maxde >= 0.09 ? "Needs Fixing!" : "OK");
+ break;
+ }
+
+ if (pass > 0) {
+ printf("\nDrift test & fix complete\n");
+ break;
+ }
+
+ if (maxde >= 0.09)
+ remtime = 60.0;
+ else if (maxde >= 0.12)
+ remtime = 90.0;
+ else if (maxde > 0.20)
+ remtime = 120.0;
+
+ if (remtime > 0.0) {
+ printf("\nDoing %.0f seconds of remediation\n",remtime);
+ // Do remediation */
+ if ((rv = it->get_set_opt(it, inst_opt_lamp_remediate, remtime)) != inst_ok) {
+ error("Remediating Lamp Drift failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ cooltime = 45;
+ } else {
+ printf("\nDrift is OK\n");
+ break;
+ }
+ }
+
+ goto done;
+ }
+
/* Configure the instrument mode */
{
int ccssset = 0;
@@ -873,17 +1078,26 @@ int main(int argc, char *argv[]) {
}
if (trans) {
- if (!IMODETST(cap, inst_mode_trans_spot)
- || it->check_mode(it, inst_mode_trans_spot) != inst_ok) {
- printf("Need transmission spot capability,\n");
- printf("and instrument doesn't support it\n");
- it->del(it);
- return -1;
+ /* Alternate geometry - 90/diffuse */
+ if (ambient) {
+ if (it->check_mode(it, inst_mode_trans_spot_a) != inst_ok) {
+ printf("Need transmission spot (alt) capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ /* Normal geometry - diffuce/90 */
+ } else {
+ if (it->check_mode(it, inst_mode_trans_spot) != inst_ok) {
+ printf("Need transmission spot capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
}
} else if (ambient == 1) {
- if (!IMODETST(cap, inst_mode_emis_ambient)
- || it->check_mode(it, inst_mode_emis_ambient) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_ambient) != inst_ok) {
printf("Requested ambient light capability,\n");
printf("and instrument doesn't support it.\n");
return -1;
@@ -895,8 +1109,7 @@ int main(int argc, char *argv[]) {
}
} else if (ambient == 2) {
- if (!IMODETST(cap, inst_mode_emis_ambient_flash)
- || it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) {
printf("Requested ambient flash capability,\n");
printf("and instrument doesn't support it.\n");
it->del(it);
@@ -912,22 +1125,20 @@ int main(int argc, char *argv[]) {
} else if (emiss || tele) {
/* If there is a tele mode but no emission, use tele */
- if (!IMODETST(cap, inst_mode_emis_spot)
- && IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok
+ && it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
tele = 1;
}
if (tele) {
- if (!IMODETST(cap, inst_mode_emis_tele)
- || it->check_mode(it, inst_mode_emis_tele) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_tele) != inst_ok) {
printf("Need telephoto spot capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
return -1;
}
} else {
- if (!IMODETST(cap, inst_mode_emis_spot)
- || it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
printf("Need emissive spot capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -941,16 +1152,15 @@ int main(int argc, char *argv[]) {
nadaptive = 0;
}
}
- if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd)
- && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) {
+ if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
+ && it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
if (verb) {
printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
refrmode = -1;
}
}
} else {
- if (!IMODETST(cap, inst_mode_ref_spot)
- || it->check_mode(it, inst_mode_ref_spot) != inst_ok) {
+ if (it->check_mode(it, inst_mode_ref_spot) != inst_ok) {
printf("Need reflection spot reading capability,\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -1007,12 +1217,15 @@ int main(int argc, char *argv[]) {
/* Set it to the appropriate mode */
/* Should look at instrument type & user spec ??? */
- if (trans)
- smode = mode = inst_mode_trans_spot;
- else if (ambient == 1 && IMODETST(cap, inst_mode_emis_ambient)
+ if (trans) {
+ if (ambient)
+ smode = mode = inst_mode_trans_spot_a;
+ else
+ smode = mode = inst_mode_trans_spot;
+ } else if (ambient == 1
&& it->check_mode(it, inst_mode_emis_ambient) == inst_ok)
smode = mode = inst_mode_emis_ambient;
- else if (ambient == 2 && IMODETST(cap, inst_mode_emis_ambient_flash)
+ else if (ambient == 2
&& it->check_mode(it, inst_mode_emis_ambient_flash) == inst_ok)
smode = mode = inst_mode_emis_ambient_flash;
else if (tele) // Hmm. What about tele flash ?
@@ -1021,8 +1234,7 @@ int main(int argc, char *argv[]) {
smode = mode = inst_mode_emis_spot;
else {
smode = mode = inst_mode_ref_spot;
- if (IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok)
+ if (it->check_mode(it, inst_mode_s_ref_spot) == inst_ok)
smode = inst_mode_s_ref_spot;
}
@@ -1087,6 +1299,15 @@ int main(int argc, char *argv[]) {
}
}
+ /* set XRGA conversion */
+ if (calstd != xcalstd_none) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_xcalstd, calstd)) != inst_ok) {
+ printf("Setting calibration standard not supported by instrument\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
/* Colorimeter Correction Matrix */
if (ccxxname[0] != '\000') {
ccss *cs = NULL;
@@ -1242,6 +1463,26 @@ int main(int argc, char *argv[]) {
inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
}
+#ifndef SALONEINSTLIB
+ /* Save reference white tile reflectance spectrum */
+ if (wtilename[0] != '\000') {
+ xspect sp;
+
+ if ((rv = it->get_set_opt(it, inst_opt_get_cal_tile_sp, &sp)) != inst_ok) {
+ printf("\nGetting reference white tile spectrum failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (write_xspect(wtilename, inst_mrt_reflective, &sp) != 0)
+ error("Failed to save spectrum to file '%s'",wtilename);
+
+ if (verb)
+ printf("Saved reference white tile spectrum to '%s'\n",wtilename);
+ }
+#endif /* !SALONEINSTLIB */
+
#ifdef DEBUG
printf("About to enter read loop\n");
#endif
@@ -1253,9 +1494,9 @@ int main(int argc, char *argv[]) {
it->set_uicallback(it, uicallback, NULL);
}
- if (spec) {
+ if (spec || psetrefname[0] != '\000') {
/* Any non-illuminated mode has no illuminant */
- if (emiss || tele || ambient)
+ if (emiss || ambient)
illum = icxIT_none;
/* Create a spectral conversion object */
@@ -1274,6 +1515,43 @@ int main(int argc, char *argv[]) {
}
}
+#ifndef SALONEINSTLIB
+ /* Load preset reference spectrum */
+ if (psetrefname[0] != '\000') {
+ inst_meas_type mt;
+
+ if (read_xspect(&rsp, &mt, psetrefname) != 0)
+ error("Failed to read spectrum from file '%s'",psetrefname);
+
+ if (!emiss && !ambient) {
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_transmissive
+ && mt != inst_mrt_reflective)
+ error("Reference reflectance spectrum '%s' is wrong measurement type",psetrefname);
+ } else {
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Reference reflectance spectrum '%s' is wrong measurement type",psetrefname);
+ }
+
+ if (verb)
+ printf("Loaded reference spectrum from '%s'\n",psetrefname);
+
+ sp2cie->convert(sp2cie, rXYZ, &rsp);
+
+ if (!(emiss || tele || ambient)) {
+ for (j = 0; j < 3; j++)
+ rXYZ[j] *= 100.0; /* 0..100 scale */
+ }
+ icmXYZ2Lab(&icmD50_100, rLab, rXYZ);
+ if (verb)
+ printf("Preset ref. XYZ %f %f %f, Lab %f %f %f\n", rXYZ[0], rXYZ[1], rXYZ[2], rLab[0], rLab[1], rLab[2]);
+ }
+#endif
+
/* Hold table */
if (cap2 & inst2_xy_holdrel) {
for (;;) { /* retry loop */
@@ -1338,8 +1616,7 @@ int main(int argc, char *argv[]) {
#endif // NEVER
- if (savdrd != -1 && IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) {
+ if (savdrd != -1 && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) {
inst_stat_savdrd sv;
savdrd = 0;
@@ -1670,7 +1947,8 @@ int main(int argc, char *argv[]) {
break;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1792,7 +2070,7 @@ int main(int argc, char *argv[]) {
printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout);
if (getns(buf, 500) != NULL && strlen(buf) > 0) {
- if(write_xspect(buf, &tsp))
+ if(write_xspect(buf, val.mtype, &tsp))
printf("\nWriting file '%s' failed\n",buf);
else
printf("\nWriting file '%s' succeeded\n",buf);
@@ -2079,7 +2357,7 @@ int main(int argc, char *argv[]) {
ymin = 0.0;
ymax = 120.0;
}
- do_plot_x(xx, yy, rLab[0] >= -1.0 ? yr : NULL, NULL, nn, 1,
+ do_plot_x(xx, yy, NULL, rLab[0] >= -1.0 ? yr : NULL, nn, 1,
xmin, xmax, ymin, ymax, 2.0);
}
#endif /* !SALONEINSTLIB */
@@ -2333,12 +2611,18 @@ int main(int argc, char *argv[]) {
}
#ifndef SALONEINSTLIB
if (val.sp.spec_n > 0 && (ambient || doCCT)) {
- int invalid = 0;
+ int i, invalid = 0;
double RR[14];
double cri;
cri = icx_CIE1995_CRI(&invalid, RR, &sp);
printf(" Color Rendering Index (Ra) = %.1f [ R9 = %.1f ]%s\n",
cri, RR[9-1], invalid ? " (Invalid)" : "");
+ for (i = 0; i < 14; i++) {
+ printf(" R%d%s = %.1f", i+1, i < 9 ? " " : "", RR[i]);
+ if (i == 6)
+ printf("\n");
+ }
+ printf("\n");
}
if (val.sp.spec_n > 0 && (ambient || doCCT)) {
int invalid = 0;
@@ -2380,6 +2664,8 @@ int main(int argc, char *argv[]) {
} /* Next reading */
+done:;
+
/* Release paper */
if (cap2 & inst2_xy_holdrel) {
it->xy_clear(it);
diff --git a/spectro/spyd2.c b/spectro/spyd2.c
index 6833e89..85a2d7f 100644
--- a/spectro/spyd2.c
+++ b/spectro/spyd2.c
@@ -819,10 +819,12 @@ spyd2_GetReading_ll(
msec_sleep(500);
a1logd(p->log, 1, "spyd2_GetReading_ll: reading retry with ICOM err 0x%x\n",se);
-#ifdef DO_RESETEP /* Do the miscelanous resetep()'s */
- a1logd(p->log, 1, "spyd2_GetReading_ll: resetting end point\n");
- p->icom->usb_resetep(p->icom, 0x81);
- msec_sleep(1); /* Let device recover ? */
+#ifdef DO_RESETEP /* Do the miscelanous resetep()'s every second time */
+ if ((retr & 1) == 0) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: resetting end point\n");
+ p->icom->usb_resetep(p->icom, 0x81);
+ msec_sleep(1); /* Let device recover ? */
+ }
#endif /* DO_RESETEP */
} /* End of whole command retries */
@@ -2888,7 +2890,7 @@ spyd2_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
#endif
/* On OS X the Spyder 2 can't close properly */
-#if defined(__APPLE__) /* OS X*/
+#if defined(UNIX_APPLE) /* OS X*/
if (p->itype == instSpyder1
|| p->itype == instSpyder2) {
usbflags |= icomuf_reset_before_close; /* The spyder 2 USB is buggy ? */
@@ -3255,6 +3257,7 @@ static inst_code spyd2_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) */
) {
spyd2 *p = (spyd2 *)pp;
@@ -3266,6 +3269,7 @@ 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 = spyd2_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -4060,7 +4064,18 @@ spyd2_get_set_opt(inst *pp, inst_opt_type m, ...) {
if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
return inst_ok;
}
- 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 */
diff --git a/spectro/spyd2.h b/spectro/spyd2.h
index 0588b9b..318ed7c 100644
--- a/spectro/spyd2.h
+++ b/spectro/spyd2.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update spyd2_interp_error() and spyd2_interp_code() in spyd2.c */
/* if anything of these #defines are added or subtracted */
@@ -178,5 +182,9 @@ extern spyd2 *new_spyd2(icoms *icom, instType itype);
/* Return 1 if Spyder firmware is available */
extern int setup_spyd2(int id);
+#ifdef __cplusplus
+ }
+#endif
+
#define SPYD2_H
#endif /* SPYD2_H */
diff --git a/spectro/ss.c b/spectro/ss.c
index 837e264..260df4a 100644
--- a/spectro/ss.c
+++ b/spectro/ss.c
@@ -43,17 +43,20 @@
There is a bug or limitation with using -N to skip the calibration
when using any of the emissive modes - the readings end up being nearly zero.
+ When -N is used, doing a manual calibration (i.e. spotread 'k') doesn't
+ work.
+
We aren't saving the spectrolino fake tranmission white reference in
a calibration file, so -N doesn't work with it.
You can't trigger a calibration reading using the instrument switch.
- You should be able to do use the table enter key anywhere the user
+ You should be able to use the table enter key anywhere the user
is asked to hit a key.
The corner positioning could be smarter.
- The SpectroscanT transmission cal. merely reminds the user (vie verbose)
+ The SpectroscanT transmission cal. merely reminds the user (via verbose)
that it is assuming the correct apatture, rather than given them
a chance to change it.
@@ -78,6 +81,7 @@
#include "conv.h"
#include "icoms.h"
#include "ss.h"
+#include "xrga.h"
/* Default flow control */
#define DEFFC fc_Hardware
@@ -97,6 +101,17 @@ char* filter_desc[] = {
"Custon Filter"
};
+/* Filter id */
+inst_calc_id_type filter_id[] = {
+ inst_calc_id_filt_unkn,
+ inst_calc_id_filt_none,
+ inst_calc_id_filt_pol,
+ inst_calc_id_filt_D65,
+ inst_calc_id_filt_unkn,
+ inst_calc_id_filt_UV,
+ inst_calc_id_filt_cust
+};
+
#define SS_REF_CAL_COUNT 50
#define SS_TRANS_CAL_COUNT 10
@@ -165,7 +180,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
fcc1 = ss_ctt_ProtokolWithHardwareHS;
fcc2 = ss_hst_Hardware;
} else {
- fc = fc_none;
+ fc = fc_None;
fcc1 = ss_ctt_ProtokolWithoutXonXoff;
fcc2 = ss_hst_None;
}
@@ -195,7 +210,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Until we time out, find the correct baud rate */
for (i = ci; clock() < etime;) {
a1logd(p->log, 4, "ss_init_coms: trying baud rate %d\n",i);
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
a1logd(p->log, 1, "ss_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
p->snerr = icoms2ss_err(se);
@@ -258,8 +273,24 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
return ss_inst_err(p);
}
+ /* Make sure the Spectrolino is still talking to us. */
+ ss_init_send(p);
+ ss_add_soreq(p, ss_ParameterRequest);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) != ss_ParameterAnswer) { /* Comms failed */
+ a1logd(p->log, 1, "ss_init_coms: spectrolino, instrument isn't communicating after final coms setup");
+ return inst_coms_fail;
+ }
+
} else { /* Spectroscan */
+ /* Reset the Spectroscan, in case Spectrolino got messed up. */
+ if ((ev = ss_do_ScanInitializeDevice(p)) != inst_ok) {
+ a1logd(p->log, 1, "ss_init_coms: Spectroscan reset failed ICOM err 0x%x\n",ev);
+ return ev;
+ }
+
ss_do_SetDeviceOnline(p); /* Put the device online */
/* Make sure other communication parameters are right */
@@ -275,9 +306,19 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
return ss_inst_err(p);
}
- /* Make sure the Spectrolino is talking to us. */
+ /* Make sure the Spectroscan is still talking to us. */
+ ss_init_send(p);
+ ss_add_ssreq(p, ss_OutputStatus);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) != ss_AnsPFX) { /* Comms failed */
+ a1logd(p->log, 1, "ss_init_coms: spectroscan, instrument isn't communicating after final coms setup");
+ return inst_coms_fail;
+ }
+
+ /* Make sure the Spectrolino is talking to Spectroscan. */
if ((ev = ss_do_ScanSpectrolino(p)) != inst_ok) {
- a1logd(p->log, 1, "ss_init_coms: spectroscan, instrument isn't communicating ICOM err 0x%x\n",se);
+ a1logd(p->log, 1, "ss_init_coms: Spectrolino isn't communicating with Spectroscan ICOM err 0x%x\n",ev);
return ev;
}
}
@@ -322,7 +363,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
|| strncmp(devn, "Spectrolino",11) != 0)
return inst_unknown_model;
- if (p->itype == instUnknown) /* No SpectrScan */
+ if (p->itype == instUnknown) /* No SpectroScan */
p->itype = instSpectrolino;
}
}
@@ -387,6 +428,7 @@ static void ss_determine_capabilities(ss *p) {
/* return non-zero on an error, with dtp error code */
static inst_code
ss_init_inst(inst *pp) {
+ char *envv;
ss *p = (ss *)pp;
inst_code rv = inst_ok;
@@ -395,6 +437,19 @@ ss_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_gmdi; /* Native is GMDI */
+ p->target_calstd = xcalstd_native; /* Default to native calibration */
+
+ /* Honor Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Reset the instrument to a known state */
if (p->itype != instSpectrolino) {
@@ -409,8 +464,9 @@ ss_init_inst(inst *pp) {
return rv;
if ((rv = ss_do_ReleasePaper(p)) != inst_ok)
return rv;
- if ((rv = ss_do_InitMotorPosition(p)) != inst_ok)
- return rv;
+ /* Skip this since we did a ss_do_ScanInitializeDevice() */
+// if ((rv = ss_do_InitMotorPosition(p)) != inst_ok)
+// return rv;
if (p->log->verb) {
char dn[19]; /* Device name */
@@ -642,7 +698,7 @@ struct _inst *pp) {
return rv;
}
-static inst_code ss_calibrate_imp(ss *p, inst_cal_type *calt, inst_cal_cond *calc, char id[CALIDLEN]);
+static inst_code ss_calibrate_imp(ss *p, inst_cal_type *calt, inst_cal_cond *calc, inst_calc_id_type *idtype, char id[CALIDLEN]);
/* Read a sheet full of patches using xy mode */
/* Return the inst error code */
@@ -725,10 +781,11 @@ ipatch *vals) { /* Pointer to array of values */
if ( (p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
inst_cal_type calt = inst_calt_needed;
inst_cal_cond calc = inst_calc_none;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
/* We expect this to be automatic, but handle as if it mightn't be */
- if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, &idtype, id)) != inst_ok) {
if (rv == inst_cal_setup)
return inst_needs_cal; /* Not automatic, needs a manual setup */
if (try < notries) {
@@ -819,6 +876,11 @@ ipatch *vals) { /* Pointer to array of values */
}
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch,
+ p->filt == ss_aft_PolFilter ? xcalstd_pol : xcalstd_nonpol,
+ p->target_calstd, p->native_calstd, instClamp);
+
return rv;
}
@@ -945,10 +1007,11 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if ((p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
inst_cal_type calt = inst_calt_needed;
inst_cal_cond calc = inst_calc_none;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
/* This could be automatic or need manual intervention */
- if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, &idtype, id)) != inst_ok) {
if (rv == inst_cal_setup) {
return inst_needs_cal; /* Not automatic, needs a manual setup */
}
@@ -1269,7 +1332,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
/* spectrum data is returned only if requested */
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
ss_rvt rvf; /* Return Reference Valid Flag */
ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
@@ -1294,6 +1358,12 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
}
+
+ /* Apply any XRGA conversion to the measurement */
+ ipatch_convert_xrga(val, 1,
+ p->filt == ss_aft_PolFilter ? xcalstd_pol : xcalstd_nonpol,
+ p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return rv;
@@ -1342,6 +1412,7 @@ static inst_code ss_calibrate_imp(
ss *p,
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) */
) {
inst_code rv = inst_ok;
@@ -1350,6 +1421,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
ss_owrt owr; /* Original white reference */
inst_cal_type needed, available;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
a1logd(p->log, 3, "ss calibrate called with calt = 0x%x, condition 0x%x, need w %d, t %d\n", *calt, *calc, p->need_wd_cal, p->need_t_cal);
@@ -1407,6 +1479,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
/* Get the name of the expected white reference */
if ((rv = so_do_WhiteReferenceRequest(p, p->filt, &afilt, sp, &owr, id)) != inst_ok)
return rv;
+ *idtype = inst_calc_id_ref_sn;
if (p->noinitcalib == 0) {
@@ -1457,6 +1530,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
a1logd(p->log, 3, "got filt %d, want %d\n",af,p->filt);
+ *idtype = filter_id[p->filt];
strcpy(id, filter_desc[p->filt]);
*calc = inst_calc_change_filter;
return inst_cal_setup;
@@ -1543,6 +1617,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (i < 36) {
*calc = inst_calc_message;
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
rv = inst_ok;
}
@@ -1596,6 +1671,7 @@ inst_code ss_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) */
) {
ss *p = (ss *)pp;
@@ -1605,7 +1681,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- return ss_calibrate_imp(p, calt, calc, id);
+ return ss_calibrate_imp(p, calt, calc, idtype, id);
}
/* Insert a compensation filter in the instrument readings */
@@ -1629,7 +1705,7 @@ char *filtername
} else {
xspect sp;
int i;
- if (read_xspect(&sp, filtername) != 0) {
+ if (read_xspect(&sp, NULL, filtername) != 0) {
return inst_wrong_setup;
}
if (sp.spec_n != 36 || sp.spec_wl_short != 380.0 || sp.spec_wl_long != 730.0) {
@@ -1944,6 +2020,35 @@ ss_get_set_opt(inst *pp, inst_opt_type m, ...) {
break;
}
return inst_unsupported;
+
+ /* Set the current xcalstd */
+ } else if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+
+ /* Get the current effective xcalstd */
+ } else if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
}
/* Record the trigger mode */
@@ -2002,6 +2107,34 @@ ss_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
+ /* Return the white calibration tile spectrum for current filter */
+ if (m == inst_opt_get_cal_tile_sp) {
+ ss_aft raf;
+ ss_owrt owr;
+ xspect *sp;
+ char dtn[19];
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ /* Queries the spectra of the white tile reference for the desired filter */
+ if ((rv = so_do_WhiteReferenceRequest(p, p->filt, &raf, sp->spec, &owr, dtn)) != inst_ok)
+ return rv;
+
+ sp->spec_n = 36;
+ sp->spec_wl_short = 380;
+ sp->spec_wl_long = 730;
+ sp->norm = 100.0;
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] *= 100.0;
+
+ return inst_ok;
+ }
+
/* Use default implementation of other inst_opt_type's */
{
va_list args;
diff --git a/spectro/ss.h b/spectro/ss.h
index bff0846..bc816e7 100644
--- a/spectro/ss.h
+++ b/spectro/ss.h
@@ -44,6 +44,10 @@
#include "inst.h"
#include "ss_imp.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#define SS_MAX_WR_SIZE 1000 /* Assumed maximum normal message query size */
#define SS_MAX_RD_SIZE 1000 /* Assumed maximum normal messagle answer size */
@@ -60,7 +64,7 @@ struct _ss {
inst_mode mode; /* Currently instrument mode */
/* Desired measurement configuration */
- ss_aft filt; /* Filter type (None/UV/D65 etc.) */
+ ss_aft filt; /* Filter type (None/UV/D65/Pol etc.) */
ss_dst dstd; /* Density standard (ANSI A/ANSI T/DIN etc.) */
ss_ilt illum; /* Illuminant type (A/C/D50 etc.) */
ss_ot obsv; /* Observer type (2deg/10deg) */
@@ -85,6 +89,9 @@ struct _ss {
int compen; /* Compensation filter enabled */
double comp[36]; /* Compensation filter */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
#ifdef EMSST
int tmode; /* Transmission mode */
ss_rt sbr; /* Standby reference */
@@ -111,5 +118,9 @@ struct _ss {
/* Constructor */
extern ss *new_ss(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define SS_H
#endif /* SS_H */
diff --git a/spectro/ss_imp.c b/spectro/ss_imp.c
index 6f184b3..05f0602 100644
--- a/spectro/ss_imp.c
+++ b/spectro/ss_imp.c
@@ -511,7 +511,7 @@ void ss_command(ss *p, double tmo) {
p->sbuf[2] = '\00'; /* write_read terminates on nul */
p->rbuf = p->_rbuf; /* Reset read pointer */
- if ((se = p->icom->write_read(p->icom, p->_sbuf, 0, p->_rbuf, SS_MAX_RD_SIZE, NULL, "\n", 1, tmo)) != 0) {
+ if ((se = p->icom->write_read_ex(p->icom, p->_sbuf, 0, p->_rbuf, SS_MAX_RD_SIZE, NULL, "\n", 1, tmo, 1)) != 0) {
p->snerr = icoms2ss_err(se);
return;
}
@@ -631,7 +631,7 @@ char pn[9], /* Return the part number */
unsigned int *sn, /* Return serial number */
char sv[13] /* Return software version */
) {
- char rsv[17]; /* Space for resered field */
+ char rsv[17]; /* Space for reserved field */
ss_add_soreq(p, ss_DeviceDataRequest);
ss_command(p, DF_TMO);
ss_sub_soans(p, ss_DeviceDataAnswer);
@@ -866,13 +866,13 @@ int ct /* Color temperature to set for illuminant Dxx in deg K/100 */
return ss_inst_err(p);
}
-/* Queries the spectra of the white reference for the desired filter */
+/* Queries the spectra of the white tile reference for the desired filter */
inst_code so_do_WhiteReferenceRequest(
ss *p,
ss_aft af, /* Filter being queried (None/Pol/D65/UV/custom */
ss_aft *raf, /* Return filter being queried (None/Pol/D65/UV/custom */
double sp[36], /* Return 36 spectral values */
-ss_owrt *owr, /* Return original white reference */
+ss_owrt *owr, /* Return original white reference (i.e. factory/user) */
char dtn[19] /* Return name of data table */
) {
int i;
@@ -890,6 +890,7 @@ char dtn[19] /* Return name of data table */
}
/* Load spectra of a user defined white reference for the desired filter. */
+/* This lets the user override the factory white tile calibration */
/* A name can be given to the white reference. */
inst_code so_do_WhiteReferenceDownld(
ss *p,
@@ -1312,12 +1313,20 @@ ss_toost oo /* Activated/Deactivated */
/* Initialise the device. Scans the Spectrolino */
/* (Doesn't work when device is offline ) */
inst_code ss_do_ScanInitializeDevice(ss *p) {
+ inst_code rv;
ss_add_ssreq(p, ss_InitializeDevice);
ss_command(p, IT_TMO);
ss_sub_ssans(p, ss_ErrorAnswer);
ss_incorp_scanerr(p, ss_sub_1(p));
chended(p);
- return ss_inst_err(p);
+ rv = ss_inst_err(p);
+
+ if (rv != inst_ok)
+ return rv;
+
+ /* Wait for Spectroscan to finish init. */
+ msec_sleep(3000);
+ return rv;
}
/* Establish communications between the SpectroScan and Spectrolino */
diff --git a/spectro/ss_imp.h b/spectro/ss_imp.h
index c298e80..ccd9ce3 100644
--- a/spectro/ss_imp.h
+++ b/spectro/ss_imp.h
@@ -37,6 +37,9 @@
and agreed to support.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
/* Communication symbol definitions */
/* From the Gretag Spectrolino/Spectroscan */
@@ -1086,7 +1089,8 @@ ss_toost oo /* Activated/Deactivated */
/* Device Initialisation and configuration */
/* Initialise the device. Scans the Spectrolino */
-/* (Doesn't work when device is offline ) */
+/* (Doesn't work when device is offline, */
+/* takes some seconds for the device to recover after reply.) */
inst_code ss_do_ScanInitializeDevice(struct _ss *p);
/* Establish communications between the SpectroScan and Spectrolino */
@@ -1331,5 +1335,9 @@ struct _ss *p,
ss_sss *sss /* Return Special Status bits */
);
+#ifdef __cplusplus
+ }
+#endif
+
#define SS_IMP_H
#endif /* SS_IMP_H */
diff --git a/spectro/strange.cal b/spectro/strange.cal
new file mode 100644
index 0000000..1e9451d
--- /dev/null
+++ b/spectro/strange.cal
@@ -0,0 +1,272 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Wed Sep 28 02:35:54 2016"
+DEVICE_CLASS "DISPLAY"
+COLOR_REP "RGB"
+
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.00000 0.00000 0.00000 0.00000
+0.00392157 0.0000567518 0.0118787 0.0186065
+0.00784314 0.000184387 0.0206820 0.0302263
+0.0117647 0.000367355 0.0286065 0.0401466
+0.0156863 0.000599076 0.0360094 0.0491028
+0.0196078 0.000875445 0.0430471 0.0574042
+0.0235294 0.00119354 0.0498068 0.0652184
+0.0274510 0.00155112 0.0563438 0.0726496
+0.0313725 0.00194640 0.0626960 0.0797678
+0.0352941 0.00237789 0.0688909 0.0866232
+0.0392157 0.00284433 0.0749493 0.0932533
+0.0431373 0.00334462 0.0808876 0.0996872
+0.0470588 0.00387782 0.0867187 0.105948
+0.0509804 0.00444307 0.0924533 0.112053
+0.0549020 0.00503962 0.0981003 0.118020
+0.0588235 0.00566676 0.103667 0.123859
+0.0627451 0.00632388 0.109160 0.129583
+0.0666667 0.00701040 0.114585 0.135201
+0.0705882 0.00772579 0.119946 0.140720
+0.0745098 0.00846956 0.125248 0.146148
+0.0784314 0.00924125 0.130494 0.151490
+0.0823529 0.0100404 0.135689 0.156754
+0.0862745 0.0108667 0.140834 0.161942
+0.0901961 0.0117197 0.145932 0.167061
+0.0941176 0.0125991 0.150986 0.172112
+0.0980392 0.0135045 0.155998 0.177102
+0.101961 0.0144356 0.160971 0.182031
+0.105882 0.0153921 0.165905 0.186904
+0.109804 0.0163738 0.170803 0.191723
+0.113725 0.0173803 0.175665 0.196491
+0.117647 0.0184114 0.180495 0.201210
+0.121569 0.0194668 0.185292 0.205882
+0.125490 0.0205464 0.190059 0.210508
+0.129412 0.0216498 0.194796 0.215092
+0.133333 0.0227769 0.199504 0.219634
+0.137255 0.0239274 0.204184 0.224136
+0.141176 0.0251012 0.208838 0.228600
+0.145098 0.0262980 0.213466 0.233027
+0.149020 0.0275177 0.218069 0.237418
+0.152941 0.0287600 0.222648 0.241774
+0.156863 0.0300249 0.227204 0.246097
+0.160784 0.0313121 0.231737 0.250388
+0.164706 0.0326215 0.236248 0.254647
+0.168627 0.0339528 0.240737 0.258876
+0.172549 0.0353061 0.245205 0.263076
+0.176471 0.0366810 0.249654 0.267247
+0.180392 0.0380775 0.254082 0.271391
+0.184314 0.0394954 0.258491 0.275507
+0.188235 0.0409345 0.262882 0.279597
+0.192157 0.0423948 0.267254 0.283662
+0.196078 0.0438762 0.271609 0.287702
+0.200000 0.0453784 0.275946 0.291718
+0.203922 0.0469014 0.280266 0.295710
+0.207843 0.0484450 0.284570 0.299680
+0.211765 0.0500091 0.288857 0.303627
+0.215686 0.0515937 0.293128 0.307552
+0.219608 0.0531985 0.297384 0.311455
+0.223529 0.0548235 0.301625 0.315338
+0.227451 0.0564686 0.305851 0.319201
+0.231373 0.0581337 0.310063 0.323043
+0.235294 0.0598187 0.314260 0.326866
+0.239216 0.0615234 0.318443 0.330670
+0.243137 0.0632478 0.322613 0.334456
+0.247059 0.0649918 0.326769 0.338223
+0.250980 0.0667553 0.330911 0.341972
+0.254902 0.0685382 0.335041 0.345703
+0.258824 0.0703403 0.339159 0.349418
+0.262745 0.0721617 0.343264 0.353115
+0.266667 0.0740022 0.347356 0.356797
+0.270588 0.0758618 0.351437 0.360461
+0.274510 0.0777403 0.355505 0.364110
+0.278431 0.0796377 0.359563 0.367744
+0.282353 0.0815539 0.363608 0.371362
+0.286275 0.0834889 0.367643 0.374965
+0.290196 0.0854424 0.371666 0.378553
+0.294118 0.0874146 0.375679 0.382127
+0.298039 0.0894052 0.379681 0.385686
+0.301961 0.0914143 0.383672 0.389231
+0.305882 0.0934417 0.387653 0.392763
+0.309804 0.0954873 0.391624 0.396281
+0.313725 0.0975512 0.395585 0.399786
+0.317647 0.0996332 0.399536 0.403277
+0.321569 0.101733 0.403477 0.406756
+0.325490 0.103851 0.407409 0.410222
+0.329412 0.105987 0.411331 0.413676
+0.333333 0.108141 0.415244 0.417117
+0.337255 0.110313 0.419147 0.420546
+0.341176 0.112503 0.423042 0.423963
+0.345098 0.114710 0.426927 0.427368
+0.349020 0.116935 0.430804 0.430762
+0.352941 0.119177 0.434672 0.434144
+0.356863 0.121437 0.438532 0.437515
+0.360784 0.123714 0.442383 0.440875
+0.364706 0.126009 0.446225 0.444224
+0.368627 0.128321 0.450060 0.447563
+0.372549 0.130650 0.453886 0.450890
+0.376471 0.132997 0.457704 0.454207
+0.380392 0.135360 0.461514 0.457514
+0.384314 0.137741 0.465317 0.460811
+0.388235 0.140139 0.469111 0.464097
+0.392157 0.142554 0.472898 0.467374
+0.396078 0.144986 0.476678 0.470641
+0.400000 0.147435 0.480450 0.473898
+0.403922 0.149900 0.484214 0.477145
+0.407843 0.152383 0.487972 0.480383
+0.411765 0.154882 0.491722 0.483612
+0.415686 0.157398 0.495465 0.486831
+0.419608 0.159931 0.499200 0.490042
+0.423529 0.162480 0.502929 0.493243
+0.427451 0.165046 0.506651 0.496436
+0.431373 0.167628 0.510366 0.499619
+0.435294 0.170227 0.514075 0.502794
+0.439216 0.172842 0.517776 0.505961
+0.443137 0.175474 0.521472 0.509119
+0.447059 0.178122 0.525160 0.512269
+0.450980 0.180787 0.528842 0.515410
+0.454902 0.183467 0.532518 0.518543
+0.458824 0.186164 0.536187 0.521668
+0.462745 0.188877 0.539850 0.524785
+0.466667 0.191606 0.543507 0.527895
+0.470588 0.194351 0.547158 0.530996
+0.474510 0.197113 0.550803 0.534090
+0.478431 0.199890 0.554441 0.537176
+0.482353 0.202684 0.558074 0.540254
+0.486275 0.205493 0.561701 0.543325
+0.490196 0.208318 0.565322 0.546388
+0.494118 0.211159 0.568937 0.549444
+0.498039 0.214016 0.572547 0.552493
+0.501961 0.216889 0.576150 0.555535
+0.505882 0.219777 0.579748 0.558569
+0.509804 0.222681 0.583341 0.561597
+0.513725 0.225601 0.586928 0.564617
+0.517647 0.228536 0.590510 0.567631
+0.521569 0.231487 0.594086 0.570638
+0.525490 0.234454 0.597657 0.573638
+0.529412 0.237436 0.601222 0.576631
+0.533333 0.240434 0.604782 0.579618
+0.537255 0.243447 0.608337 0.582598
+0.541176 0.246476 0.611887 0.585571
+0.545098 0.249520 0.615431 0.588538
+0.549020 0.252579 0.618971 0.591499
+0.552941 0.255654 0.622505 0.594453
+0.556863 0.258744 0.626035 0.597401
+0.560784 0.261849 0.629559 0.600343
+0.564706 0.264970 0.633079 0.603279
+0.568627 0.268105 0.636594 0.606208
+0.572549 0.271256 0.640103 0.609132
+0.576471 0.274422 0.643608 0.612049
+0.580392 0.277603 0.647109 0.614961
+0.584314 0.280800 0.650604 0.617867
+0.588235 0.284011 0.654095 0.620766
+0.592157 0.287237 0.657581 0.623661
+0.596078 0.290478 0.661063 0.626549
+0.600000 0.293735 0.664540 0.629431
+0.603922 0.297006 0.668012 0.632308
+0.607843 0.300292 0.671480 0.635180
+0.611765 0.303593 0.674944 0.638045
+0.615686 0.306909 0.678403 0.640906
+0.619608 0.310239 0.681857 0.643761
+0.623529 0.313585 0.685308 0.646610
+0.627451 0.316945 0.688754 0.649454
+0.631373 0.320320 0.692195 0.652293
+0.635294 0.323709 0.695633 0.655126
+0.639216 0.327114 0.699066 0.657954
+0.643137 0.330533 0.702495 0.660777
+0.647059 0.333966 0.705919 0.663595
+0.650980 0.337414 0.709340 0.666408
+0.654902 0.340877 0.712756 0.669215
+0.658824 0.344354 0.716169 0.672018
+0.662745 0.347846 0.719577 0.674816
+0.666667 0.351352 0.722981 0.677608
+0.670588 0.354873 0.726381 0.680396
+0.674510 0.358408 0.729778 0.683179
+0.678431 0.361958 0.733170 0.685957
+0.682353 0.365522 0.736559 0.688730
+0.686275 0.369100 0.739943 0.691498
+0.690196 0.372693 0.743324 0.694262
+0.694118 0.376300 0.746701 0.697021
+0.698039 0.379921 0.750074 0.699775
+0.701961 0.383557 0.753443 0.702525
+0.705882 0.387207 0.756808 0.705270
+0.709804 0.390871 0.760170 0.708010
+0.713725 0.394549 0.763528 0.710746
+0.717647 0.398242 0.766882 0.713477
+0.721569 0.401948 0.770233 0.716204
+0.725490 0.405669 0.773580 0.718927
+0.729412 0.409404 0.776923 0.721645
+0.733333 0.413153 0.780263 0.724358
+0.737255 0.416916 0.783599 0.727068
+0.741176 0.420693 0.786932 0.729773
+0.745098 0.424484 0.790261 0.732473
+0.749020 0.428289 0.793587 0.735170
+0.752941 0.432108 0.796909 0.737862
+0.756863 0.435940 0.800228 0.740550
+0.760784 0.439787 0.803543 0.743234
+0.764706 0.443648 0.806855 0.745914
+0.768627 0.447523 0.810164 0.748589
+0.772549 0.451411 0.813469 0.751261
+0.776471 0.455314 0.816770 0.753928
+0.780392 0.459230 0.820069 0.756592
+0.784314 0.463160 0.823364 0.759251
+0.788235 0.467103 0.826656 0.761906
+0.792157 0.471061 0.829944 0.764558
+0.796078 0.475032 0.833230 0.767205
+0.800000 0.479017 0.836512 0.769849
+0.803922 0.483016 0.839790 0.772489
+0.807843 0.487028 0.843066 0.775124
+0.811765 0.491054 0.846339 0.777756
+0.815686 0.495094 0.849608 0.780385
+0.819608 0.499147 0.852874 0.783009
+0.823529 0.503214 0.856137 0.785630
+0.827451 0.507294 0.859397 0.788247
+0.831373 0.511388 0.862654 0.790860
+0.835294 0.515496 0.865908 0.793469
+0.839216 0.519617 0.869158 0.796075
+0.843137 0.523751 0.872406 0.798677
+0.847059 0.527899 0.875651 0.801276
+0.850980 0.532061 0.878892 0.803871
+0.854902 0.536236 0.882131 0.806462
+0.858824 0.540424 0.885367 0.809050
+0.862745 0.544626 0.888599 0.811634
+0.866667 0.548841 0.891829 0.814215
+0.870588 0.553070 0.895056 0.816792
+0.874510 0.557311 0.898280 0.819366
+0.878431 0.561567 0.901501 0.821936
+0.882353 0.565835 0.904719 0.824503
+0.886275 0.570117 0.907935 0.827066
+0.890196 0.574412 0.911147 0.829626
+0.894118 0.578721 0.914357 0.832183
+0.898039 0.583042 0.917564 0.834736
+0.901961 0.587377 0.920768 0.837286
+0.905882 0.591725 0.923969 0.839833
+0.909804 0.596087 0.927168 0.842376
+0.913725 0.600461 0.930363 0.844916
+0.917647 0.604849 0.933556 0.847453
+0.921569 0.609249 0.936747 0.849986
+0.925490 0.613663 0.939934 0.852516
+0.929412 0.618090 0.943119 0.855044
+0.933333 0.622530 0.946301 0.857567
+0.937255 0.626984 0.949481 0.860088
+0.941176 0.631450 0.952658 0.862606
+0.945098 0.635929 0.955832 0.865120
+0.949020 0.640421 0.959003 0.867631
+0.952941 0.644927 0.962172 0.870139
+0.956863 0.649445 0.965339 0.872644
+0.960784 0.653976 0.968502 0.875146
+0.964706 0.658521 0.971664 0.877645
+0.968627 0.663078 0.974822 0.880141
+0.972549 0.667648 0.977978 0.882634
+0.976471 0.672231 0.981132 0.885124
+0.980392 0.676827 0.984283 0.887610
+0.984314 0.681436 0.987431 0.890094
+0.988235 0.686058 0.990577 0.892575
+0.992157 0.690692 0.993721 0.895053
+0.996078 0.695340 0.996862 0.897528
+1.000000 0.700000 1.000000 0.900000
+END_DATA
diff --git a/spectro/synthcal.c b/spectro/synthcal.c
index 75d18be..14471f6 100644
--- a/spectro/synthcal.c
+++ b/spectro/synthcal.c
@@ -41,6 +41,7 @@ usage(int level) {
fprintf(stderr,"Create a synthetic calibration file, Version %s\n",ARGYLL_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: synthcal [-options] outfile\n");
+ fprintf(stderr," -r res Set the calibration resolution (default 256)\n");
fprintf(stderr," -t N i = input, o = output, d = display (default)\n");
fprintf(stderr," -d col_comb choose colorant combination from the following (default 3):\n");
for (i = 0; ; i++) {
@@ -78,6 +79,7 @@ int main(int argc, char *argv[])
char *profDesc = NULL; /* Description */
int devtype = 2; /* debice type, 0 = in, 1 = out, 2 = display */
inkmask devmask = 0; /* ICX ink mask of device space */
+ int calres = 256; /* Resolution of resulting file */
int devchan; /* Number of chanels in device space */
char *ident; /* Ink combination identifier (includes possible leading 'i') */
char *bident; /* Base ink combination identifier */
@@ -120,8 +122,17 @@ int main(int argc, char *argv[])
else if (argv[fa][1] == 'v')
verb = 1;
+ /* Calibration file resolution */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ calres = atoi(na);
+ if (calres < 2 || calres > MAX_CAL_ENT)
+ usage(0);
+ }
+
/* Select the device type */
- else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ else if (argv[fa][1] == 't') {
fa = nfa;
if (na == NULL) usage(0);
if (na[0] == 'i' || na[0] == 'I')
@@ -280,7 +291,7 @@ int main(int argc, char *argv[])
/* Write out the resulting calibration file */
{
- int i, j, calres = 256; /* 256 steps in calibration */
+ int i, j;
cgats *ocg; /* output cgats structure */
time_t clk = time(0);
struct tm *tsp = localtime(&clk);
diff --git a/spectro/usbio.c b/spectro/usbio.c
index 9f8964a..fca997d 100644
--- a/spectro/usbio.c
+++ b/spectro/usbio.c
@@ -90,7 +90,7 @@ static int icoms_usb_wait_io(
# ifdef NT
# include "usbio_nt.c"
# endif
-# if defined(__APPLE__)
+# if defined(UNIX_APPLE)
# include "usbio_ox.c"
# endif
# if defined(UNIX_X11)
@@ -491,7 +491,7 @@ double tout) /* Time out in seconds */
return ICOM_SYS;
}
- if (p->port_type(p) == icomt_usbserial)
+ if (p->dctype & icomt_fastserial)
fastserial = 1;
for (j = 0; j < bsize; j++)
@@ -517,7 +517,7 @@ double tout) /* Time out in seconds */
int c, rv;
int rsize = bsize;
- /* If not a fast USB serial port, read in quanta size chunks */
+ /* If not a fast USB/BT serial port, read in quanta size chunks */
if (!fastserial && rsize > p->rd_qa)
rsize = p->rd_qa;
@@ -614,8 +614,7 @@ char **pnames /* List of process names to try and kill before opening */
) {
a1logd(p->log, 8, "icoms_set_usb_port: About to set usb port characteristics\n");
- if (p->port_type(p) == icomt_usb
- || p->port_type(p) == icomt_usbserial) {
+ if (p->port_type(p) & icomt_usb) {
int rv;
if (p->is_open)
diff --git a/spectro/usbio.h b/spectro/usbio.h
index 578bd83..2a01ea3 100644
--- a/spectro/usbio.h
+++ b/spectro/usbio.h
@@ -44,7 +44,7 @@ struct usb_idevice {
# endif /* NT */
-# if defined(UNIX) && defined(__APPLE__)
+# if defined(UNIX_APPLE)
/* OS X structure version wrangling */
@@ -127,7 +127,7 @@ struct usb_idevice {
};
# endif /* OS X */
-# if defined(UNIX) && !defined(__APPLE__)
+# if defined(UNIX_X11)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
diff --git a/spectro/usbio_bsd.c b/spectro/usbio_bsd.c
index 0af13a1..4b3e038 100644
--- a/spectro/usbio_bsd.c
+++ b/spectro/usbio_bsd.c
@@ -23,7 +23,7 @@
( Most of the below code is stubbed out, with the Linux
code as a placeholder. )
- BSD uses fd per end point, so simplifies things.
+ BSD uses fd per end point, so simplifies things (good).
No clear ep or abort i/o though, so we could try clear halt,
or close fd and see if that works in aborting transaction ?
@@ -57,7 +57,7 @@
#define poll_x poll
#endif
-/* Add paths to USB connected instruments */
+/* Add paths to USB connected device */
/* Return an icom error */
int usb_get_paths(
icompaths *p
@@ -75,7 +75,7 @@ icompaths *p
int vid, pid;
int nconfig = 0, nep = 0;
char *dpath;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
a1logd(p->log, 6, "usb_get_paths: about to look through usb devices:\n");
@@ -193,7 +193,7 @@ icompaths *p
break;
}
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
diff --git a/spectro/usbio_lx.c b/spectro/usbio_lx.c
index cb9ec59..6d001a2 100644
--- a/spectro/usbio_lx.c
+++ b/spectro/usbio_lx.c
@@ -81,7 +81,7 @@ char *dpath /* path to device */
unsigned char buf[IUSB_DESC_TYPE_DEVICE_SIZE];
unsigned vid, pid, nep10 = 0xffff;
unsigned int configix, nconfig, totlen;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
int fd; /* device file descriptor */
@@ -322,7 +322,7 @@ icompaths *p
}
}
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
@@ -384,6 +384,9 @@ void usb_close_port(icoms *p) {
ioctl(p->usbd->fd, USBDEVFS_RELEASEINTERFACE, &iface);
/* Workaround for some bugs - reset device on close */
+ /* !!!! Alternative would be to do reset before open.
+ On Linux the path stays the same, so could do open/reset/open
+ */
if (p->uflags & icomuf_reset_before_close) {
if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESET, NULL)) != 0) {
a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv);
@@ -531,7 +534,8 @@ char **pnames /* List of process names to try and kill before opening */
/* Clear any errors. */
/* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
- /* The ColorMunki on Linux only starts every second time if we don't do this. */
+ /* (The ColorMunki on some Linux's only starts every second time if we don't do this, */
+ /* and on others, every second time if we do.) */
if (!(p->uflags & icomuf_no_open_clear)) {
for (i = 0; i < 32; i++) {
if (!p->ep[i].valid)
@@ -701,7 +705,8 @@ static void *urb_reaper(void *context) {
iurb = (usbio_urb *)out->usercontext;
req = iurb->req;
- a1logd(p->log, 8, "urb_reaper: urb reap URB %d with status %d bytes %d, urbs left %d\n",iurb->urbno, out->status, out->actual_length, req->nourbs-1);
+ a1logd(p->log, 8, "urb_reaper: urb reap URB %d with status %d, bytes %d, urbs left %d\n",iurb->urbno, out->status, out->actual_length, req->nourbs-1);
+
pthread_mutex_lock(&req->lock); /* Stop requester from missing reap */
req->nourbs--; /* We're reaped one */
@@ -778,7 +783,7 @@ static int icoms_usb_transaction(
int i;
in_usb_rw++;
- a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
+ a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d to %d\n",ttype,endpoint,length, timeout);
if (!p->usbd->running) {
in_usb_rw--;
diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c
index f5c3af8..34426fd 100644
--- a/spectro/usbio_nt.c
+++ b/spectro/usbio_nt.c
@@ -99,14 +99,14 @@ int *retsz) {
return ICOM_OK;
}
-/* Add paths to USB connected instruments */
+/* Add paths to USB connected device */
/* Return an icom error */
int usb_get_paths(
icompaths *p
) {
unsigned int vid, pid, nep10 = 0xffff;
unsigned int configix, nconfig, nifce;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
int rv, retsz, i;
diff --git a/spectro/usbio_ox.c b/spectro/usbio_ox.c
index d3da59a..2b09955 100644
--- a/spectro/usbio_ox.c
+++ b/spectro/usbio_ox.c
@@ -15,6 +15,8 @@
* see the License2.txt file for licencing details.
*/
+/* OS X I/O error codes are in IOKit/IOReturn.h */
+
#include <sys/time.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -62,7 +64,7 @@ icompaths *p
CFNumberRef nconfref; /* No configurations */
CFNumberRef nepref, lidpref; /* No ep's, Location ID properties */
unsigned int vid = 0, pid = 0, nep, tnep, nconfig = 0, lid = 0;
- instType itype;
+ devType itype;
if ((ioob = IOIteratorNext(mit)) == 0)
break;
@@ -127,7 +129,7 @@ icompaths *p
unsigned int config = 0;
/* Get the configuration number */
- if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
+ if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBConfigurationValue),
kCFAllocatorDefault,kNilOptions)) != 0) {
CFNumberGetValue(nconfref, kCFNumberIntType, &config);
CFRelease(nconfref);
@@ -157,16 +159,16 @@ icompaths *p
/* If this device is HID, it will have already added to the paths list, */
/* so check for this and skip this device if it is already there. */
- for (i = 0; i < p->npaths; i++) {
- if (p->paths[i]->vid == vid
- && p->paths[i]->pid == pid
- && p->paths[i]->hidd != NULL
- && p->paths[i]->hidd->lid == lid) {
+ for (i = 0; i < p->ndpaths[dtix_combined]; i++) {
+ if (p->dpaths[i][dtix_combined]->vid == vid
+ && p->dpaths[i][dtix_combined]->pid == pid
+ && p->dpaths[i][dtix_combined]->hidd != NULL
+ && p->dpaths[i][dtix_combined]->hidd->lid == lid) {
a1logd(p->log, 1, "usb_get_paths: Ignoring device because it is already in list as HID\n");
break;
}
}
- if (i < p->npaths) {
+ if (i < p->ndpaths[dtix_combined]) {
IOObjectRelease(ioob); /* Release found object */
free(usbd);
@@ -195,7 +197,7 @@ icompaths *p
}
IOObjectRelease(mit); /* Release the itterator */
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
@@ -271,6 +273,8 @@ void usb_close_port(icoms *p) {
/* Workaround for some bugs - reset device on close */
if (p->uflags & icomuf_reset_before_close) {
IOReturn rv;
+ // ~~~~ may have to switch to ->USBDeviceReEnumerate(p->usbd->device, 0) ???
+ // because new OS X 10.11 ignore ResetDevice ?
if ((rv = (*(p->usbd->device))->ResetDevice(p->usbd->device)) != kIOReturnSuccess) {
a1logd(p->log, 1, "usb_close_port: ResetDevice failed with 0x%x\n",rv);
}
diff --git a/spectro/webwin.c b/spectro/webwin.c
index e13981a..1d5f713 100644
--- a/spectro/webwin.c
+++ b/spectro/webwin.c
@@ -70,7 +70,9 @@ char src_addr[20];
}
mg_printf(conn,
- "\r\n#%02X%02X%02X",
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "#%02X%02X%02X",
(int)(p->r_rgb[0] * 255.0 + 0.5),
(int)(p->r_rgb[1] * 255.0 + 0.5),
(int)(p->r_rgb[2] * 255.0 + 0.5));
@@ -93,7 +95,8 @@ static void *webwin_ehandler(enum mg_event event,
} else if (strcmp(request_info->uri, "/webdisp.js") == 0) {
#ifndef NEVER
char *webdisp_js =
- "\r\n"
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: application/javascript\r\n\r\n"
"if (typeof XMLHttpRequest == \"undefined\") {\r\n"
" XMLHttpRequest = function () {\r\n"
" try { return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\"); }\r\n"
@@ -141,17 +144,26 @@ static void *webwin_ehandler(enum mg_event event,
#else
return NULL; /* Read webdisp.js */
#endif
- } else {
+ } else if (strcmp(request_info->uri, "/") == 0) {
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
- "Content-Type: text/html\r\n\r\n"
+ "Content-Type: text/html; charset=UTF-8\r\n\r\n"
+ "<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>ArgyllCMS Web Display</title>\r\n"
"<script src=\"webdisp.js\"></script>\r\n"
"</head>\r\n"
+ "<body>\r\n"
+ "</body>\r\n"
"</html>\r\n"
);
+ } else {
+ mg_printf(conn, "HTTP/1.1 404 Not Found\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "404 Not Found: %s",
+ request_info->uri
+ );
}
// "<script type=\"text/javascript\"src=\"webdisp.js\"></script>"
@@ -230,9 +242,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
@@ -361,8 +373,11 @@ int ddebug /* >0 to print debug statements to stderr */
p->ncix = 1;
- p->pdepth = 8; /* Assume this by API */
- p->edepth = 8;
+ p->fdepth = 8; /* Assume this by API */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+ p->nent = 0; /* No ramdac */
+ p->edepth = 8; /* Assumed */
/* Basic object is initialised, so create a web server */
diff --git a/spectro/xdg_bds.c b/spectro/xdg_bds.c
index c1805ed..e24e4ab 100644
--- a/spectro/xdg_bds.c
+++ b/spectro/xdg_bds.c
@@ -169,20 +169,22 @@ static char *append(char *in, char *app) {
return rv;
}
-/* Append a ':' or ';' then a string. Free in. Return NULL on error. */
+/* Append a ':' or ';' then a string. Free in. */
+/* Return NULL on error. */
static char *cappend(char *in, char *app) {
- int inlen;
+ int inlen, aplen;
char *rv;
inlen = strlen(in);
+ aplen = strlen(app);
- if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ if ((rv = malloc(inlen + 1 + aplen + 1)) == NULL) {
a1loge(g_log, 1, "xdg_bds: cappend malloc failed\n");
free(in);
return NULL;
}
strcpy(rv, in);
- if (inlen > 1)
+ if (inlen > 0 && in[inlen-1] != SSEP && aplen > 0)
strcat(rv, SSEPS);
strcat(rv, app);
free(in);
@@ -190,20 +192,22 @@ static char *cappend(char *in, char *app) {
return rv;
}
-/* Append a '/' then a string. Free in. Return NULL on error. */
+/* Append a '/' then a string. Free in. */
+/* Return NULL on error. */
static char *dappend(char *in, char *app) {
- int inlen;
+ int inlen, aplen;
char *rv;
inlen = strlen(in);
+ aplen = strlen(app);
- if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ if ((rv = malloc(inlen + 1 + aplen + 1)) == NULL) {
a1loge(g_log, 1, "xdg_bds: dappend malloc failed\n");
free(in);
return NULL;
}
strcpy(rv, in);
- if (inlen > 1 && in[inlen-1] != '/')
+ if (inlen > 0 && in[inlen-1] != '/')
strcat(rv, "/");
strcat(rv, app);
free(in);
@@ -332,7 +336,7 @@ int xdg_bds(
if (getenv("HOME") != NULL)
path = dappend(path, ".local/share");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Application Support");
#else /* Unix, Default */
path = dappend(path, ".local/share");
@@ -380,7 +384,7 @@ int xdg_bds(
if (getenv("HOME") != NULL)
path = dappend(path, ".config");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Preferences");
#else /* Unix, Default */
path = dappend(path, ".config");
@@ -435,7 +439,7 @@ int xdg_bds(
else
path = dappend(path, "Cache");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Caches");
#else /* Unix, Default */
path = dappend(path, ".cache");
@@ -477,7 +481,7 @@ int xdg_bds(
}
path = cappend(path, home);
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = cappend(path, "/Library");
#else
path = cappend(path, "/usr/local/share:/usr/share");
@@ -508,7 +512,7 @@ int xdg_bds(
}
path = cappend(path, home);
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = cappend(path, "/Library/Preferences");
#else
path = cappend(path, "/etc/xdg");
diff --git a/spectro/xdg_bds.h b/spectro/xdg_bds.h
index 5c29790..4fedbea 100644
--- a/spectro/xdg_bds.h
+++ b/spectro/xdg_bds.h
@@ -70,7 +70,7 @@ typedef enum {
#endif
/* ONLY use this for xdg_data type */
-#ifdef __APPLE__ /* fudge to assist OS X migration from */
+#ifdef UNIX_APPLE /* fudge to assist OS X migration from */
#define XDG_FUDGE SSEPS "../" /* Library/color to Library/Application Support/ArgyllCMS */
#else
#define XDG_FUDGE SSEPS
diff --git a/spectro/xrga.c b/spectro/xrga.c
new file mode 100644
index 0000000..0bf22fa
--- /dev/null
+++ b/spectro/xrga.c
@@ -0,0 +1,224 @@
+
+/*
+ * This file contains resources to translate colors to/from
+ * X-Rites XRGA calibration standard. This only applies to
+ * reflective measurements from historical Gretag-Macbeth & X-Rite
+ * instruments, and current X-Rite instruments.
+ */
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 9/2/2016
+ * Version: 1.00
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#if defined(UNIX)
+# include <utime.h>
+#else
+# include <sys/utime.h>
+#endif
+#include <sys/stat.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#ifndef SALONEINSTLIB
+# include "plot.h"
+#endif
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "rspec.h"
+
+#include "xrga.h"
+
+/* A conversion equation */
+typedef struct {
+ double gain0, gain1; /* Destination gain at 550 nm, slope */
+ double wl0; /* Wavlength shift at 550nm to source - assumed constant */
+} xrga_eqn;
+
+/* XRGA conversion values in order [pol][src][dst] */
+/* Parameters are gain at 550nm, slope of gain per nm, src wavelengh offset in nm. */
+/* These values were inferred from the results one gets from processing spectral */
+/* values though X-Rite's conversion routines. */
+
+xrga_eqn xrga_equations[2][3][3] = {
+ { /* Unpolarized */
+ {
+ { 1.000000, 0.000000, 0.000000 }, /* XRDI -> XRDI */
+ { 1.000046, -0.000050, -1.400568 }, /* XRDI -> GMDI */
+ { 1.000005, -0.000025, -0.400084 } /* XRDI -> XRGA */
+ },
+ {
+ { 1.000046, 0.000050, 1.400568 }, /* GMDI -> XRDI */
+ { 1.000000, 0.000000, 0.000000 }, /* GMDI -> GMDI */
+ { 1.000015, 0.000025, 1.000207 } /* GMDI -> XRGA */
+ },
+ {
+ { 1.000005, 0.000025, 0.400084 }, /* XRGA -> XRDI */
+ { 1.000015, -0.000025, -1.000207 }, /* XRGA -> GMDI */
+ { 1.000000, 0.000000, 0.000000 } /* XRGA -> XRGA */
+ }
+ },
+ { /* Polarized */
+ {
+ { 1.000000, 0.000000, 0.000000 }, /* XRDI -> XRDI */
+ { 1.028710, -0.000081, -1.399477 }, /* XRDI -> GMDI */
+ { 1.000005, -0.000025, -0.400084 } /* XRDI -> XRGA */
+ },
+ {
+ { 0.971957, 0.000072, 1.398829 }, /* GMDI -> XRDI */
+ { 1.000000, 0.000000, 0.000000 }, /* GMDI -> GMDI */
+ { 0.971975, 0.000049, 0.998938 } /* GMDI -> XRGA */
+ },
+ {
+ { 1.000005, 0.000025, 0.400084 }, /* XRGA -> XRDI */
+ { 1.028711, -0.000056, -0.999421 }, /* XRGA -> GMDI */
+ { 1.000000, 0.000000, 0.000000 } /* XRGA -> XRGA */
+ }
+ }
+};
+
+
+/* Core conversion code. dst and src are assumed to be different xspect's */
+static void convert_xrga(xspect *dst, xspect *src, xrga_eqn *eq) {
+ int j;
+
+ XSPECT_COPY_INFO(dst, src); /* Copy parameters */
+
+ for (j = 0; j < dst->spec_n; j++) {
+ double dw, sw, ga;
+ double spcing, f;
+ double y[4], yw;
+ double x[4];
+ int i;
+
+ dw = XSPECT_XWL(dst, j); /* Destination wavelength */
+ sw = dw + eq->wl0; /* Source wavelength */
+ ga = eq->gain0 + (dw - 550.0) * eq->gain1; /* Gain at this dest wl */
+
+ /* Compute fraction 0.0 - 1.0 out of known spectrum. */
+ /* Place it so that the target wavelength lands in middle section */
+ /* of Lagrange basis points. */
+ spcing = (src->spec_wl_long - src->spec_wl_short)/(src->spec_n-1.0);
+ f = (sw - src->spec_wl_short) / (src->spec_wl_long - src->spec_wl_short);
+ f *= (src->spec_n - 1.0);
+ i = (int)floor(f); /* Base grid coordinate */
+
+ if (i < 1) /* Limit to valid Lagrange basis index range, */
+ i = 1; /* and extrapolate from that at the ends. */
+ else if (i > (src->spec_n - 3))
+ i = (src->spec_n - 3);
+
+ /* Setup the surrounding values */
+ x[0] = src->spec_wl_short + (i-1) * spcing;
+ y[0] = src->spec[i-1];
+ x[1] = src->spec_wl_short + i * spcing;
+ y[1] = src->spec[i];
+ x[2] = src->spec_wl_short + (i+1) * spcing;
+ y[2] = src->spec[i+1];
+ x[3] = src->spec_wl_short + (i+2) * spcing;
+ y[3] = src->spec[i+2];
+
+
+ /* Compute interpolated value using Lagrange: */
+ yw = y[0] * (sw-x[1]) * (sw-x[2]) * (sw-x[3])/((x[0]-x[1]) * (x[0]-x[2]) * (x[0]-x[3]))
+ + y[1] * (sw-x[0]) * (sw-x[2]) * (sw-x[3])/((x[1]-x[0]) * (x[1]-x[2]) * (x[1]-x[3]))
+ + y[2] * (sw-x[0]) * (sw-x[1]) * (sw-x[3])/((x[2]-x[0]) * (x[2]-x[1]) * (x[2]-x[3]))
+ + y[3] * (sw-x[0]) * (sw-x[1]) * (sw-x[2])/((x[3]-x[0]) * (x[3]-x[1]) * (x[3]-x[2]));
+
+ yw *= ga;
+
+ dst->spec[j] = yw;
+ }
+}
+
+/* Apply a conversion from one calibration standard to another to an xspect */
+void xspec_convert_xrga(xspect *dst, xspect *srcp, xcalpol pol, xcalstd dsp, xcalstd ssp) {
+ xrga_eqn *eq;
+ xspect tmp, *src = srcp;
+
+ /* If no conversion and no copy needed */
+ if ((ssp == xcalstd_native || dsp == xcalstd_native || dsp == ssp)
+ && dst == src)
+ return;
+
+ /* If no conversion needed */
+ if (ssp == xcalstd_native || dsp == xcalstd_native || dsp == ssp) {
+ *dst = *src; /* Struct copy */
+ return;
+ }
+
+ /* If the dest is the same as the src, make a temporary copy */
+ if (dst == src) {
+ tmp = *src; /* Struct copy */
+ src = &tmp;
+
+ } else {
+ XSPECT_COPY_INFO(dst, src); /* Copy parameters */
+ }
+
+ eq = &xrga_equations[pol][ssp][dsp];
+ convert_xrga(dst, src, eq);
+}
+
+/* Apply a conversion from one calibration standard to another to an array of ipatch's */
+void ipatch_convert_xrga(ipatch *vals, int nvals,
+ xcalpol pol, xcalstd dsp, xcalstd ssp, int clamp) {
+ xrga_eqn *eq;
+ xspect tmp;
+ xsp2cie *conv = NULL; /* Spectral to XYZ conversion object */
+ int i;
+
+ /* If no conversion needed */
+ if (ssp == xcalstd_native || dsp == xcalstd_native
+ || dsp == ssp || nvals <= 0)
+ return;
+
+ /* Conversion to use */
+ eq = &xrga_equations[pol][ssp][dsp];
+
+ for (i = 0; i < nvals; i++) {
+ if (vals[i].mtype != inst_mrt_reflective
+ || vals[i].sp.spec_n <= 0) {
+ continue;
+ }
+ tmp = vals[i].sp; // Struct copy */
+ convert_xrga(&vals[i].sp, &tmp, eq);
+
+ /* Re-compute XYZ */
+ if (vals[i].XYZ_v) {
+ if (conv == NULL) {
+ conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2,
+ NULL, icSigXYZData, (icxClamping)clamp);
+ }
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+ vals[i].XYZ[0] *= 100.0; /* Convert to % */
+ vals[i].XYZ[1] *= 100.0;
+ vals[i].XYZ[2] *= 100.0;
+ }
+ }
+ if (conv != NULL)
+ conv->del(conv);
+}
diff --git a/spectro/xrga.h b/spectro/xrga.h
new file mode 100644
index 0000000..0605fc8
--- /dev/null
+++ b/spectro/xrga.h
@@ -0,0 +1,86 @@
+
+#ifndef XRGA_H
+#define XRGA_H
+
+/*
+ * This file contains resources to translate colors to/from
+ * X-Rites XRGA calibration standard. This only applies to
+ * reflective measurements from historical Gretag-Macbeth & X-Rite
+ * instruments, and current X-Rite instruments.
+ */
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 9/2/2016
+ * Version: 1.00
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef enum {
+ xcalstd_nonpol = 0, /* Unpolarized */
+ xcalstd_pol = 1 /* Polarized */
+} xcalpol;
+
+/* Apply a conversion from one calibration standard to another to an xspect. */
+void xspec_convert_xrga(xspect *dst, xspect *srcp, xcalpol pol, xcalstd dsp, xcalstd ssp);
+
+/* Apply a conversion from one calibration standard to another to an array of ipatch's */
+void ipatch_convert_xrga(ipatch *vals, int nvals,
+ xcalpol pol, xcalstd dsp, xcalstd ssp, int clamp);
+
+/* Macro returns true if a conversion is needed */
+#define XCALSTD_NEEDED(ssp, dsp) \
+ ((ssp) != xcalstd_native && (dsp) != xcalstd_native && (dsp) != (ssp))
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* XRGA_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+