diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-08-23 12:22:51 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-08-23 12:22:51 +0200 |
commit | bc3604d9b226ac475a104cd8ae2ca2d1d4a27984 (patch) | |
tree | e796661f371a94a50edfdc693388bb911b253dfd /spectro | |
parent | 509016be676f7915d635fa57144d2a441e3090ca (diff) | |
parent | c0b89ac5bfb90835ef01573267020e42d4fe070c (diff) |
Merge new upstream release
Diffstat (limited to 'spectro')
-rwxr-xr-x[-rw-r--r--] | spectro/IntsLib_Readme.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Jamfile | 49 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/License.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/License2.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/License3.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/LzmaDec.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/LzmaDec.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/LzmaTypes.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Makefile.OSX | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Makefile.SA | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Makefile.UNIX | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Makefile.WNT | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/Readme.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/SOtele.sp | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/afiles | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/aglob.c | 28 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/aglob.h | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/average.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/base64.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/base64.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ccwin.c | 319 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ccwin.h | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ccxx.ti1 | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ccxxmake.c | 35 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/chartread.c | 12 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/colorhug.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/colorhug.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/conv.c | 32 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/conv.h | 6 | ||||
-rwxr-xr-x | spectro/cubecal.h | 5554 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispcal.c | 55 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispread.c | 42 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispsup.c | 270 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispsup.h | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/disptechs.c | 128 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/disptechs.h | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispwin.c | 45 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dispwin.h | 30 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp20.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp20.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp22.c | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp22.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp41.c | 12 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp41.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp51.c | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp51.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp92.c | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/dtp92.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ex1.c | 2902 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ex1.h | 108 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/fakeread.c | 11 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/hcfr.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/hcfr.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/hidio.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/hidio.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/huey.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/huey.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1d3.c | 16 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1d3.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1disp.c | 8 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1disp.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1pro.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1pro.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1pro_imp.c | 108 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/i1pro_imp.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/icoms.c | 30 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/icoms.h | 46 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/icoms_nt.c | 369 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/icoms_ux.c | 163 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ifiles | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/illumread.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/inflate.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/inst.c | 191 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/inst.h | 81 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/instappsup.c | 57 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/instappsup.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/instlib.ksh | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/instlib.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/insttypeinst.h | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/insttypes.c | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/insttypes.h | 13 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/iusb.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/kleink10.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/kleink10.h | 0 | ||||
-rwxr-xr-x | spectro/linear.cal | 272 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/linear.sp | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/madvrwin.c | 31 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/madvrwin.h | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/mongoose.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/mongoose.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/munki.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/munki.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/munki_imp.c | 40 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/munki_imp.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/oemarch.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/oemarch.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/oeminst.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/pollem.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/pollem.h | 0 | ||||
-rwxr-xr-x | spectro/rspec.c | 1258 | ||||
-rwxr-xr-x | spectro/rspec.h | 265 | ||||
-rwxr-xr-x | spectro/smcube.c | 2187 | ||||
-rwxr-xr-x | spectro/smcube.h | 119 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/spec2cie.c | 103 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/specbos.c | 45 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/specbos.h | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/spotread.c | 83 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/spyd2.c | 100 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/spyd2.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ss.c | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ss.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ss_imp.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/ss_imp.h | 0 | ||||
-rwxr-xr-x | spectro/strange.cal | 272 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/synthcal.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/synthread.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio.c | 47 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio_bsd.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio_lx.c | 20 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio_nt.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/usbio_ox.c | 12 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/vinflate.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/webwin.c | 22 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/webwin.h | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/xdg_bds.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | spectro/xdg_bds.h | 0 |
127 files changed, 13816 insertions, 1880 deletions
diff --git a/spectro/IntsLib_Readme.txt b/spectro/IntsLib_Readme.txt index 7d9fb0c..7d9fb0c 100644..100755 --- a/spectro/IntsLib_Readme.txt +++ b/spectro/IntsLib_Readme.txt diff --git a/spectro/Jamfile b/spectro/Jamfile index 3aedce6..9eb292f 100644..100755 --- a/spectro/Jamfile +++ b/spectro/Jamfile @@ -2,6 +2,7 @@ #PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags +#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging & Debugging flags PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Compile .c as .m @@ -10,7 +11,10 @@ if $(OS) = MACOSX { ObjectCcFlags dispwin_dispwin : -ObjC ; } -DEFINES += ENABLE_FTDI ; +if [ GLOB [ NormPaths . ] : fastserio.c ] { +# echo "!!!!!!!!! fastserio.c is enabled !!!!!!!!!" ; +# DEFINES += ENABLE_FTDI ; +} MADVRSOURCE = ; @@ -94,7 +98,7 @@ USB_INSTS = dtp20.c i1disp.c i1d3.c i1pro.c i1pro_imp.c munki.c munki_imp.c hcfr.c spyd2.c huey.c colorhug.c ex1.c usbio.c hidio.c ; -FAST_SER_INSTS = specbos.c kleink10.c ; +FAST_SER_INSTS = specbos.c kleink10.c smcube.c ; SER_USB_INSTS = dtp92.c ; @@ -123,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 $(INST_SRCS) ; +Library libinst : inst.c insttypes.c icoms.c disptechs.c rspec.c $(INST_SRCS) ; # Display access library ObjectKeep mongoose.c ; @@ -153,7 +157,7 @@ LINKLIBS = libinst libinstapp ../gamut/libgamut ../rspl/librspl ../cgats/libcgats ../icc/libicc ../plot/libplot ../plot/libvrml - ../ccast/libccast ../ccast/axTLS/libaxtls ../yajl/libyajl ../render/librender + ../ccast/libccast $(SSLLIB) ../yajl/libyajl ../render/librender $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIB) ../numlib/libui ../numlib/libnum $(CMMLIBS) libconv ; @@ -242,9 +246,6 @@ NDepends exe : strange.cal ; # Normally create it # Individual stand alone test of xdg_bds library MainVariant xdg_bds : xdg_bds.c : : STANDALONE_TEST : : : libconv ; -# Simple test code of aglob -#Main globtest : globtest.c : : : : : libconv ; - # fp conversion code test #Main fp : fp.c ; @@ -258,21 +259,37 @@ MainVariant xdg_bds : xdg_bds.c : : STANDALONE_TEST : : : libconv ; #Main t9 : t9.c ; #Main i1d3eval : i1d3eval.c ; +# Simple test code of aglob +if [ GLOB [ NormPaths . ] : globtest.c ] { + Main globtest : globtest.c : : : : : libconv ; +} -# Test code -if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/spectro" { - # /SUBSYSTEM:WINDOWS on NT link ? -# GuiBin oemdnld ; +# reflect_db.txt parser */ +if [ GLOB [ NormPaths . ] : txt2sp.c ] { + Main txt2sp : txt2sp.c ; +} + +# SwatchMate Cube calibration +if [ GLOB [ NormPaths . ] : cubecal.c ] { + Main cubecal : cubecal.c ; +} + +# ColorMeter utility +if [ GLOB [ NormPaths . ] : oemdnld.c ] { + echo "Found oemdnld.c !" ; Main oemdnld : oemdnld.c : : : : oemarch vinflate inflate LzmaDec mongoose : libconv ; -# Main fakeindev : fakeindev.c ; -# Main cmtest : cmtest.c : : : : : libconv ; -# Main webdisp : webdisp.c : : : : : libconv ; } -if $(OLD_GRETAG) && $(UNIX) && $(OS) != MACOSX { +# Test code +if $(BUILD_JUNK) { + + # /SUBSYSTEM:WINDOWS on NT link ? + # Main fakeindev : fakeindev.c ; + # Main cmtest : cmtest.c : : : : : libconv ; + # Main webdisp : webdisp.c : : : : : libconv ; # test for parsing a VISE archive - Main visetest : visetest.c vinflate.c ; + #Main visetest : visetest.c vinflate.c ; # Compute deconvolution filter for i1pro #Main i1deconv : i1deconv.c ; diff --git a/spectro/License.txt b/spectro/License.txt index a871fcf..a871fcf 100644..100755 --- a/spectro/License.txt +++ b/spectro/License.txt diff --git a/spectro/License2.txt b/spectro/License2.txt index 05ca889..05ca889 100644..100755 --- a/spectro/License2.txt +++ b/spectro/License2.txt diff --git a/spectro/License3.txt b/spectro/License3.txt index 94a9ed0..94a9ed0 100644..100755 --- a/spectro/License3.txt +++ b/spectro/License3.txt diff --git a/spectro/LzmaDec.c b/spectro/LzmaDec.c index 8c1a148..8c1a148 100644..100755 --- a/spectro/LzmaDec.c +++ b/spectro/LzmaDec.c diff --git a/spectro/LzmaDec.h b/spectro/LzmaDec.h index 6045fae..6045fae 100644..100755 --- a/spectro/LzmaDec.h +++ b/spectro/LzmaDec.h diff --git a/spectro/LzmaTypes.h b/spectro/LzmaTypes.h index 7732c24..7732c24 100644..100755 --- a/spectro/LzmaTypes.h +++ b/spectro/LzmaTypes.h diff --git a/spectro/Makefile.OSX b/spectro/Makefile.OSX index 485cbf4..485cbf4 100644..100755 --- a/spectro/Makefile.OSX +++ b/spectro/Makefile.OSX diff --git a/spectro/Makefile.SA b/spectro/Makefile.SA index 2d57742..2d57742 100644..100755 --- a/spectro/Makefile.SA +++ b/spectro/Makefile.SA diff --git a/spectro/Makefile.UNIX b/spectro/Makefile.UNIX index adafa67..adafa67 100644..100755 --- a/spectro/Makefile.UNIX +++ b/spectro/Makefile.UNIX diff --git a/spectro/Makefile.WNT b/spectro/Makefile.WNT index 83eef28..83eef28 100644..100755 --- a/spectro/Makefile.WNT +++ b/spectro/Makefile.WNT diff --git a/spectro/Readme.txt b/spectro/Readme.txt index b9fe0aa..b9fe0aa 100644..100755 --- a/spectro/Readme.txt +++ b/spectro/Readme.txt diff --git a/spectro/SOtele.sp b/spectro/SOtele.sp index f63d90e..f63d90e 100644..100755 --- a/spectro/SOtele.sp +++ b/spectro/SOtele.sp diff --git a/spectro/afiles b/spectro/afiles index ecea51d..984bac5 100644..100755 --- a/spectro/afiles +++ b/spectro/afiles @@ -80,8 +80,13 @@ colorhug.c colorhug.h ex1.c ex1.h +smcube.c +smcube.h +cubecal.h spec2cie.c average.c +rspec.h +rspec.c conv.h conv.c aglob.h diff --git a/spectro/aglob.c b/spectro/aglob.c index e700f76..2ba37d5 100644..100755 --- a/spectro/aglob.c +++ b/spectro/aglob.c @@ -102,8 +102,34 @@ int aglob_create(aglob *g, char *spath) { g->first = 1; g->ff = _findfirst(spath, &g->ffs); #else /* UNIX */ + char *tpath, *d, *s; + + /* Make a copy of the pattern with extra space */ + if ((tpath = malloc(4 * strlen(spath)+1)) == NULL) { + a1loge(g_log, 1, "aglob_create: malloc failed\n"); + return 1; + } + strcpy(tpath, spath); + + /* If there is a file extension, make it case insensitive */ + if ((s = strrchr(spath, '.')) != NULL) { + d = tpath + (s - spath); + while (*s != '\000') { + if (isalpha(*s)) { + *d++ = '['; + *d++ = tolower(*s); + *d++ = toupper(*s++); + *d++ = ']'; + } else { + *d++ = *s++; + } + } + *d++ = '\000'; +//printf("~` converted '%s' to '%s'\n",spath,tpath); + } memset(&g->g, 0, sizeof(g->g)); - g->rv = glob(spath, GLOB_NOSORT, NULL, &g->g); + g->rv = glob(tpath, GLOB_NOSORT, NULL, &g->g); + free(tpath); //a1loge(g_log, 0, "~1 glob '%s' returns %d and gl_pathc = %d\n",spath,g->rv,g->g.gl_pathc); if (g->rv == GLOB_NOSPACE) { a1loge(g_log, 1, "aglob_create: glob returned GLOB_NOSPACE\n"); diff --git a/spectro/aglob.h b/spectro/aglob.h index 6c46746..dbb5025 100644..100755 --- a/spectro/aglob.h +++ b/spectro/aglob.h @@ -45,6 +45,10 @@ typedef struct { /* Create the aglob for files matching the given path and pattern. */ +/* Characters '*' and '?' are treated as wildcards. */ +/* Note that on Unix, '?' matches exactly one character, while on */ +/* MSWin it matches 0 or 1 characters. */ +/* Any file extension will be treated as case insensitive on all OS's. */ /* Return nz on malloc error */ int aglob_create(aglob *g, char *spath); diff --git a/spectro/average.c b/spectro/average.c index 5a8fb3f..5a8fb3f 100644..100755 --- a/spectro/average.c +++ b/spectro/average.c diff --git a/spectro/base64.c b/spectro/base64.c index 388d121..388d121 100644..100755 --- a/spectro/base64.c +++ b/spectro/base64.c diff --git a/spectro/base64.h b/spectro/base64.h index 726f20a..726f20a 100644..100755 --- a/spectro/base64.h +++ b/spectro/base64.h diff --git a/spectro/ccwin.c b/spectro/ccwin.c index 3c0d97f..1e9a18d 100644..100755 --- a/spectro/ccwin.c +++ b/spectro/ccwin.c @@ -15,18 +15,6 @@ #include <stdio.h> #include <string.h> -#ifdef NT -# include <winsock2.h> -#endif -#ifdef UNIX -# include <sys/types.h> -# include <ifaddrs.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# ifdef __FreeBSD__ -# include <sys/socket.h> -# endif /* __FreeBSD__ */ -#endif #include "copyright.h" #include "aconfig.h" #include "icc.h" @@ -59,23 +47,18 @@ //#define STANDALONE_TEST #ifdef DEBUG -#define errout stderr -# define debug(xx) fprintf(errout, xx ) -# define debug2(xx) fprintf xx -# define debugr(xx) fprintf(errout, xx ) -# define debugr2(xx) fprintf xx -# define debugrr(xx) fprintf(errout, xx ) -# define debugrr2(xx) fprintf xx -# define debugrr2l(lev, xx) fprintf xx +# pragma message("######### ccwin DEBUG is defined! ########") +#define errout g_log,0 +# define debug2(xx) a1logd xx +# define debugr2(xx) a1logd xx +# define debugrr2(xx) a1logd xx +# define debugrr2l(lev, xx) a1logd xx #else -#define errout stderr -# define debug(xx) -# define debug2(xx) -# define debugr(xx) if (p->ddebug) fprintf(errout, xx ) -# define debugr2(xx) if (p->ddebug) fprintf xx -# define debugrr(xx) if (callback_ddebug) fprintf(errout, xx ) -# define debugrr2(xx) if (callback_ddebug) fprintf xx -# define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx +#define errout g_log,0 +# define debug2(xx) // Debug, args +# define debugr2(xx) if (p->ddebug) a1logd xx // Run ->ddebug, args +# define debugrr2(xx) if (callback_ddebug) a1logd xx // Run cback, args +# define debugrr2l(lev, xx) if (callback_ddebug >= lev) a1logd xx // Run cback >= lev, args #endif /* ================================================================== */ @@ -93,13 +76,17 @@ typedef struct _chws { // double hoff, voff; /* Input position of test square */ double x, y; /* position of test square in pixels */ double w, h; /* size of test square in pixels */ + double bg[3]; /* Background color */ int pno; /* Index to generate a sequence of URLs */ unsigned char *ibuf; /* Memory image of .png file */ size_t ilen; ccast *cc; /* ChromeCast */ - /* Update the png image */ + /* Set a whole screen sized png image */ + int (*set)(struct _chws *p, unsigned char *ibuf, size_t ilen); + + /* Update the test patch png image */ int (*update)(struct _chws *p, unsigned char *ibuf, size_t ilen, double *bg); /* Destroy ourselves */ @@ -109,9 +96,11 @@ typedef struct _chws { static void chws_del(chws *p) { + /* delete mongoose, if we are using it */ if (p->mg != NULL) mg_stop(p->mg); + /* Delete ChromeCast */ if (p->cc != NULL) p->cc->del(p->cc); @@ -124,12 +113,62 @@ static void chws_del(chws *p) { free(p); } -/* Change the .png being served */ +/* Set a whole screen .png (size is assumed to be large enough) */ +/* Return nz on error */ +static int chws_set(chws *p, unsigned char *ibuf, size_t ilen) { + char url[200]; + double bg[3] = { 0.0, 0.0, 0.0 }; + + debug2((errout,"\nUpdate png\n")); + + if (p->ibuf != NULL) + free(p->ibuf); + + p->ibuf = ibuf; + p->ilen = ilen; + + /* Send the PNG swatch direct */ + if (p->direct) { + double x, y, w, h; + /* Convert x,y,w,h to relative rather than pixel size */ + + debugr2((errout,"Got x %f y %f w %f h %f\n", p->x, p->y, p->w, p->h)); + + // Convert from quantized to direct loader parameters + x = 0.0; + y = 0.0; + w = 10.0; /* Scale */ + h = 10.0 * 9.0/16.0; + + debugr2((errout,"Sending direct x %f y %f w %f h %f\n", x, y, w, h)); + + if (p->cc->load(p->cc, NULL, p->ibuf, p->ilen, bg, x, y, w, h)) { + debugr2((errout,"ccwin_set direct load failed\n")); + return 1; + } + + /* Using web server */ + } else { + +#ifdef SEND_TEST_FILE + sprintf(url, "%s%s",p->ws_url, SEND_TEST_FILE); +#else + sprintf(url, "%stpatch_%d.png",p->ws_url, ++p->pno); +#endif + if (p->cc->load(p->cc, url, NULL, 0, NULL, 0.0, 0.0, 0.0, 0.0)) { + debugr2((errout,"ccwin_set server load failed\n")); + return 1; + } + } + return 0; +} + +/* Change the test patch .png being served */ /* Return nz on error */ static int chws_update(chws *p, unsigned char *ibuf, size_t ilen, double *bg) { char url[200]; - debug("\nUpdate png\n"); + debug2((errout,"\nUpdate png\n")); if (p->ibuf != NULL) free(p->ibuf); @@ -230,6 +269,65 @@ static void *ccwin_ehandler(enum mg_event event, return "yes"; } +/* Change the patch display parameters. */ +/* Optional - may be NULL */ +static int ccwin_set_patch_win( +dispwin *p, +double hoff, double voff, /* Offset from c. in fraction of screen, -1.0 .. 1.0 */ +double area, /* Patch area 0..1 */ +dw_bg_type bge /* Background */ +) { + chws *ws = (chws *)p->pcntx; + double width, height; + + /* Set background color handling */ + p->fullscreen = 1; + p->bge = bge; + + if (area < 0.0) + area = 0.0; + else if (area > 1.0) + area = 1.0; + + /* Can't do constant luma/power with larger than 50% area */ + if (bge == dw_bg_cvideo + || bge == dw_bg_clight) { + if (area > 0.5) + area = 0.5; + } + + p->area = area; + + if (area < (IHEIGHT * IHEIGHT)/(IWIDTH * IHEIGHT)) { // Not height limited + width = height = sqrt(area * IWIDTH * IHEIGHT)/IWIDTH; + + } else { + height = IHEIGHT/IWIDTH; + width = area; + } + + /* Setup window size and position */ + /* The default size is 10% of the width */ + ws->w = floor(width * IWIDTH + 0.5); + if (ws->w > IWIDTH) + ws->w = IWIDTH; + ws->h = floor(height * IWIDTH + 0.5); + if (ws->h > IHEIGHT) + ws->h = IHEIGHT; + + ws->x = floor((hoff * 0.5 + 0.5) * (IWIDTH - ws->w) + 0.5); + ws->y = floor((voff * 0.5 + 0.5) * (IHEIGHT - ws->h) + 0.5); + + // Make offset be on an even pixel boundary, so that we know + // the up-filter phase. + if (((int)ws->x) & 1) + ws->x++; + if (((int)ws->y) & 1) + ws->y++; + + return 0; +} + chws *new_chws( ccast_id *cc_id, /* ChromeCast to open */ double width, double height, /* Width and height as % */ @@ -249,6 +347,7 @@ int verb, int ddebug) { p->verb = verb; p->ddebug = ddebug; + p->set = chws_set; p->update = chws_update; p->del = chws_del; @@ -265,10 +364,11 @@ int verb, int ddebug) { if (p->h > IHEIGHT) p->h = IHEIGHT; - // Make offset be on an even pixel boundary, so that we know - // the up-filter phase. p->x = floor((hoff * 0.5 + 0.5) * (IWIDTH - p->w) + 0.5); p->y = floor((voff * 0.5 + 0.5) * (IHEIGHT - p->h) + 0.5); + + // Make offset be on an even pixel boundary, so that we know + // the up-filter phase. if (((int)p->x) & 1) p->x++; if (((int)p->y) & 1) @@ -282,8 +382,7 @@ int verb, int ddebug) { /* Connect to the chrome cast */ if ((p->cc = new_ccast(cc_id, forcedef)) == NULL) { - error("new_ccast: failed"); - chws_del(p); + debugr2((errout,"new_chws: new_ccast() failed\n")); return NULL; } @@ -317,14 +416,14 @@ int verb, int ddebug) { /* Get RAMDAC values. ->del() when finished. */ /* Return NULL if not possible */ static ramdac *ccwin_get_ramdac(dispwin *p) { - debugr("webdisp doesn't have a RAMDAC\n"); + debugr2((errout,"webdisp doesn't have a RAMDAC\n")); return NULL; } /* Set the RAMDAC values. */ /* Return nz if not possible */ static int ccwin_set_ramdac(dispwin *p, ramdac *r, int persist) { - debugr("webdisp doesn't have a RAMDAC\n"); + debugr2((errout,"webdisp doesn't have a RAMDAC\n")); return 1; } @@ -333,21 +432,21 @@ static int ccwin_set_ramdac(dispwin *p, ramdac *r, int persist) { /* it the default for this display. */ /* Return nz if failed */ int ccwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) { - debugr("webdisp doesn't support installing profiles\n"); + debugr2((errout,"webdisp doesn't support installing profiles\n")); return 1; } /* Un-Install a display profile */ /* Return nz if failed, */ int ccwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) { - debugr("webdisp doesn't support uninstalling profiles\n"); + debugr2((errout,"webdisp doesn't support uninstalling profiles\n")); return 1; } /* Get the currently installed display profile. */ /* Return NULL if failed. */ icmFile *ccwin_get_profile(dispwin *p, char *name, int mxlen) { - debugr("webdisp doesn't support getting the current profile\n"); + debugr2((errout,"webdisp doesn't support getting the current profile\n")); return NULL; } @@ -355,6 +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 */ static int ccwin_set_color( dispwin *p, double r, double g, double b /* Color values 0.0 - 1.0 */ @@ -365,10 +465,10 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ double kr, kf; int update_delay = 0; - debugr("ccwin_set_color called\n"); + debugr2((errout, "ccwin_set_color called with %f %f %f\n",r,g,b)); if (p->nowin) { - debugr("ccwin_set_color: nowin - give up\n"); + debugr2((errout,"ccwin_set_color: nowin - give up\n")); return 1; } @@ -404,7 +504,7 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ { /* We want a raster of IWIDTH x IHEIGHT pixels for web server, */ /* or p->w x p->h for PNG direct. */ - render2d *r; + render2d *rr; prim2d *rct; depth2d depth = bpc8_2d; #if DDITHER == 1 @@ -418,10 +518,10 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ double hres = 1.0; /* Resoltion in pix/mm */ double vres = 1.0; /* Resoltion in pix/mm */ double iw, ih; /* Size of page in mm (pixels) */ - double bg[3]; /* Background color */ color2d c; unsigned char *ibuf; /* Memory image of .png file */ size_t ilen; + int rv; #ifdef DO_TIMING int stime; #endif @@ -434,42 +534,63 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ ih = IHEIGHT; /* Size of page in mm */ } - if (p->blackbg) { - bg[0] = 0.0; - bg[1] = 0.0; - bg[2] = 0.0; + /* Full screen background: */ + if (p->fullscreen) { + if (p->bge == dw_bg_grey) { + ws->bg[0] = 0.2; + ws->bg[1] = 0.2; + ws->bg[2] = 0.2; + } else if (p->bge == dw_bg_cvideo) { + ws->bg[0] = p->area * (1.0 - r)/(1.0 - p->area); + ws->bg[1] = p->area * (1.0 - g)/(1.0 - p->area); + ws->bg[2] = p->area * (1.0 - b)/(1.0 - p->area); + + } else if (p->bge == dw_bg_clight) { + double gamma = 2.3; + ws->bg[0] = pow(p->area * (1.0 - pow(r, gamma))/(1.0 - p->area), 1.0/gamma); + ws->bg[1] = pow(p->area * (1.0 - pow(g, gamma))/(1.0 - p->area), 1.0/gamma); + ws->bg[2] = pow(p->area * (1.0 - pow(b, gamma))/(1.0 - p->area), 1.0/gamma); + + } else { /* Assume dw_bg_black */ + ws->bg[0] = 0.0; + ws->bg[1] = 0.0; + ws->bg[2] = 0.0; + } + + /* Use default dark gray background */ } else { - bg[0] = 0.5; - bg[1] = 0.5; - bg[2] = 0.5; + ws->bg[0] = 0.2; + ws->bg[1] = 0.2; + ws->bg[2] = 0.2; } debugr2((errout, "ccwin_set_color iw %f ih %f\n",iw,ih)); - if ((r = new_render2d(iw, ih, NULL, hres, vres, rgb_2d, + if ((rr = new_render2d(iw, ih, NULL, hres, vres, rgb_2d, 0, depth, dither, #if DDITHER == 1 - ccastQuant, + ccastQuant, NULL, 3.0/255.0 #else - NULL, + NULL, NULL, 0.0 #endif - NULL)) == NULL) { - error("ccwin: new_render2d() failed"); + )) == NULL) { + a1loge(g_log, 1,"ccwin: new_render2d() failed\n"); + return 1; } /* Set the background color */ - c[0] = bg[0]; - c[1] = bg[1]; - c[2] = bg[2]; - r->set_defc(r, c); + c[0] = ws->bg[0]; + c[1] = ws->bg[1]; + c[2] = ws->bg[2]; + rr->set_defc(rr, c); c[0] = p->r_rgb[0]; c[1] = p->r_rgb[1]; c[2] = p->r_rgb[2]; if (ws->direct) - r->add(r, rct = new_rect2d(r, 0.0, 0.0, ws->w, ws->h, c)) ; + rr->add(rr, rct = new_rect2d(rr, 0.0, 0.0, ws->w, ws->h, c)); else - r->add(r, rct = new_rect2d(r, ws->x, ws->y, ws->w, ws->h, c)) ; + rr->add(rr, rct = new_rect2d(rr, ws->x, ws->y, ws->w, ws->h, c)); #if DDITHER == 2 /* Use dither pattern */ { @@ -483,8 +604,10 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ rgb[i] = p->r_rgb[i] * 255.0; get_ccast_dith(dpat, rgb); - if ((cpat = malloc(sizeof(double) * MXPATSIZE * MXPATSIZE * TOTC2D)) == NULL) - error("ccwin: malloc of dither pattern failed"); + if ((cpat = malloc(sizeof(double) * MXPATSIZE * MXPATSIZE * TOTC2D)) == NULL) { + a1loge(g_log, 1, "ccwin: malloc of dither pattern failed\n"); + return 1; + } for (i = 0; i < CCDITHSIZE; i++) { for (j = 0; j < CCDITHSIZE; j++) { @@ -503,35 +626,50 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ #pragma message("############################# ccwin.c TEST_PATTERN defined ! ##") if (getenv("ARGYLL_CCAST_TEST_PATTERN") != NULL) { verbose(0, "Writing test pattern to '%s'\n","testpattern.png"); - if (r->write(r, "testpattern.png", 1, NULL, NULL, png_file)) - error("ccwin: render->write failed"); + if (r->write(r, "testpattern.png", 1, NULL, NULL, png_file)) { + a1loge(g_log, 1, "ccwin: render->write failed\n"); + return 1; + } } #else /* !CCTEST_PATTERN */ # ifdef WRITE_PNG /* Write it to a file so that we can look at it */ # pragma message("############################# spectro/ccwin.c WRITE_PNG is enabled ######") - if (r->write(r, "ccwin.png", 1, NULL, NULL, png_file)) - error("ccwin: render->write failed"); + if (r->write(rr, "ccwin.png", 1, NULL, NULL, png_file)) { + a1loge(g_log, 1, "ccwin: render->write failed\n"); + return 1; + } # endif /* WRITE_PNG */ #endif /* !CCTEST_PATTERN */ + #ifdef DO_TIMING stime = msec_time(); #endif - if (r->write(r, "MemoryBuf", 1, &ibuf, &ilen, png_mem)) - error("ccwin: render->write failed"); + + rv = rr->write(rr, "MemoryBuf", 1, &ibuf, &ilen, png_mem); + + + if (rv) { + a1loge(g_log, 1, "ccwin: render->write failed\n"); + return 1; + } + rr->del(rr); #ifdef DO_TIMING stime = msec_time() - stime; printf("render->write took %d msec\n",stime); #endif - if (ws->update(ws, ibuf, ilen, bg)) - error("ccwin: color update failed"); + if (ws->update(ws, ibuf, ilen, ws->bg)) { + a1loge(g_log, 1, "ccwin: color update failed\n"); + return 1; + } p->ccix = p->ncix; } + /* If update is notified asyncronously ... */ -// while(p->ncix != p->ccix) { -// msec_sleep(50); -// } + while(p->ncix != p->ccix) { + msec_sleep(50); + } //printf("#################################################################\n"); //printf("################# RGB update notified ################\n"); //printf("#################################################################\n"); @@ -544,10 +682,10 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ return 0; } -/* Set/unset the blackground color flag */ +/* Set/unset the full screen background color flag */ /* Return nz on error */ -static int ccwin_set_bg(dispwin *p, int blackbg) { - p->blackbg = blackbg; +static int ccwin_set_fc(dispwin *p, int fullscreen) { + p->fullscreen = fullscreen; return 0; } @@ -571,7 +709,7 @@ dispwin *p ) { chws *ws; - debugr("ccwin_del called\n"); + debugr2((errout,"ccwin_del called with %p\n",p)); if (p == NULL) return; @@ -593,7 +731,7 @@ dispwin *p /* ----------------------------------------------- */ -/* Create a web display test window, default grey */ +/* Create a ChromeCast display test window, default grey */ dispwin *new_ccwin( ccast_id *cc_id, /* ChromeCast to open */ double width, double height, /* Width and height in mm. (TV width assumed to b 1000mm) */ @@ -606,7 +744,8 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ +int noinitpatch, /* NZ if no initial test patch should be shown */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ) { @@ -615,10 +754,10 @@ int ddebug /* >0 to print debug statements to stderr */ chws *ws = NULL; const char *options[3]; - debug("new_ccwin called\n"); + debug2((errout,"new_ccwin called\n")); if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) { - if (ddebug) fprintf(stderr,"new_ccwin failed because malloc failed\n"); + debugr2((errout,"new_ccwin failed because malloc failed\n")); return NULL; } @@ -629,7 +768,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->nowin = nowin; p->native = native; p->out_tvenc = out_tvenc; - p->blackbg = blackbg; + p->fullscreen = fullscreen; p->ddebug = ddebug; p->get_ramdac = ccwin_get_ramdac; p->set_ramdac = ccwin_set_ramdac; @@ -637,7 +776,8 @@ int ddebug /* >0 to print debug statements to stderr */ p->uninstall_profile = ccwin_uninstall_profile; p->get_profile = ccwin_get_profile; p->set_color = ccwin_set_color; - p->set_bg = ccwin_set_bg; + p->set_fc = ccwin_set_fc; + p->set_patch_win = ccwin_set_patch_win; p->set_update_delay = dispwin_set_update_delay; p->set_settling_delay = dispwin_set_settling_delay; p->enable_update_delay = dispwin_enable_update_delay; @@ -663,7 +803,8 @@ int ddebug /* >0 to print debug statements to stderr */ /* Basic object is initialised, so create connection to ChromeCast */ if ((ws = new_chws(cc_id, width, height, hoff, voff, verb, ddebug)) == NULL) { - if (ddebug) fprintf(stderr,"new_ccwin failed - new_chws() failed\n"); + debugr2((errout,"new_ccwin failed - new_chws() failed\n")); + p->del(p); return NULL; } @@ -680,13 +821,13 @@ int ddebug /* >0 to print debug statements to stderr */ } // Set a default first color - if (ccwin_set_color(p, 128.0, 128.0, 128.0)) { - if (ddebug) fprintf(stderr,"new_ccwin set_color()\n"); + if (!noinitpatch && ccwin_set_color(p, 128.0, 128.0, 128.0)) { + debugr2((errout,"new_ccwin failed because set_color() failed\n")); p->del(p); return NULL; } - debugr("new_ccwin: return sucessfully\n"); + debugr2((errout,"new_ccwin: return sucessfully\n")); return p; } diff --git a/spectro/ccwin.h b/spectro/ccwin.h index 4d32466..9fb902d 100644..100755 --- a/spectro/ccwin.h +++ b/spectro/ccwin.h @@ -31,7 +31,8 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ +int noinitpatch, /* NZ if no initial test patch should be shown */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ); diff --git a/spectro/ccxx.ti1 b/spectro/ccxx.ti1 index 47f2b13..47f2b13 100644..100755 --- a/spectro/ccxx.ti1 +++ b/spectro/ccxx.ti1 diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c index 2df2e5f..4202c67 100644..100755 --- a/spectro/ccxxmake.c +++ b/spectro/ccxxmake.c @@ -119,7 +119,7 @@ usage(int flag, char *diag, ...) { fprintf(stderr,"usage: ccmxmake -t dtech [-options] output.ccmx\n"); fprintf(stderr," -v Verbose mode\n"); fprintf(stderr," -S Create CCSS rather than CCMX\n"); - fprintf(stderr," -f file1.ti3[,file2.ti3] Create from one or two .ti3 files rather than measure.\n"); + fprintf(stderr," -f ref.ti3[,targ.ti3] Create from one or two .ti3 files rather than measure.\n"); #if defined(UNIX_X11) fprintf(stderr," -display displayname Choose X11 display name\n"); fprintf(stderr," -d n[,m] Choose the display n from the following list (default 1)\n"); @@ -210,7 +210,7 @@ int main(int argc, char *argv[]) { disppath *disp = NULL; /* Display being used */ double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */ - int blackbg = 0; /* NZ if whole screen should be filled with black */ + int fullscreen = 0; /* NZ if whole screen should be filled with black */ int verb = 0; int debug = 0; int doccss = 0; /* Create CCSS rather than CCMX */ @@ -441,9 +441,9 @@ int main(int argc, char *argv[]) { ho = 2.0 * ho - 1.0; vo = 2.0 * vo - 1.0; - /* Black background */ + /* Full screen black background */ } else if (argv[fa][1] == 'F') { - blackbg = 1; + fullscreen = 1; /* No initial calibration */ } else if (argv[fa][1] == 'N') { @@ -651,6 +651,9 @@ int main(int argc, char *argv[]) { if ((spi[j] = cgf->find_field(cgf, 0, buf)) < 0) error("Input file '%s' doesn't contain field %s",innames[0],buf); + + if (cgf->t[0].ftype[spi[j]] != r_t) + error("Field %s is wrong type - expect float",buf); } /* Transfer all the spectral values */ @@ -698,7 +701,7 @@ int main(int argc, char *argv[]) { error("new_ccss() failed"); if (cc->set_ccss(cc, "Argyll ccxxmake", NULL, description, displayname, - dtinfo->dtech, refrmode, uisel, refname, samples, npat)) { + dtinfo->dtech, refrmode, uisel, refname, 0, samples, npat)) { error("set_ccss failed with '%s'\n",cc->err); } if(cc->write_ccss(cc, outname)) @@ -890,29 +893,29 @@ int main(int argc, char *argv[]) { if ((xix = cgf->find_field(cgf, 0, "LAB_L")) < 0) error("Input file '%s' doesn't contain field LAB_L",innames[n]); if (cgf->t[0].ftype[xix] != r_t) - error("Field LAB_L is wrong type"); + error("Field LAB_L is wrong type - expect float"); if ((yix = cgf->find_field(cgf, 0, "LAB_A")) < 0) error("Input file '%s' doesn't contain field LAB_A",innames[n]); if (cgf->t[0].ftype[yix] != r_t) - error("Field LAB_A is wrong type"); + error("Field LAB_A is wrong type - expect float"); if ((zix = cgf->find_field(cgf, 0, "LAB_B")) < 0) error("Input file '%s' doesn't contain field LAB_B",innames[n]); if (cgf->t[0].ftype[zix] != r_t) - error("Field LAB_B is wrong type"); + error("Field LAB_B is wrong type - expect float"); } else { /* Expect XYZ */ if ((xix = cgf->find_field(cgf, 0, "XYZ_X")) < 0) error("Input file '%s' doesn't contain field XYZ_X",innames[n]); if (cgf->t[0].ftype[xix] != r_t) - error("Field XYZ_X is wrong type"); + error("Field XYZ_X is wrong type - expect float"); if ((yix = cgf->find_field(cgf, 0, "XYZ_Y")) < 0) error("Input file '%s' doesn't contain field XYZ_Y",innames[n]); if (cgf->t[0].ftype[yix] != r_t) - error("Field XYZ_Y is wrong type"); + error("Field XYZ_Y is wrong type - expect float"); if ((zix = cgf->find_field(cgf, 0, "XYZ_Z")) < 0) error("Input file '%s' doesn't contain field XYZ_Z",innames[n]); if (cgf->t[0].ftype[zix] != r_t) - error("Field XYZ_Z is wrong type"); + error("Field XYZ_Z is wrong type - expect float"); } for (i = 0; i < npat; i++) { @@ -964,7 +967,7 @@ int main(int argc, char *argv[]) { error("new_ccmx() failed"); if (cc->create_ccmx(cc, description, colname, displayname, dtinfo->dtech, - refrmode, cbid, uisel, refname, npat, refs, cols)) { + refrmode, cbid, uisel, refname, 0, npat, refs, cols)) { error("create_ccmx failed with '%s'\n",cc->err); } if (verb) { @@ -1246,12 +1249,12 @@ int main(int argc, char *argv[]) { if ((dr = new_disprd(&errc, icmps->get_path(icmps, comno), fc, dtype, sdtype, 1, tele, nadaptive, noinitcal, 0, highres, refrate, 3, NULL, NULL, - NULL, 0, disp, 0, blackbg, + NULL, 0, disp, 0, fullscreen, override, webdisp, ccid, #ifdef NT madvrdisp, #endif - ccallout, NULL, + ccallout, NULL, 0, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, disptech_unknown, 0, NULL, NULL, 0, 2, icxOT_default, NULL, 0, 0, "fake" ICC_FILE_EXT, g_log)) == NULL) { @@ -1396,7 +1399,7 @@ int main(int argc, char *argv[]) { error("new_ccss() failed"); if (cc->set_ccss(cc, "Argyll ccxxmake", NULL, description, displayname, - dtinfo->dtech, refrmode, NULL, refname, samples, npat)) { + dtinfo->dtech, refrmode, NULL, refname, 0, samples, npat)) { error("set_ccss failed with '%s'\n",cc->err); } if(cc->write_ccss(cc, outname)) @@ -1451,7 +1454,7 @@ int main(int argc, char *argv[]) { error("new_ccmx() failed"); if (cc->create_ccmx(cc, description, colname, displayname, dtinfo->dtech, - refrmode, cbid, uisel, refname, npat, refs, cols)) { + refrmode, cbid, uisel, refname, 0, npat, refs, cols)) { error("create_ccmx failed with '%s'\n",cc->err); } if (verb) { diff --git a/spectro/chartread.c b/spectro/chartread.c index cfbeee6..0fc7646 100644..100755 --- a/spectro/chartread.c +++ b/spectro/chartread.c @@ -218,6 +218,7 @@ icxObserverType obType, /* ccss observer */ double scan_tol, /* Modify patch consistency tolerance */ int pbypatch, /* Patch by patch measurement */ int xtern, /* Use external (user supplied) values rather than instument read */ + /* 1 = Lab, 2 = XYZ */ int spectral, /* Generate spectral info flag */ int uvmode, /* ~~~ i1pro2 test mode ~~~ */ int accurate_expd, /* Expected values can be assumed to be accurate */ @@ -321,7 +322,7 @@ a1log *log /* verb, debug & error log */ } } - /* Set display type */ + /* Set display type or calibration mode */ if (dtype != 0) { if (cap2 & inst2_disptype) { @@ -1746,7 +1747,7 @@ a1log *log /* verb, debug & error log */ empty_con_chars(); printf("\nReady to read patch '%s'%s\n",scols[pix]->loc, - i >= npat ? "(All patches read!)" : + i >= npat ? " (All patches read!)" : strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" : scols[pix]->rr ? " (Already read)" : ""); @@ -2563,7 +2564,7 @@ int main(int argc, char *argv[]) { if ((ii = icg->find_field(icg, 0, fname)) < 0) error ("Input file doesn't contain field %s",fname); if (icg->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",fname); + error ("Field %s is wrong type - expect float",fname); ocg->add_field(ocg, 0, fname, r_t); chix[j] = ii; @@ -2573,7 +2574,7 @@ int main(int argc, char *argv[]) { for (j = 0; j < 3; j++) { if ((ii = icg->find_field(icg, 0, xyzfname[j])) >= 0) { if (icg->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",xyzfname[j]); + error ("Field %s is wrong type - expect float",xyzfname[j]); xyzix[j] = ii; } else { gotexyz = 0; @@ -2765,6 +2766,9 @@ int main(int argc, char *argv[]) { if ((spi[j] = rcg->find_field(rcg, 0, buf)) < 0) error("Resumed file '%s' doesn't contain field %s",outname,buf); + + if (rcg->t[0].ftype[spi[j]] != r_t) + error("Field %s is wrong type - expect float",buf); } } diff --git a/spectro/colorhug.c b/spectro/colorhug.c index 76e5bfb..1b2a56d 100644..100755 --- a/spectro/colorhug.c +++ b/spectro/colorhug.c @@ -1213,7 +1213,7 @@ extern colorhug *new_colorhug(icoms *icom, instType itype) { p->del = colorhug_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; if (itype == instColorHug2) p->stype = ch_two; diff --git a/spectro/colorhug.h b/spectro/colorhug.h index 90fff6f..90fff6f 100644..100755 --- a/spectro/colorhug.h +++ b/spectro/colorhug.h diff --git a/spectro/conv.c b/spectro/conv.c index c0137ce..1f4d102 100644..100755 --- a/spectro/conv.c +++ b/spectro/conv.c @@ -131,6 +131,10 @@ int next_con_char(void) { } /* 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 - */ +/* trying to do this manually typically doesn't work unless you are */ +/* very fast an lucky. */ static int th_read_char(void *pp) { char *rp = (char *)pp; HANDLE stdinh; @@ -1581,32 +1585,4 @@ int sa_lu_psinvert(double **out, double **in, int m, int n) { #endif /* SALONEINSTLIB */ /* ============================================================= */ -/* Diagnostic aids */ - -// Print bytes as hex to debug log */ -void adump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len) { - int i, j, ii; - char oline[200] = { '\000' }, *bp = oline; - for (i = j = 0; i < len; i++) { - if ((i % 16) == 0) - bp += sprintf(bp,"%s%04x:",pfx,base+i); - bp += sprintf(bp," %02x",buf[i]); - if ((i+1) >= len || ((i+1) % 16) == 0) { - for (ii = i; ((ii+1) % 16) != 0; ii++) - bp += sprintf(bp," "); - bp += sprintf(bp," "); - for (; j <= i; j++) { - if (!(buf[j] & 0x80) && isprint(buf[j])) - bp += sprintf(bp,"%c",buf[j]); - else - bp += sprintf(bp,"."); - } - bp += sprintf(bp,"\n"); - a1logd(log,0,"%s",oline); - bp = oline; - } - } -} - - diff --git a/spectro/conv.h b/spectro/conv.h index 7a7baca..4e14dd9 100644..100755 --- a/spectro/conv.h +++ b/spectro/conv.h @@ -266,12 +266,6 @@ int sa_lu_psinvert(double **out, double **in, int m, int n); #endif /* SALONEINSTLIB */ /* - - - - - - - - - - - - - - - - - - -- */ -/* Diagnostic aids */ - -// Print bytes as hex to debug log */ -void adump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len); - -/* - - - - - - - - - - - - - - - - - - -- */ #ifdef __cplusplus diff --git a/spectro/cubecal.h b/spectro/cubecal.h new file mode 100755 index 0000000..60f7380 --- /dev/null +++ b/spectro/cubecal.h @@ -0,0 +1,5554 @@ + +/* + * Calibration Table for SwatchMate Cube + * + * Copyright 2015 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. + * + * This calibration is for a Cube with LED wavlengths 630.0 530.0 460.0 nm + * + */ + +typedef struct { + int res; + float dpow; + int islab; + float table[17][17][17][3]; +} cube_clut; + +cube_clut clut = { + 17, + 0.560000, + 1, + { + { + { + { 0.000000, 0.000000, 0.000000 }, + { -3.108725, 6.379437, -16.262457 }, + { -3.513774, 12.119589, -30.739702 }, + { -2.115353, 17.935534, -41.855820 }, + { -0.010341, 24.314871, -50.902515 }, + { 1.854175, 31.610882, -59.665554 }, + { 3.449414, 39.690384, -68.404831 }, + { 4.988287, 47.418373, -76.619690 }, + { 6.660570, 53.383759, -83.814575 }, + { 8.526612, 57.535027, -90.003593 }, + { 10.574578, 60.238720, -95.427658 }, + { 12.685945, 62.268253, -100.538567 }, + { 14.754425, 64.383377, -105.725388 }, + { 16.737513, 66.922600, -111.162636 }, + { 18.639080, 69.858894, -116.850212 }, + { 20.484802, 73.024666, -122.704948 }, + { 22.306879, 76.269745, -128.628067 } + }, + { + { 4.234821, -19.241503, 11.292808 }, + { 2.843881, -13.871078, -6.200700 }, + { 2.827496, -7.748870, -22.260107 }, + { 3.952048, -1.440168, -33.601727 }, + { 5.672034, 5.117609, -42.689331 }, + { 7.361498, 11.773417, -51.513256 }, + { 9.100790, 18.863472, -59.675938 }, + { 10.697422, 26.752626, -67.525803 }, + { 12.227798, 32.830032, -74.627243 }, + { 13.716241, 37.288288, -81.072021 }, + { 15.297711, 40.708969, -86.998367 }, + { 16.991249, 44.180187, -92.798790 }, + { 18.763279, 48.119270, -98.691429 }, + { 20.576683, 52.399059, -104.699463 }, + { 22.403513, 56.800434, -110.775215 }, + { 24.236834, 61.223938, -116.874222 }, + { 26.075523, 65.651451, -122.975830 } + }, + { + { 10.640698, -37.914284, 21.981108 }, + { 9.888870, -33.497070, 4.419587 }, + { 9.632989, -27.494251, -11.957022 }, + { 10.227860, -20.078138, -25.040745 }, + { 11.195958, -12.701514, -35.623631 }, + { 12.744726, -6.568381, -44.244148 }, + { 14.799405, -0.984663, -51.357300 }, + { 16.581852, 5.544156, -58.274593 }, + { 17.951008, 12.551022, -65.364006 }, + { 19.114931, 17.187794, -71.947189 }, + { 20.164137, 21.516897, -78.497963 }, + { 21.407064, 26.724361, -85.085754 }, + { 22.878307, 32.437378, -91.678307 }, + { 24.505775, 38.226738, -98.215355 }, + { 26.228365, 43.882099, -104.651878 }, + { 28.021624, 49.423836, -110.978996 }, + { 29.852308, 54.926193, -117.244186 } + }, + { + { 17.840609, -54.014400, 31.482065 }, + { 17.239162, -49.899727, 14.727889 }, + { 16.713871, -44.337044, -1.582370 }, + { 16.983976, -37.032753, -15.767160 }, + { 17.277546, -29.690071, -27.638208 }, + { 18.434795, -22.976774, -36.755417 }, + { 20.241308, -16.644985, -43.990032 }, + { 21.888008, -11.439743, -50.310852 }, + { 23.389778, -4.672492, -57.037277 }, + { 24.390499, -1.550237, -63.394146 }, + { 25.049068, 3.946567, -70.458015 }, + { 25.954910, 10.981771, -77.681068 }, + { 27.184675, 18.032602, -84.781555 }, + { 28.595022, 24.752199, -91.705009 }, + { 30.166162, 31.248569, -98.424278 }, + { 31.870760, 37.613705, -104.930702 }, + { 33.633942, 43.899342, -111.315231 } + }, + { + { 24.523094, -66.826271, 39.123337 }, + { 24.155392, -62.930618, 23.907663 }, + { 23.385942, -58.392117, 8.178281 }, + { 23.499163, -52.274418, -5.687166 }, + { 24.152292, -45.770733, -17.248781 }, + { 25.308041, -38.504848, -26.531488 }, + { 26.092649, -29.958961, -35.283051 }, + { 27.132149, -25.425463, -42.373322 }, + { 28.260490, -21.008181, -49.500965 }, + { 29.064190, -18.958935, -55.951431 }, + { 29.684616, -10.219873, -63.695320 }, + { 30.512142, -2.169182, -71.004639 }, + { 31.619951, 5.171085, -78.145775 }, + { 32.792465, 12.050668, -85.208824 }, + { 34.217468, 18.978827, -92.060959 }, + { 35.788540, 25.757549, -98.651100 }, + { 37.384262, 32.303059, -105.080009 } + }, + { + { 30.245825, -77.505936, 44.899803 }, + { 29.945150, -74.127945, 30.956144 }, + { 29.422693, -70.561089, 16.842474 }, + { 29.867500, -64.914642, 4.572066 }, + { 31.462145, -58.134586, -5.249294 }, + { 33.357727, -50.895237, -13.638721 }, + { 33.089081, -39.280712, -24.553354 }, + { 33.019260, -33.548992, -34.143417 }, + { 33.317039, -32.300022, -42.273518 }, + { 33.573269, -31.657618, -49.453796 }, + { 34.065811, -19.613224, -58.254604 }, + { 34.934368, -13.305716, -64.859550 }, + { 35.844479, -6.896156, -71.776550 }, + { 36.957993, -0.002162, -78.787140 }, + { 38.346428, 7.100326, -85.557175 }, + { 39.720154, 13.719435, -92.097511 }, + { 41.025173, 19.866701, -98.500572 } + }, + { + { 35.235012, -86.441414, 49.726543 }, + { 34.758579, -85.026138, 36.455482 }, + { 34.462742, -82.534927, 23.675982 }, + { 35.611725, -75.017761, 13.446783 }, + { 37.702091, -65.528801, 5.167120 }, + { 40.179146, -54.286797, -2.609262 }, + { 40.901623, -44.071568, -12.577824 }, + { 40.139965, -41.447945, -22.765736 }, + { 39.066429, -44.586857, -32.310959 }, + { 38.215954, -43.197380, -42.328728 }, + { 38.405800, -30.678701, -52.029255 }, + { 39.270744, -23.080603, -59.145893 }, + { 39.820694, -18.002005, -65.778786 }, + { 41.184551, -11.119964, -72.449829 }, + { 42.477837, -4.495872, -78.928993 }, + { 43.501858, 1.116444, -85.279678 }, + { 44.489861, 6.571913, -91.668831 } + }, + { + { 39.958138, -93.179825, 54.704079 }, + { 39.555668, -93.157700, 42.108181 }, + { 39.214561, -92.018959, 29.819813 }, + { 40.364056, -83.579498, 20.198338 }, + { 42.055130, -73.175941, 12.419911 }, + { 45.573200, -59.653439, 5.937179 }, + { 47.942894, -49.991074, -1.680336 }, + { 48.170784, -46.276493, -11.122963 }, + { 45.713558, -49.093582, -23.128136 }, + { 43.032284, -48.764896, -36.073044 }, + { 42.848442, -40.468571, -45.971424 }, + { 43.794662, -32.508579, -53.292789 }, + { 44.814892, -26.621048, -59.638981 }, + { 45.709064, -21.018253, -66.044327 }, + { 46.319767, -16.250605, -72.321960 }, + { 46.946510, -12.385717, -78.291138 }, + { 47.852665, -6.934625, -84.808495 } + }, + { + { 44.629810, -97.512657, 60.343151 }, + { 44.495537, -97.860184, 48.383362 }, + { 44.423790, -96.815140, 36.808792 }, + { 44.905434, -90.878922, 26.749361 }, + { 46.081753, -81.581528, 18.502306 }, + { 47.897537, -73.804169, 10.768237 }, + { 49.712009, -66.343132, 2.913184 }, + { 51.391113, -57.542595, -5.912806 }, + { 50.904179, -53.260086, -16.853422 }, + { 47.826492, -52.822918, -29.804100 }, + { 46.345203, -48.492229, -40.639957 }, + { 48.398746, -41.844818, -46.582294 }, + { 50.077869, -35.219254, -52.237839 }, + { 49.625580, -30.934124, -59.463520 }, + { 49.808678, -28.108028, -65.701012 }, + { 50.442028, -25.044247, -71.418922 }, + { 51.356403, -19.369282, -78.134308 } + }, + { + { 49.270729, -99.759590, 66.688675 }, + { 49.337383, -100.308464, 55.103058 }, + { 49.428707, -99.807571, 43.756931 }, + { 49.838558, -95.655418, 33.235252 }, + { 50.703857, -88.109573, 24.046219 }, + { 50.950581, -86.008919, 15.020423 }, + { 51.044769, -82.859673, 5.777906 }, + { 52.370487, -72.516121, -2.969076 }, + { 54.230980, -62.567928, -11.389186 }, + { 53.761917, -57.989693, -21.253706 }, + { 52.653187, -53.524620, -31.124254 }, + { 54.125965, -47.007568, -37.658783 }, + { 54.943760, -42.044025, -43.944542 }, + { 54.719326, -39.561131, -50.772568 }, + { 54.593254, -37.591316, -57.665367 }, + { 54.861210, -34.177044, -64.452827 }, + { 55.230713, -29.885284, -71.424011 } + }, + { + { 53.749859, -101.007339, 73.324669 }, + { 54.037182, -101.500282, 61.988304 }, + { 54.351585, -101.485573, 50.763695 }, + { 54.728493, -100.275581, 39.571770 }, + { 55.182110, -97.096970, 28.963995 }, + { 55.612743, -93.981888, 20.119753 }, + { 55.534679, -89.943001, 11.638604 }, + { 56.984486, -80.488998, 4.237844 }, + { 59.775852, -67.887016, -2.702181 }, + { 60.846546, -58.743637, -10.944484 }, + { 60.257290, -52.556461, -19.970139 }, + { 59.879021, -47.652100, -27.901505 }, + { 59.704334, -45.628235, -34.953999 }, + { 60.177921, -45.100357, -41.311794 }, + { 60.064106, -44.065216, -48.531544 }, + { 59.917400, -41.407433, -56.159145 }, + { 59.860271, -38.118248, -63.809296 } + }, + { + { 57.959553, -102.546158, 79.702118 }, + { 58.467693, -103.093224, 68.435059 }, + { 59.052544, -103.585632, 57.205406 }, + { 59.614182, -104.189972, 45.818848 }, + { 59.676968, -105.192863, 34.029060 }, + { 59.924614, -101.542435, 24.995707 }, + { 60.108082, -95.345459, 17.530905 }, + { 61.442051, -85.966286, 10.957516 }, + { 64.263809, -72.848038, 5.029232 }, + { 66.800751, -60.241428, -1.336677 }, + { 67.511726, -52.286400, -8.862195 }, + { 67.081146, -48.533459, -16.744081 }, + { 66.224373, -47.949566, -24.555666 }, + { 65.538208, -48.899300, -32.113544 }, + { 65.567955, -48.106628, -39.325703 }, + { 65.502762, -46.144470, -47.025230 }, + { 65.350967, -43.767235, -55.044312 } + }, + { + { 61.895813, -105.321358, 85.412849 }, + { 62.516296, -106.177589, 74.107948 }, + { 63.178932, -107.293785, 62.723862 }, + { 63.767868, -108.630531, 51.311371 }, + { 64.098648, -109.043663, 40.378693 }, + { 64.414215, -105.720825, 31.327908 }, + { 64.761299, -99.257347, 23.988560 }, + { 65.764763, -90.388802, 17.513399 }, + { 68.571144, -76.901031, 12.216690 }, + { 71.551918, -63.674194, 6.957545 }, + { 72.788559, -55.732986, 0.336008 }, + { 72.672279, -52.393192, -7.323466 }, + { 72.037094, -51.219807, -15.259692 }, + { 71.400864, -50.899494, -23.046545 }, + { 71.332153, -50.024654, -30.363155 }, + { 71.474503, -48.580414, -37.788166 }, + { 71.327637, -47.099865, -45.686085 } + }, + { + { 65.598488, -109.693581, 90.303467 }, + { 66.294830, -110.335930, 79.263634 }, + { 67.013908, -111.152596, 68.204987 }, + { 67.703514, -111.816353, 57.345287 }, + { 68.293015, -111.143593, 47.252151 }, + { 68.862648, -107.791237, 38.435230 }, + { 69.651482, -101.074799, 31.149630 }, + { 71.128685, -91.379051, 24.969904 }, + { 73.456062, -79.259766, 19.580812 }, + { 75.713127, -68.222137, 14.215412 }, + { 76.748306, -61.720993, 7.848460 }, + { 76.764755, -58.632881, 0.344270 }, + { 76.856544, -55.937836, -7.337325 }, + { 77.160217, -53.299274, -14.535153 }, + { 77.230278, -51.371181, -21.751291 }, + { 77.391808, -49.948524, -28.912670 }, + { 77.257851, -48.938850, -36.447983 } + }, + { + { 69.138222, -115.407463, 94.530319 }, + { 69.959679, -114.994591, 84.179970 }, + { 70.797920, -114.599388, 73.895081 }, + { 71.641388, -113.936798, 63.835060 }, + { 72.479919, -112.139946, 54.427727 }, + { 73.405617, -108.114395, 46.073639 }, + { 74.657585, -101.248184, 38.904060 }, + { 76.375427, -92.013535, 32.660847 }, + { 78.273735, -81.927620, 26.830244 }, + { 79.643272, -73.650864, 20.762907 }, + { 80.095856, -68.746277, 13.996282 }, + { 80.237488, -65.328606, 6.593365 }, + { 80.829597, -61.168301, -0.847144 }, + { 81.967155, -56.674473, -7.359741 }, + { 82.741562, -53.372719, -13.773818 }, + { 82.948288, -51.470921, -20.592533 }, + { 82.850342, -50.285915, -27.703110 } + }, + { + { 72.591682, -121.923248, 98.382576 }, + { 73.593880, -119.906700, 88.960213 }, + { 74.603554, -117.826050, 79.632339 }, + { 75.632095, -115.451370, 70.543335 }, + { 76.720016, -112.245041, 61.945644 }, + { 77.956146, -107.561996, 54.052269 }, + { 79.407364, -101.229942, 46.834183 }, + { 80.923347, -93.843704, 40.059162 }, + { 82.208199, -86.485527, 33.375301 }, + { 83.020081, -80.255562, 26.494286 }, + { 83.393234, -75.393074, 19.325455 }, + { 83.745392, -70.887688, 11.981798 }, + { 84.426193, -65.981232, 4.849656 }, + { 86.235596, -60.403255, -0.857586 }, + { 87.477249, -56.231133, -6.660480 }, + { 87.960991, -53.619331, -12.939464 }, + { 88.118187, -51.753475, -19.465408 } + }, + { + { 76.015961, -128.743332, 102.099846 }, + { 77.222733, -124.923180, 93.688072 }, + { 78.426880, -120.974251, 85.391876 }, + { 79.659309, -116.711052, 77.348976 }, + { 80.990257, -111.981232, 69.624046 }, + { 82.451942, -106.808617, 62.145725 }, + { 83.891411, -101.533310, 54.721294 }, + { 84.959831, -96.684952, 47.167572 }, + { 85.535416, -92.302246, 39.441597 }, + { 85.935226, -87.629555, 31.732239 }, + { 86.558685, -82.017166, 24.319881 }, + { 87.481041, -75.890518, 17.362139 }, + { 88.740135, -69.898308, 11.060918 }, + { 90.419434, -64.218529, 5.507547 }, + { 91.805351, -59.621750, 0.013592 }, + { 92.643288, -56.218506, -5.691527 }, + { 93.189407, -53.454399, -11.539556 } + } + }, + { + { + { -0.109722, 12.964268, 4.516390 }, + { -0.660951, 18.041716, -11.918370 }, + { 0.003791, 22.950363, -27.032158 }, + { 1.403321, 28.049053, -38.866135 }, + { 2.971407, 33.518665, -48.958076 }, + { 4.291079, 39.762562, -58.772896 }, + { 5.646095, 46.137688, -67.681908 }, + { 7.274704, 51.939293, -74.893654 }, + { 9.175462, 56.472900, -80.800064 }, + { 11.259534, 60.080914, -86.050377 }, + { 13.445276, 62.959408, -91.019852 }, + { 15.543013, 65.496269, -96.086884 }, + { 17.465246, 68.010544, -101.434532 }, + { 19.224691, 70.592606, -107.071106 }, + { 20.874966, 73.205833, -112.907555 }, + { 22.471581, 75.813858, -118.839966 }, + { 24.052408, 78.412941, -124.799286 } + }, + { + { 6.727361, -4.663532, 17.602961 }, + { 6.448769, -0.386471, -0.161296 }, + { 6.582062, 5.398698, -18.839003 }, + { 7.765986, 10.174873, -30.236370 }, + { 9.299706, 15.462027, -39.349197 }, + { 10.179111, 21.265503, -49.232906 }, + { 11.351582, 26.229401, -57.799107 }, + { 12.637918, 31.964056, -65.316002 }, + { 14.254212, 37.069191, -71.860504 }, + { 15.845289, 42.339211, -78.106773 }, + { 17.692101, 45.783108, -83.596008 }, + { 19.456791, 49.311340, -89.289185 }, + { 21.127934, 53.087559, -95.247589 }, + { 22.767759, 56.765354, -101.260284 }, + { 24.410303, 60.317146, -107.236206 }, + { 26.067160, 63.855080, -113.180855 }, + { 27.734791, 67.423645, -119.116615 } + }, + { + { 14.152776, -21.465309, 29.291939 }, + { 13.953787, -18.502064, 12.135889 }, + { 13.431262, -15.198259, -6.332568 }, + { 13.720811, -7.956450, -21.397753 }, + { 14.754900, -0.191718, -32.763718 }, + { 15.762719, 3.656883, -41.039291 }, + { 17.077890, 6.374919, -48.146095 }, + { 18.095776, 9.619523, -55.350586 }, + { 19.449051, 16.296291, -62.782795 }, + { 20.736963, 23.167822, -69.657776 }, + { 21.976349, 28.129045, -76.072792 }, + { 23.347792, 33.280758, -82.546509 }, + { 24.800255, 38.308910, -89.086266 }, + { 26.344727, 42.966049, -95.414513 }, + { 27.983362, 47.424789, -101.503319 }, + { 29.692310, 51.907467, -107.465797 }, + { 31.432634, 56.457760, -113.395195 } + }, + { + { 21.270660, -36.292389, 38.919945 }, + { 21.016575, -33.381729, 22.203236 }, + { 20.238115, -30.629267, 4.818551 }, + { 19.120800, -25.013151, -12.603518 }, + { 18.984547, -16.175421, -26.927734 }, + { 19.989426, -10.840259, -35.730373 }, + { 22.304512, -8.846658, -41.007481 }, + { 23.467249, -7.326241, -47.191299 }, + { 24.429728, 0.189621, -55.007816 }, + { 25.352819, 5.999861, -62.085197 }, + { 26.242043, 12.090010, -69.035919 }, + { 27.335072, 18.170822, -75.944267 }, + { 28.588709, 23.825348, -82.863823 }, + { 30.039783, 29.255419, -89.422386 }, + { 31.660833, 34.633133, -95.626015 }, + { 33.388287, 40.051426, -101.636810 }, + { 35.146011, 45.484661, -107.586769 } + }, + { + { 27.545839, -48.871937, 46.338982 }, + { 26.898664, -45.666077, 30.167574 }, + { 25.458376, -43.679428, 13.034832 }, + { 25.289818, -39.786076, -2.052759 }, + { 24.949835, -34.862461, -16.536722 }, + { 25.280588, -27.313738, -27.964441 }, + { 26.894756, -20.516470, -35.373688 }, + { 28.177526, -17.190155, -41.813789 }, + { 28.946136, -13.411076, -48.748680 }, + { 29.929111, -10.218981, -55.002426 }, + { 30.832394, -2.945107, -62.046577 }, + { 31.552807, 3.647907, -69.314583 }, + { 32.595730, 9.699430, -76.433617 }, + { 33.931698, 15.902310, -83.197861 }, + { 35.515831, 22.263783, -89.573074 }, + { 37.191975, 28.443512, -95.668488 }, + { 38.839813, 34.345196, -101.642899 } + }, + { + { 32.824162, -59.902714, 51.764248 }, + { 32.316071, -56.329464, 37.105709 }, + { 31.785854, -53.159557, 22.594913 }, + { 31.956902, -50.697521, 9.062675 }, + { 31.638990, -47.666862, -4.450498 }, + { 31.657951, -40.266228, -16.832432 }, + { 31.585718, -31.178511, -27.786552 }, + { 31.798576, -27.714243, -36.478394 }, + { 33.255405, -26.615278, -42.475090 }, + { 34.677929, -23.363750, -48.271221 }, + { 35.794525, -14.450707, -55.341911 }, + { 35.931828, -9.867313, -62.549294 }, + { 36.767994, -3.860245, -69.778938 }, + { 37.964397, 3.296212, -76.853638 }, + { 39.572792, 10.721520, -83.411667 }, + { 41.092911, 17.156990, -89.555016 }, + { 42.447281, 22.770515, -95.525772 } + }, + { + { 37.555626, -69.281143, 56.263180 }, + { 37.338058, -66.389442, 42.991028 }, + { 37.232368, -63.723949, 29.965485 }, + { 37.530113, -60.881599, 17.600735 }, + { 38.033909, -57.176727, 6.448005 }, + { 39.606743, -48.073418, -3.336276 }, + { 40.732307, -37.373260, -13.427800 }, + { 39.156296, -36.143059, -24.613016 }, + { 39.195580, -39.853985, -32.753349 }, + { 39.392818, -36.341888, -41.277798 }, + { 40.255852, -26.215784, -49.228638 }, + { 40.425007, -21.494568, -56.337517 }, + { 40.998665, -16.328390, -63.159996 }, + { 42.008045, -8.124515, -70.667885 }, + { 43.735588, -0.008248, -77.213425 }, + { 44.908211, 5.695886, -83.263741 }, + { 45.916843, 10.629616, -89.268532 } + }, + { + { 42.147465, -76.766701, 60.789772 }, + { 42.299606, -74.511528, 48.546928 }, + { 42.680542, -71.664650, 36.780590 }, + { 42.632626, -69.321091, 24.549770 }, + { 42.984146, -64.874771, 14.230529 }, + { 46.074726, -53.758888, 7.089729 }, + { 51.096718, -39.566898, 2.165134 }, + { 50.707195, -36.346497, -8.316802 }, + { 47.442959, -41.171867, -21.913683 }, + { 42.755508, -42.518425, -36.689568 }, + { 42.632286, -35.811646, -45.989227 }, + { 43.898434, -30.842978, -52.080032 }, + { 45.236687, -26.553791, -57.309086 }, + { 46.277924, -18.302681, -64.644577 }, + { 47.551899, -11.595761, -70.939049 }, + { 48.216679, -7.295179, -76.814461 }, + { 49.303459, -1.626661, -83.059784 } + }, + { + { 46.797306, -82.113327, 65.985092 }, + { 47.033451, -81.177040, 53.767132 }, + { 47.481213, -79.334969, 42.047043 }, + { 47.178333, -77.716866, 30.496847 }, + { 47.269470, -73.222015, 20.729061 }, + { 48.622013, -66.941208, 12.548149 }, + { 51.883324, -56.784122, 6.483915 }, + { 55.790810, -44.951359, 0.086268 }, + { 53.158058, -46.061443, -13.531353 }, + { 46.925144, -48.451294, -30.261021 }, + { 44.608372, -44.204845, -42.466583 }, + { 48.035027, -38.204216, -46.903751 }, + { 49.927052, -33.555050, -51.517765 }, + { 50.282928, -29.511238, -58.053574 }, + { 50.787457, -25.119465, -64.510788 }, + { 51.487301, -19.928804, -70.663300 }, + { 52.675152, -13.315639, -77.167068 } + }, + { + { 51.493137, -85.459854, 72.064362 }, + { 51.550728, -86.243324, 59.471241 }, + { 51.346626, -87.506058, 46.928963 }, + { 51.311836, -86.649879, 35.516239 }, + { 51.907852, -80.964729, 26.292250 }, + { 51.813568, -78.481682, 17.138964 }, + { 52.567123, -73.797798, 9.103230 }, + { 55.225285, -63.819031, 2.390569 }, + { 56.310726, -57.706341, -6.933607 }, + { 54.957817, -54.361889, -18.578909 }, + { 50.593243, -52.641651, -32.250191 }, + { 54.304844, -44.332932, -36.933754 }, + { 55.239887, -39.910801, -42.867847 }, + { 55.378731, -38.685192, -49.435268 }, + { 54.855000, -36.205738, -57.380051 }, + { 55.288586, -30.180481, -64.696053 }, + { 55.905106, -24.846655, -71.332436 } + }, + { + { 55.956814, -87.956116, 78.583946 }, + { 55.951458, -89.536247, 65.894104 }, + { 55.745937, -91.953247, 53.061142 }, + { 55.692318, -93.895714, 40.732735 }, + { 56.506737, -88.414177, 31.591509 }, + { 57.266376, -82.886047, 23.740088 }, + { 57.495304, -78.910980, 15.539824 }, + { 59.111946, -71.728149, 8.452766 }, + { 60.979137, -63.319157, 0.804020 }, + { 61.443375, -56.433319, -8.248948 }, + { 59.583656, -52.542572, -18.632784 }, + { 62.097126, -43.624664, -24.672235 }, + { 62.627522, -40.016567, -31.555696 }, + { 62.710709, -40.601006, -38.678001 }, + { 60.328259, -42.333290, -48.320518 }, + { 59.827030, -38.607014, -56.820175 }, + { 59.847618, -34.463291, -64.449989 } + }, + { + { 60.068268, -90.793953, 84.838387 }, + { 60.192654, -91.867699, 72.754684 }, + { 60.324646, -93.828621, 60.231186 }, + { 60.575718, -96.841438, 47.259399 }, + { 60.726017, -95.176804, 36.974895 }, + { 61.436455, -89.088951, 29.144070 }, + { 61.951851, -83.778435, 21.123663 }, + { 63.845016, -74.660370, 14.288402 }, + { 65.216415, -66.999649, 7.456645 }, + { 68.125725, -55.735107, 1.499337 }, + { 69.251022, -48.719326, -5.498009 }, + { 70.189156, -43.322033, -12.529144 }, + { 69.082596, -42.297348, -20.923473 }, + { 68.525894, -42.538307, -29.228800 }, + { 67.309402, -43.267155, -38.226288 }, + { 65.869087, -42.537128, -47.454998 }, + { 65.015205, -40.900902, -56.037113 } + }, + { + { 63.852764, -94.783005, 90.225807 }, + { 63.971390, -95.628693, 78.901123 }, + { 64.149033, -96.903503, 67.372749 }, + { 64.579300, -99.282082, 54.539188 }, + { 64.799271, -99.079834, 43.678539 }, + { 65.079315, -96.510017, 34.479843 }, + { 65.121437, -92.977661, 25.917637 }, + { 66.091507, -85.305870, 18.747765 }, + { 69.334427, -71.213768, 13.885178 }, + { 72.561859, -58.281437, 8.913195 }, + { 74.310188, -51.313866, 2.740475 }, + { 73.969696, -49.620586, -4.987424 }, + { 73.929848, -47.415058, -12.807284 }, + { 74.025833, -45.128033, -20.781549 }, + { 73.090965, -44.432991, -29.403418 }, + { 72.148270, -44.601425, -37.916103 }, + { 70.987411, -44.660252, -46.620445 } + }, + { + { 67.349503, -100.061180, 94.650215 }, + { 67.601540, -100.434921, 83.617081 }, + { 67.903160, -100.973869, 72.507225 }, + { 68.354591, -101.984932, 61.023727 }, + { 68.759125, -102.480919, 50.264988 }, + { 69.016815, -101.482994, 40.703499 }, + { 69.324677, -97.733971, 32.336086 }, + { 71.038406, -88.192230, 25.881205 }, + { 74.985741, -71.900978, 21.772619 }, + { 77.482079, -60.222874, 16.449583 }, + { 77.933144, -56.736950, 9.423805 }, + { 76.813301, -58.797630, 2.149310 }, + { 77.355469, -55.228737, -6.327007 }, + { 78.259544, -50.391342, -13.713044 }, + { 78.103210, -48.086994, -21.148453 }, + { 78.002663, -47.081196, -28.671013 }, + { 77.030518, -47.001961, -37.058868 } + }, + { + { 70.605003, -106.439667, 98.235733 }, + { 71.140068, -105.973495, 87.486649 }, + { 71.694679, -105.471542, 76.829102 }, + { 72.323982, -104.921577, 66.701965 }, + { 72.968239, -104.236778, 57.044533 }, + { 73.590027, -102.457184, 48.004147 }, + { 74.561729, -97.738243, 40.070148 }, + { 76.610374, -88.369049, 33.687614 }, + { 79.365761, -76.003113, 28.395283 }, + { 80.942566, -67.236389, 22.230713 }, + { 80.441360, -65.912842, 14.429005 }, + { 80.244576, -65.192047, 6.871123 }, + { 81.199265, -60.701340, -0.728169 }, + { 82.711586, -54.392048, -6.819124 }, + { 83.609283, -50.680126, -12.874462 }, + { 83.095512, -49.684742, -20.470055 }, + { 82.480148, -49.196350, -28.229549 } + }, + { + { 73.684883, -113.550720, 101.266472 }, + { 74.626152, -111.773849, 91.339706 }, + { 75.592712, -109.830963, 81.652618 }, + { 76.607193, -107.591873, 72.505096 }, + { 77.654190, -105.035706, 63.792137 }, + { 78.738289, -101.704308, 55.492760 }, + { 80.045647, -96.695099, 47.840370 }, + { 81.571915, -89.846458, 40.910126 }, + { 82.833275, -82.680305, 34.199139 }, + { 83.401482, -77.321457, 27.011520 }, + { 83.379631, -74.066193, 19.249519 }, + { 84.194870, -70.010719, 12.123606 }, + { 84.990082, -64.780075, 5.048793 }, + { 87.093262, -58.014503, -0.075778 }, + { 88.201401, -53.856739, -5.644595 }, + { 87.616577, -52.735920, -13.246017 }, + { 87.337021, -51.746410, -20.465263 } + }, + { + { 76.684563, -120.966629, 104.093536 }, + { 78.093948, -117.602921, 95.307915 }, + { 79.545799, -113.991295, 86.722534 }, + { 81.063217, -109.926338, 78.470009 }, + { 82.615700, -105.414131, 70.545959 }, + { 84.114738, -100.665062, 62.867340 }, + { 85.422188, -96.014442, 55.340061 }, + { 86.284492, -91.952156, 47.838909 }, + { 86.657570, -88.576141, 40.181431 }, + { 86.881157, -85.085617, 32.401379 }, + { 87.432716, -80.339417, 24.811174 }, + { 88.704414, -74.038391, 18.005541 }, + { 90.213524, -67.554886, 12.052963 }, + { 91.620010, -62.085636, 6.675619 }, + { 92.291824, -58.350330, 0.847642 }, + { 92.037338, -56.386528, -6.154075 }, + { 91.936905, -54.630192, -13.065011 } + } + }, + { + { + { 2.194631, 25.095215, 9.179912 }, + { 2.535604, 28.960636, -7.282309 }, + { 3.353140, 33.036476, -22.606419 }, + { 4.573775, 37.572872, -35.686512 }, + { 5.676416, 42.495136, -47.258976 }, + { 6.610404, 47.420284, -57.757523 }, + { 7.818703, 51.882191, -66.543503 }, + { 9.515291, 55.643257, -72.815201 }, + { 11.606574, 58.869347, -77.634598 }, + { 13.890020, 62.074142, -82.079819 }, + { 16.160198, 65.357147, -86.746582 }, + { 18.225294, 68.515205, -91.824394 }, + { 20.022654, 71.423988, -97.299744 }, + { 21.598852, 74.056053, -103.086853 }, + { 23.042112, 76.400558, -109.033325 }, + { 24.432238, 78.536957, -115.013809 }, + { 25.812370, 80.586716, -120.984123 } + }, + { + { 9.901916, 8.968406, 23.153603 }, + { 10.358676, 12.571314, 5.857030 }, + { 10.570131, 16.108046, -11.906166 }, + { 11.461482, 20.904707, -25.971270 }, + { 12.730595, 26.082245, -37.043167 }, + { 12.714532, 31.786831, -48.192539 }, + { 13.684689, 34.340706, -56.575371 }, + { 14.829589, 37.366947, -63.120487 }, + { 16.488838, 41.572044, -68.774307 }, + { 18.501955, 46.352768, -74.186302 }, + { 20.389347, 50.655849, -79.800995 }, + { 22.014421, 54.539814, -85.720810 }, + { 23.503624, 58.037853, -91.802032 }, + { 24.956276, 61.020641, -97.805519 }, + { 26.417416, 63.753407, -103.685410 }, + { 27.900967, 66.489265, -109.498505 }, + { 29.398708, 69.283798, -115.296959 } + }, + { + { 17.451143, -6.325978, 35.710957 }, + { 18.003298, -3.016162, 18.793209 }, + { 17.896296, -0.078914, 0.028142 }, + { 17.471020, 4.411031, -17.127514 }, + { 18.982416, 8.579102, -27.946648 }, + { 19.038702, 14.572520, -38.390671 }, + { 19.704178, 16.331751, -45.886612 }, + { 20.004011, 19.128130, -53.421867 }, + { 21.045374, 25.227642, -60.787697 }, + { 22.801613, 31.111900, -67.068665 }, + { 24.249241, 35.682217, -73.315773 }, + { 25.547836, 40.101151, -79.811272 }, + { 26.858282, 44.392147, -86.431282 }, + { 28.268349, 47.748821, -92.534111 }, + { 29.797926, 50.983318, -98.277176 }, + { 31.393112, 54.455765, -103.931427 }, + { 33.007431, 58.105129, -109.601860 } + }, + { + { 24.292648, -20.138687, 45.617935 }, + { 24.971777, -16.802303, 29.347603 }, + { 25.346998, -13.742940, 12.478652 }, + { 21.122198, -13.227751, -9.132559 }, + { 22.305494, -6.659871, -22.702999 }, + { 23.011808, -1.123648, -32.047771 }, + { 25.525679, -0.211187, -36.241470 }, + { 25.756536, 4.644544, -44.602814 }, + { 25.840973, 11.298232, -53.517941 }, + { 26.829462, 16.430367, -60.688976 }, + { 27.652020, 21.782227, -67.751640 }, + { 28.910469, 26.301149, -74.379189 }, + { 30.146084, 30.179363, -81.058609 }, + { 31.579718, 33.976017, -87.102821 }, + { 33.238701, 38.112206, -92.703529 }, + { 34.947792, 42.564442, -98.278885 }, + { 36.640854, 47.154568, -103.910927 } + }, + { + { 30.301794, -32.328533, 53.148087 }, + { 30.405544, -28.283329, 37.291245 }, + { 29.676292, -25.656490, 20.496344 }, + { 27.777134, -27.602325, 2.952641 }, + { 27.557623, -25.159525, -12.110916 }, + { 26.518534, -17.454735, -26.993191 }, + { 28.999338, -10.260637, -33.469845 }, + { 30.414633, -6.226771, -39.660065 }, + { 30.276592, -2.275715, -47.689045 }, + { 31.098280, 1.345354, -54.325443 }, + { 31.976587, 5.175725, -60.724094 }, + { 32.615475, 10.754633, -68.118881 }, + { 33.737099, 14.980473, -74.908112 }, + { 35.131855, 20.051573, -81.156303 }, + { 36.868195, 25.572502, -86.913742 }, + { 38.607178, 31.061434, -92.574371 }, + { 40.259167, 36.369659, -98.238182 } + }, + { + { 35.382980, -43.329361, 58.613159 }, + { 35.207798, -39.057785, 43.838673 }, + { 35.050964, -35.084080, 29.248339 }, + { 34.968304, -35.820610, 14.351086 }, + { 33.223244, -37.257790, -1.493230 }, + { 30.949011, -31.828493, -17.702541 }, + { 31.174631, -23.175850, -29.025476 }, + { 32.263760, -20.181923, -37.010376 }, + { 34.674049, -16.877617, -41.970982 }, + { 35.586941, -12.644517, -47.552761 }, + { 37.087936, -8.336677, -53.200623 }, + { 37.083496, -3.730099, -61.019989 }, + { 37.831272, 0.247786, -67.973015 }, + { 39.022266, 6.754309, -74.784615 }, + { 40.780113, 13.971962, -81.055656 }, + { 42.366253, 20.086637, -86.884544 }, + { 43.796871, 25.481882, -92.556931 } + }, + { + { 39.948502, -52.952614, 62.897900 }, + { 39.628967, -49.796329, 48.918201 }, + { 39.688084, -46.726738, 35.430050 }, + { 39.375797, -47.028996, 20.873234 }, + { 38.475773, -48.905254, 6.884608 }, + { 39.458763, -43.291008, -3.572394 }, + { 39.489826, -36.093319, -14.410599 }, + { 37.602917, -33.218281, -26.926895 }, + { 38.817688, -33.080070, -34.469784 }, + { 40.318954, -27.357950, -40.574001 }, + { 41.810589, -20.104589, -46.785088 }, + { 41.829170, -15.665214, -54.446774 }, + { 41.763390, -12.290133, -61.611927 }, + { 42.733498, -5.432084, -68.789139 }, + { 44.726223, 3.366291, -75.443398 }, + { 46.009464, 9.140537, -81.228241 }, + { 47.211384, 14.207494, -86.838799 } + }, + { + { 44.469303, -60.942226, 67.033600 }, + { 44.072899, -59.545395, 53.454151 }, + { 43.589680, -59.275539, 39.789970 }, + { 44.173740, -56.968903, 27.566654 }, + { 44.255180, -55.819550, 15.700629 }, + { 45.512672, -49.237385, 6.715030 }, + { 50.048660, -35.835350, 1.199268 }, + { 48.057964, -35.218792, -10.832495 }, + { 44.178928, -40.510128, -25.550926 }, + { 43.465389, -37.455090, -35.874447 }, + { 43.969254, -30.261490, -43.930126 }, + { 43.710777, -25.991590, -51.519974 }, + { 46.010311, -23.513035, -55.455326 }, + { 46.719158, -15.558161, -63.210384 }, + { 48.003292, -7.677940, -70.166420 }, + { 49.113945, -2.992069, -75.562256 }, + { 50.520443, 2.628662, -81.191345 } + }, + { + { 49.053989, -67.339638, 71.702660 }, + { 48.946247, -66.777161, 58.507133 }, + { 49.001602, -65.950226, 45.870338 }, + { 48.869263, -65.330559, 33.801479 }, + { 48.924679, -63.406174, 23.124716 }, + { 49.280014, -58.823711, 13.704093 }, + { 51.454487, -51.239620, 6.639690 }, + { 56.162136, -40.061489, 1.558339 }, + { 51.062859, -46.689415, -14.372479 }, + { 48.089073, -46.722515, -27.927631 }, + { 46.953163, -37.322376, -40.044312 }, + { 47.695263, -32.370831, -47.063793 }, + { 49.674248, -30.064732, -51.138908 }, + { 51.071812, -25.133070, -57.132317 }, + { 51.369411, -20.790157, -63.808540 }, + { 52.370518, -15.104189, -69.826317 }, + { 53.715008, -8.912852, -75.826714 } + }, + { + { 53.667492, -72.006172, 77.333694 }, + { 53.578102, -73.069977, 63.819088 }, + { 53.328735, -74.379608, 50.613174 }, + { 53.386139, -73.728226, 39.010635 }, + { 53.820370, -70.681190, 29.347925 }, + { 53.410606, -68.602669, 19.635309 }, + { 53.799366, -64.811562, 11.000597 }, + { 56.047768, -57.881500, 4.115935 }, + { 55.462044, -56.289005, -6.353141 }, + { 55.409985, -53.160442, -16.191645 }, + { 52.973038, -49.084675, -28.795504 }, + { 55.926296, -39.643646, -34.678410 }, + { 53.981461, -36.194904, -43.723473 }, + { 55.459995, -34.598022, -49.395664 }, + { 55.411591, -32.031933, -56.859909 }, + { 55.956169, -26.336586, -63.916164 }, + { 56.728645, -20.625961, -70.475304 } + }, + { + { 58.033115, -75.756813, 83.591255 }, + { 57.842823, -78.319115, 69.722427 }, + { 57.442631, -81.830055, 55.419949 }, + { 57.309395, -82.678490, 43.329327 }, + { 57.720406, -78.288940, 34.737045 }, + { 58.630104, -72.702286, 26.867136 }, + { 59.379299, -68.129593, 18.479708 }, + { 60.060944, -64.735535, 10.138718 }, + { 60.293015, -61.901642, 1.722394 }, + { 61.385609, -56.515881, -6.036154 }, + { 61.516903, -51.733845, -14.463455 }, + { 64.376671, -39.633358, -21.465460 }, + { 64.010742, -35.625416, -29.963118 }, + { 62.376034, -36.676537, -39.230270 }, + { 60.101643, -38.940693, -48.788219 }, + { 59.948208, -35.420223, -56.903278 }, + { 60.187248, -30.912054, -64.303490 } + }, + { + { 62.056602, -79.679520, 89.683746 }, + { 61.869900, -81.927528, 76.714905 }, + { 61.526600, -85.526810, 62.680946 }, + { 61.350494, -88.479546, 49.023941 }, + { 61.813396, -82.389336, 41.596577 }, + { 63.236813, -77.776184, 33.562771 }, + { 63.261086, -75.461021, 23.811033 }, + { 64.299416, -69.526375, 15.783103 }, + { 65.437401, -63.085815, 8.809142 }, + { 67.781418, -55.276165, 2.801233 }, + { 69.307442, -48.943413, -3.321628 }, + { 70.953491, -40.664391, -10.525912 }, + { 69.428200, -39.737701, -19.786943 }, + { 67.989159, -39.293697, -29.585358 }, + { 67.638527, -39.054317, -38.505459 }, + { 65.973038, -38.841251, -48.043533 }, + { 64.923340, -37.894558, -56.554012 } + }, + { + { 65.737114, -84.598015, 94.810410 }, + { 65.540222, -85.533203, 83.544983 }, + { 65.230560, -86.721992, 72.204872 }, + { 65.257118, -89.631004, 58.255112 }, + { 65.439896, -88.250008, 47.650379 }, + { 65.553215, -89.119293, 37.287495 }, + { 65.257912, -88.506767, 26.953806 }, + { 66.427071, -80.770760, 19.825281 }, + { 70.421585, -66.107765, 15.927446 }, + { 71.516235, -58.012222, 9.095668 }, + { 75.344673, -48.974476, 4.611082 }, + { 74.737366, -47.086361, -2.869295 }, + { 74.877426, -44.999966, -10.993717 }, + { 73.819298, -44.693714, -20.385696 }, + { 73.416718, -40.986900, -29.807699 }, + { 71.755127, -41.214722, -39.230854 }, + { 70.695229, -42.077965, -47.422150 } + }, + { + { 69.072258, -90.534775, 98.886292 }, + { 69.056961, -90.705116, 87.911491 }, + { 68.979012, -90.894714, 76.869583 }, + { 69.024605, -92.041595, 64.912987 }, + { 69.304054, -93.726433, 53.204182 }, + { 69.522881, -94.200539, 43.293697 }, + { 69.556480, -93.220123, 33.719936 }, + { 71.453629, -83.581116, 27.105017 }, + { 76.917679, -65.015106, 24.520969 }, + { 78.577454, -56.272324, 18.225880 }, + { 78.572884, -54.228306, 10.668219 }, + { 77.995499, -57.547890, 5.408533 }, + { 78.411736, -53.483692, -4.360085 }, + { 78.496071, -49.117741, -13.108184 }, + { 78.135521, -46.280880, -21.312641 }, + { 77.623795, -45.354427, -29.477657 }, + { 76.794304, -45.041386, -37.654995 } + }, + { + { 72.075340, -97.406487, 101.929771 }, + { 72.407211, -97.152084, 90.723274 }, + { 72.667000, -96.972237, 79.360672 }, + { 72.971550, -96.240379, 69.481636 }, + { 73.393394, -95.540085, 60.153633 }, + { 73.849358, -95.912552, 50.358929 }, + { 74.528046, -94.122581, 41.292908 }, + { 76.500092, -85.317551, 34.320076 }, + { 79.044769, -73.388412, 28.958109 }, + { 80.833748, -64.972137, 22.744417 }, + { 80.788940, -63.750832, 14.804865 }, + { 80.836174, -63.386673, 7.686352 }, + { 81.646385, -59.193317, 0.212945 }, + { 82.911789, -52.774822, -6.272336 }, + { 83.513535, -49.207619, -12.943359 }, + { 82.804749, -48.579193, -20.900297 }, + { 82.299706, -47.889545, -28.673395 } + }, + { + { 74.799271, -105.043137, 104.165260 }, + { 75.675255, -103.756248, 93.705460 }, + { 76.567032, -102.202591, 83.565628 }, + { 77.554558, -99.933395, 74.484726 }, + { 78.617561, -97.505600, 65.860451 }, + { 79.620697, -95.552521, 57.026375 }, + { 80.554436, -92.507607, 48.704605 }, + { 81.842400, -86.657944, 41.410156 }, + { 82.850945, -80.363754, 34.571987 }, + { 83.029381, -75.999786, 27.154219 }, + { 83.220375, -72.820343, 19.049273 }, + { 84.532372, -68.817284, 12.205650 }, + { 85.923851, -63.227489, 6.058865 }, + { 86.832962, -57.249149, -0.034191 }, + { 88.269928, -52.623829, -5.252475 }, + { 87.259964, -52.059555, -13.713599 }, + { 86.813766, -51.339622, -21.334677 } + }, + { + { 77.385391, -113.011169, 106.109253 }, + { 78.937599, -110.230659, 96.961586 }, + { 80.608109, -107.050621, 88.106422 }, + { 82.468857, -103.218445, 79.631317 }, + { 84.396355, -98.898643, 71.429558 }, + { 86.028198, -94.532646, 63.464943 }, + { 86.991661, -90.664894, 55.861614 }, + { 87.681717, -87.002808, 48.568203 }, + { 88.304604, -83.485542, 41.308357 }, + { 88.612885, -80.697365, 33.686573 }, + { 88.476112, -78.461243, 25.592838 }, + { 89.653885, -73.213661, 18.767080 }, + { 91.629936, -65.628807, 13.180240 }, + { 92.446182, -60.526260, 7.562860 }, + { 92.675156, -57.211643, 1.782133 }, + { 91.726112, -56.188511, -6.286141 }, + { 91.172867, -54.933483, -14.135710 } + } + }, + { + { + { 6.117427, 35.947819, 14.820762 }, + { 5.893884, 38.959026, -2.062465 }, + { 6.399037, 42.215172, -17.978819 }, + { 7.309673, 45.956497, -32.407795 }, + { 8.160170, 49.880272, -45.076698 }, + { 9.032639, 53.327087, -55.509731 }, + { 10.112206, 56.424629, -63.986366 }, + { 11.657075, 59.045643, -70.162193 }, + { 13.746931, 61.395958, -74.579277 }, + { 16.117617, 64.200249, -78.577148 }, + { 18.423384, 67.656410, -83.038132 }, + { 20.479229, 71.191856, -88.062233 }, + { 22.220304, 74.394951, -93.552605 }, + { 23.707523, 77.081543, -99.372604 }, + { 25.046595, 79.266182, -105.330353 }, + { 26.327345, 81.108589, -111.287659 }, + { 27.596712, 82.810242, -117.214798 } + }, + { + { 13.252975, 20.825071, 28.595383 }, + { 13.102325, 23.563944, 10.929248 }, + { 13.628094, 26.082235, -6.209916 }, + { 13.964641, 30.279911, -22.407536 }, + { 14.748767, 36.146362, -36.163464 }, + { 15.362448, 41.678211, -48.303669 }, + { 16.265064, 42.768356, -55.843605 }, + { 17.210234, 44.025738, -61.183208 }, + { 18.729355, 46.459003, -65.575394 }, + { 21.122395, 50.734577, -70.330544 }, + { 23.072115, 55.912136, -76.204330 }, + { 24.539829, 59.862236, -82.278366 }, + { 25.830883, 62.628979, -88.348663 }, + { 27.108751, 64.884575, -94.304382 }, + { 28.406799, 66.992622, -100.122665 }, + { 29.731779, 69.140213, -105.862144 }, + { 31.071486, 71.347107, -111.582214 } + }, + { + { 20.369745, 6.414908, 41.201965 }, + { 21.389925, 8.453310, 24.397776 }, + { 21.098978, 10.288438, 6.139821 }, + { 20.296091, 14.809955, -12.231910 }, + { 21.618414, 21.086046, -25.679499 }, + { 21.729513, 30.068419, -41.484005 }, + { 22.393785, 29.059818, -47.079258 }, + { 22.804136, 29.010675, -51.641048 }, + { 23.482136, 32.723495, -57.484764 }, + { 25.562777, 38.892490, -63.603535 }, + { 27.275627, 44.531635, -70.156166 }, + { 28.217356, 48.496689, -76.942970 }, + { 29.200363, 50.568298, -83.462608 }, + { 30.390774, 52.362923, -89.331482 }, + { 31.737116, 54.538116, -94.869263 }, + { 33.146927, 57.172165, -100.388573 }, + { 34.571205, 60.047916, -105.958771 } + }, + { + { 26.813593, -6.628572, 51.259621 }, + { 27.254398, -4.897876, 34.145210 }, + { 26.920361, -4.127317, 16.370705 }, + { 27.213533, 0.013652, 0.217647 }, + { 25.932930, 3.803387, -15.362780 }, + { 26.468689, 10.412895, -28.976486 }, + { 28.689941, 10.341507, -32.836239 }, + { 28.267767, 16.074833, -42.428177 }, + { 28.402294, 21.692791, -50.986946 }, + { 29.677740, 26.289900, -57.848465 }, + { 30.102207, 30.163527, -65.247314 }, + { 31.076159, 35.264580, -72.482704 }, + { 32.229809, 37.540363, -78.971107 }, + { 33.479908, 39.091278, -84.356598 }, + { 35.042259, 41.817837, -89.467636 }, + { 36.590073, 45.303188, -94.848785 }, + { 38.100040, 49.090496, -100.394493 } + }, + { + { 32.713120, -18.190170, 59.253136 }, + { 33.290630, -14.952955, 43.378284 }, + { 33.720337, -12.149815, 27.512030 }, + { 32.290821, -12.725239, 9.619167 }, + { 32.014450, -11.397281, -4.304647 }, + { 30.590609, -8.117508, -18.336893 }, + { 30.052258, -0.832760, -31.381868 }, + { 32.298267, 4.022144, -37.471176 }, + { 32.716778, 7.524209, -45.053165 }, + { 33.341705, 11.049520, -52.027287 }, + { 33.252228, 14.263353, -59.503117 }, + { 34.148087, 20.085142, -67.178421 }, + { 35.496361, 22.618231, -73.323410 }, + { 36.638462, 25.095512, -78.745567 }, + { 38.412300, 29.105349, -83.859283 }, + { 40.068218, 33.739727, -89.324501 }, + { 41.617702, 38.500278, -94.950722 } + }, + { + { 37.967663, -28.549444, 65.396637 }, + { 38.229401, -25.047834, 50.444592 }, + { 38.319019, -22.512388, 35.039700 }, + { 37.569790, -22.384356, 17.489845 }, + { 37.830578, -22.407425, 4.507887 }, + { 36.201469, -20.803926, -8.725446 }, + { 36.625629, -16.630630, -19.736248 }, + { 36.625729, -13.264974, -29.655960 }, + { 36.678921, -7.156029, -39.327106 }, + { 37.347450, -3.672858, -45.149693 }, + { 38.903481, -0.336838, -51.196213 }, + { 40.681744, 7.256486, -58.772343 }, + { 39.771389, 7.527492, -65.686806 }, + { 40.389866, 11.291424, -72.255295 }, + { 41.952377, 16.964848, -78.226967 }, + { 43.547684, 22.616028, -83.938889 }, + { 45.059902, 28.049141, -89.618469 } + }, + { + { 42.583622, -38.067104, 69.794952 }, + { 41.814575, -36.201344, 54.283413 }, + { 42.057808, -34.007038, 40.136242 }, + { 41.347168, -33.577206, 24.083548 }, + { 40.015553, -36.951336, 8.577510 }, + { 42.291664, -34.696358, 0.885698 }, + { 40.986336, -34.209999, -10.465726 }, + { 40.619030, -28.104294, -22.339598 }, + { 40.283878, -20.321503, -34.189342 }, + { 41.458935, -15.368311, -40.039028 }, + { 42.519115, -11.938332, -46.031265 }, + { 43.535770, -7.938691, -52.590466 }, + { 42.098309, -6.131143, -60.591217 }, + { 43.635548, -0.951462, -66.976303 }, + { 45.503895, 5.926448, -73.012840 }, + { 46.922329, 11.745834, -78.715187 }, + { 48.391708, 17.364552, -84.317299 } + }, + { + { 47.036995, -46.502048, 73.542900 }, + { 45.942348, -46.082409, 58.415070 }, + { 46.001022, -45.082375, 45.053455 }, + { 47.150772, -40.875179, 32.964401 }, + { 46.656933, -42.582630, 18.784992 }, + { 46.544106, -40.731865, 7.490370 }, + { 45.632915, -39.982712, -3.381283 }, + { 43.760845, -39.334488, -15.305373 }, + { 42.637074, -36.541763, -28.112995 }, + { 46.235989, -30.468437, -32.136845 }, + { 45.312366, -22.974550, -41.571220 }, + { 46.050228, -18.091856, -48.797886 }, + { 48.021252, -13.571873, -54.257278 }, + { 48.094105, -8.895799, -61.848476 }, + { 48.674381, -4.315119, -68.238457 }, + { 50.050194, 0.809479, -73.635086 }, + { 51.620659, 6.252522, -79.035057 } + }, + { + { 51.543526, -53.712116, 77.732307 }, + { 51.096584, -53.475170, 63.787384 }, + { 51.278469, -52.219025, 51.228817 }, + { 51.592999, -50.980339, 39.192776 }, + { 50.508759, -51.913673, 25.566275 }, + { 50.779716, -47.775322, 14.718497 }, + { 50.460659, -49.346107, 4.974362 }, + { 52.683895, -45.378361, -2.137845 }, + { 50.015160, -42.611443, -15.991169 }, + { 50.598282, -40.046455, -24.457029 }, + { 50.429485, -33.937263, -33.839947 }, + { 50.135254, -28.094063, -42.750465 }, + { 52.073410, -22.954578, -48.433609 }, + { 52.339336, -18.396524, -55.676014 }, + { 52.620033, -14.139872, -62.718872 }, + { 53.608433, -9.319524, -68.450203 }, + { 54.715168, -5.263414, -73.838264 } + }, + { + { 55.849358, -59.723293, 82.601425 }, + { 55.547173, -60.632198, 68.508591 }, + { 55.270336, -60.885391, 55.096241 }, + { 54.913963, -61.460869, 42.719887 }, + { 55.091667, -59.845264, 32.330105 }, + { 54.839176, -58.499714, 21.380018 }, + { 55.312771, -56.543930, 12.063778 }, + { 57.016434, -52.793331, 4.844398 }, + { 56.181801, -50.056053, -5.819175 }, + { 56.425949, -47.592072, -14.187377 }, + { 57.388058, -41.293106, -22.873007 }, + { 56.529896, -36.116417, -32.502850 }, + { 55.933380, -33.262894, -40.853798 }, + { 56.321426, -30.305681, -48.189648 }, + { 56.346931, -26.734625, -55.683182 }, + { 56.989059, -21.468363, -62.511627 }, + { 57.574120, -17.170641, -68.690071 } + }, + { + { 59.903015, -64.806206, 88.134560 }, + { 59.755989, -66.852829, 74.196327 }, + { 59.636536, -68.850616, 60.402405 }, + { 59.094963, -69.401009, 48.409935 }, + { 59.543911, -65.463264, 39.562447 }, + { 60.389771, -62.404659, 29.811714 }, + { 60.088875, -61.203682, 19.292044 }, + { 60.586674, -58.971989, 10.769589 }, + { 61.755909, -54.691498, 2.870778 }, + { 62.393375, -51.545071, -4.703671 }, + { 63.848419, -44.300224, -12.367669 }, + { 64.527359, -36.153870, -20.806168 }, + { 62.858212, -36.767944, -30.212439 }, + { 61.295643, -36.521793, -39.707775 }, + { 60.339752, -35.800167, -48.123539 }, + { 59.933956, -32.129284, -56.536354 }, + { 60.658714, -27.640661, -63.287815 } + }, + { + { 63.782776, -69.623932, 93.882225 }, + { 63.731552, -71.628716, 81.092323 }, + { 63.504131, -74.707497, 67.094780 }, + { 63.062969, -76.056816, 53.888214 }, + { 63.966694, -68.212486, 47.465206 }, + { 66.382332, -67.003174, 37.494850 }, + { 63.898514, -69.552467, 24.974005 }, + { 65.808250, -62.777843, 17.931005 }, + { 67.418358, -55.238293, 10.817096 }, + { 67.120087, -53.757187, 2.772894 }, + { 70.598183, -44.876358, -2.051252 }, + { 71.073242, -39.196213, -9.795617 }, + { 69.541763, -39.132519, -19.476381 }, + { 67.551247, -38.176109, -30.130148 }, + { 67.145706, -35.998146, -38.809280 }, + { 65.999161, -35.403130, -48.083221 }, + { 65.046051, -34.754566, -56.433418 } + }, + { + { 67.410187, -75.015121, 98.923820 }, + { 67.417717, -75.712738, 87.904037 }, + { 67.168678, -76.967239, 76.002457 }, + { 66.517403, -78.757553, 62.952511 }, + { 66.510544, -78.793877, 51.274174 }, + { 67.254662, -80.184258, 39.615536 }, + { 65.689796, -81.937576, 28.031570 }, + { 68.151276, -72.911888, 22.359917 }, + { 72.592911, -58.883945, 18.786095 }, + { 72.562057, -54.633446, 10.408222 }, + { 75.443489, -48.029518, 5.553681 }, + { 75.764374, -44.613750, -1.603719 }, + { 76.048904, -41.795113, -9.655909 }, + { 74.588722, -40.935097, -19.920965 }, + { 72.612289, -39.328579, -30.775398 }, + { 70.989578, -38.724747, -40.560711 }, + { 70.647972, -39.310246, -47.748615 } + }, + { + { 70.670319, -81.230377, 102.820793 }, + { 70.768417, -81.268265, 92.150124 }, + { 70.632507, -81.402405, 80.943352 }, + { 69.931236, -82.322960, 68.864792 }, + { 69.941223, -83.397575, 56.925262 }, + { 70.417656, -83.677147, 46.508537 }, + { 70.502701, -84.892540, 35.746990 }, + { 71.705818, -78.052948, 28.219292 }, + { 76.312424, -63.918640, 24.908173 }, + { 78.271812, -56.380417, 18.689669 }, + { 78.267784, -54.270096, 10.610400 }, + { 78.987938, -53.068668, 4.215909 }, + { 78.376617, -50.977795, -4.442294 }, + { 79.007057, -47.214874, -12.229679 }, + { 77.253456, -47.001591, -21.928358 }, + { 76.030365, -45.510624, -31.187033 }, + { 76.746834, -42.874187, -37.900669 } + }, + { + { 73.504074, -88.333054, 105.446938 }, + { 73.817764, -88.464912, 94.174034 }, + { 73.887596, -89.021172, 82.328743 }, + { 73.705780, -88.505234, 72.284431 }, + { 73.711349, -86.292145, 63.642597 }, + { 74.190125, -88.290268, 53.019722 }, + { 75.283180, -89.225739, 42.562611 }, + { 75.617554, -83.192047, 34.117977 }, + { 75.739449, -77.069138, 27.199215 }, + { 78.473557, -68.527718, 21.565737 }, + { 80.298340, -63.106682, 14.602099 }, + { 81.485573, -59.949066, 7.846957 }, + { 81.273026, -57.926449, 0.023018 }, + { 83.259537, -51.539238, -5.420777 }, + { 83.590004, -48.215237, -12.520311 }, + { 82.350830, -48.019398, -21.265242 }, + { 82.222519, -46.428806, -28.998222 } + }, + { + { 75.946709, -96.302673, 107.006424 }, + { 76.777214, -95.723610, 96.234734 }, + { 77.553787, -94.934937, 85.663048 }, + { 78.458504, -92.706795, 76.616440 }, + { 79.532196, -89.893318, 68.163330 }, + { 80.775505, -89.225510, 58.488800 }, + { 80.822090, -89.103615, 49.285824 }, + { 81.413612, -84.440170, 41.397675 }, + { 82.748535, -78.715454, 34.620312 }, + { 83.571503, -74.001213, 27.492136 }, + { 82.875916, -71.246574, 18.660883 }, + { 82.739861, -69.323509, 10.841211 }, + { 84.551140, -63.994465, 5.136941 }, + { 87.525040, -56.155907, 0.901207 }, + { 88.706535, -51.101658, -4.419098 }, + { 87.235985, -51.174274, -13.503173 }, + { 86.467323, -50.501480, -21.896530 } + }, + { + { 78.188950, -104.636948, 108.176056 }, + { 79.764343, -102.678467, 98.639297 }, + { 81.556129, -100.178947, 89.490028 }, + { 83.763466, -96.793785, 80.791687 }, + { 86.261673, -92.780998, 72.242188 }, + { 88.330254, -88.553970, 63.959969 }, + { 88.536469, -85.683426, 56.516510 }, + { 89.089180, -81.890968, 49.490833 }, + { 90.506927, -76.787773, 42.752247 }, + { 91.018478, -74.347237, 35.295837 }, + { 89.609779, -76.411629, 26.737776 }, + { 89.351952, -75.411697, 19.480156 }, + { 91.353775, -66.683777, 13.682072 }, + { 92.155846, -60.122658, 7.800332 }, + { 92.437271, -56.272587, 2.222061 }, + { 92.050835, -54.660583, -5.662271 }, + { 91.241249, -53.484787, -14.196399 } + } + }, + { + { + { 10.707095, 44.296329, 22.264570 }, + { 9.582357, 47.116425, 4.165955 }, + { 9.344697, 49.907036, -13.057452 }, + { 9.932414, 52.783264, -28.552025 }, + { 10.786889, 55.483433, -41.635788 }, + { 11.754217, 57.755638, -51.866360 }, + { 12.687078, 60.073803, -60.158485 }, + { 13.896039, 62.276489, -66.699982 }, + { 15.718280, 64.336876, -71.503906 }, + { 17.940336, 66.967033, -75.658241 }, + { 20.178110, 70.275551, -80.068680 }, + { 22.195814, 73.760109, -84.992401 }, + { 23.933136, 76.938774, -90.368721 }, + { 25.446825, 79.585373, -96.060616 }, + { 26.818800, 81.708786, -101.889458 }, + { 28.119102, 83.466110, -107.730003 }, + { 29.396439, 85.066269, -113.549339 } + }, + { + { 16.931627, 30.398083, 34.788761 }, + { 15.719934, 32.841911, 16.028469 }, + { 16.056419, 34.461609, -1.803600 }, + { 16.079805, 37.564243, -19.140537 }, + { 16.679523, 43.450367, -34.599125 }, + { 17.722462, 49.045719, -47.173386 }, + { 18.654381, 51.048634, -54.849335 }, + { 19.359953, 50.634327, -59.157585 }, + { 20.296001, 51.698154, -63.443348 }, + { 22.498806, 55.818031, -68.415161 }, + { 24.853622, 60.460167, -73.647797 }, + { 26.594048, 63.873062, -79.154251 }, + { 27.916265, 66.174141, -84.947403 }, + { 29.128502, 68.118561, -90.808830 }, + { 30.326269, 69.973000, -96.605354 }, + { 31.535580, 71.824295, -102.335945 }, + { 32.756138, 73.692207, -108.040939 } + }, + { + { 23.055309, 16.577860, 46.212769 }, + { 23.111469, 17.710171, 28.026049 }, + { 23.506624, 18.832281, 9.911521 }, + { 21.821501, 21.494846, -9.042798 }, + { 22.587229, 30.472300, -25.795622 }, + { 23.732210, 40.876972, -42.623028 }, + { 25.159498, 42.060844, -49.435879 }, + { 25.831684, 38.084431, -50.008224 }, + { 25.511505, 39.220230, -54.887486 }, + { 27.372240, 45.338188, -61.472576 }, + { 29.621941, 50.892681, -67.507973 }, + { 30.863405, 53.902603, -73.558647 }, + { 31.730522, 55.212185, -79.779228 }, + { 32.700447, 56.435398, -85.639671 }, + { 33.780716, 58.081814, -91.292931 }, + { 34.940487, 60.159584, -96.911156 }, + { 36.136112, 62.456451, -102.548996 } + }, + { + { 29.035896, 4.022204, 56.126595 }, + { 28.875837, 4.347186, 37.627995 }, + { 29.100513, 4.929775, 19.242447 }, + { 29.217213, 9.093901, 3.175453 }, + { 29.285755, 13.163331, -11.081565 }, + { 29.500809, 23.155403, -28.693342 }, + { 29.988817, 27.374083, -39.809654 }, + { 30.447012, 26.835844, -42.662144 }, + { 31.041098, 29.684601, -48.385685 }, + { 32.451717, 34.826702, -55.232822 }, + { 33.195190, 38.545525, -62.401005 }, + { 34.009300, 41.820183, -69.100929 }, + { 35.140533, 43.705582, -75.127678 }, + { 36.074032, 44.248398, -80.477463 }, + { 37.136875, 45.862499, -85.870399 }, + { 38.317024, 48.485325, -91.449081 }, + { 39.543102, 51.542999, -97.132965 } + }, + { + { 35.027088, -6.655026, 64.721664 }, + { 35.302830, -5.447665, 47.688728 }, + { 35.570236, -5.126636, 30.879288 }, + { 35.372959, -4.804170, 14.799982 }, + { 33.731850, -1.317551, -1.638667 }, + { 33.247227, 2.411989, -16.210724 }, + { 33.262104, 6.621255, -28.132992 }, + { 35.875023, 12.548450, -33.438358 }, + { 35.806538, 17.245914, -42.039570 }, + { 36.240868, 20.311512, -49.192459 }, + { 34.897896, 21.108482, -57.407478 }, + { 35.794003, 26.992933, -65.070366 }, + { 38.105282, 30.508247, -70.154297 }, + { 39.238636, 31.058859, -74.965591 }, + { 40.377071, 33.282185, -80.315880 }, + { 41.640770, 36.917545, -86.028687 }, + { 42.952545, 41.057354, -91.866898 } + }, + { + { 40.546551, -16.096222, 71.734032 }, + { 41.001419, -13.829608, 56.168636 }, + { 41.156357, -12.209064, 39.899822 }, + { 40.262371, -11.646186, 22.712091 }, + { 40.208672, -11.247257, 9.382845 }, + { 40.127583, -7.829805, -3.174876 }, + { 39.072105, -4.325335, -16.219755 }, + { 38.849461, -1.279088, -26.618858 }, + { 39.910522, 3.232552, -34.756752 }, + { 40.512218, 5.471983, -41.606331 }, + { 40.166744, 7.599446, -49.787891 }, + { 40.860252, 14.236703, -58.046238 }, + { 41.088654, 15.097255, -63.849014 }, + { 42.202866, 17.018044, -69.174072 }, + { 43.496704, 20.762781, -74.853607 }, + { 44.885807, 25.672092, -80.784187 }, + { 46.316307, 30.874447, -86.756996 } + }, + { + { 45.614639, -24.851767, 76.975853 }, + { 45.390110, -23.277182, 61.306782 }, + { 46.011768, -21.443399, 46.862160 }, + { 44.849285, -21.075546, 30.974430 }, + { 44.437298, -21.020803, 16.905884 }, + { 47.073944, -17.572451, 7.884696 }, + { 44.965736, -15.894739, -5.184340 }, + { 43.632275, -12.967040, -18.478067 }, + { 44.082035, -8.923743, -28.555559 }, + { 44.456299, -6.394733, -36.134048 }, + { 43.784477, -3.534443, -44.702549 }, + { 43.919510, 1.131871, -52.438583 }, + { 44.144886, 1.750177, -58.306221 }, + { 45.247787, 5.401462, -64.364204 }, + { 46.595852, 9.448371, -69.867569 }, + { 48.072289, 14.969698, -75.791725 }, + { 49.583660, 20.607580, -81.712059 } + }, + { + { 50.194347, -33.295071, 80.763428 }, + { 48.860954, -32.877495, 64.851059 }, + { 49.810799, -30.240261, 52.694321 }, + { 50.640705, -26.100996, 40.253532 }, + { 50.157616, -27.537136, 25.249853 }, + { 49.026108, -29.550589, 11.674026 }, + { 49.092258, -28.624846, 1.578097 }, + { 49.369507, -25.485924, -8.439925 }, + { 48.527477, -21.890715, -19.766565 }, + { 48.402042, -19.807060, -28.348969 }, + { 48.232021, -17.383524, -36.852726 }, + { 48.826012, -11.410976, -44.860954 }, + { 49.687580, -5.448225, -52.348354 }, + { 49.346352, -1.959749, -59.923801 }, + { 49.928707, -0.272119, -65.225433 }, + { 51.345531, 5.159173, -71.094276 }, + { 52.711761, 9.832692, -76.621399 } + }, + { + { 54.488121, -41.062225, 84.515785 }, + { 54.371887, -40.398663, 70.833443 }, + { 53.901814, -39.805305, 57.530670 }, + { 53.949074, -37.950287, 45.224892 }, + { 52.946053, -38.904533, 30.403837 }, + { 52.271019, -40.331539, 16.728401 }, + { 53.168968, -38.016598, 7.730191 }, + { 54.384945, -35.149933, -0.256731 }, + { 54.408772, -30.346960, -10.344239 }, + { 52.329811, -30.823452, -21.300188 }, + { 52.411316, -29.920118, -29.627213 }, + { 52.748158, -23.192673, -38.435997 }, + { 53.615620, -16.190615, -45.918034 }, + { 53.682907, -11.425670, -53.756401 }, + { 54.272861, -7.261932, -60.725849 }, + { 55.009026, -3.584035, -66.458420 }, + { 55.647671, -1.845111, -71.360580 } + }, + { + { 58.071800, -48.417160, 88.119751 }, + { 57.269974, -49.669910, 73.302147 }, + { 56.794724, -50.315701, 59.573555 }, + { 57.054409, -49.004337, 48.398468 }, + { 57.232655, -47.555058, 37.029331 }, + { 57.144775, -47.809032, 24.535660 }, + { 57.603428, -45.156918, 14.391821 }, + { 56.775166, -46.056362, 4.309736 }, + { 57.235924, -43.640347, -3.693494 }, + { 57.413372, -40.332829, -12.530519 }, + { 57.546902, -36.649410, -21.307673 }, + { 56.743481, -32.753578, -31.234413 }, + { 57.004059, -29.137123, -38.882950 }, + { 56.997078, -23.286909, -47.461830 }, + { 57.581593, -19.634535, -54.165333 }, + { 58.081001, -17.309996, -59.861950 }, + { 58.394150, -14.136488, -66.028763 } + }, + { + { 61.607265, -54.816444, 92.444824 }, + { 61.417789, -55.693195, 78.949890 }, + { 61.551476, -55.917877, 66.533539 }, + { 61.205612, -55.498501, 54.760303 }, + { 61.594288, -53.442921, 44.310970 }, + { 61.539337, -53.988415, 32.301243 }, + { 61.338734, -53.224430, 21.210047 }, + { 61.464565, -52.282013, 11.880844 }, + { 62.199913, -47.826813, 3.568025 }, + { 60.851231, -47.994034, -6.391453 }, + { 62.482910, -42.265194, -13.491266 }, + { 62.275589, -38.345013, -22.389015 }, + { 61.028782, -37.700050, -31.739872 }, + { 62.088795, -32.425533, -39.028954 }, + { 61.589737, -29.421883, -47.035549 }, + { 60.797390, -27.716232, -54.819675 }, + { 61.354637, -24.202702, -61.407238 } + }, + { + { 65.263206, -60.497536, 97.427719 }, + { 65.541512, -60.596855, 85.875511 }, + { 65.851593, -60.301262, 74.786125 }, + { 65.233932, -59.681248, 62.729923 }, + { 65.687546, -57.667736, 51.865322 }, + { 65.832825, -60.677723, 39.036873 }, + { 65.176994, -61.039711, 27.534039 }, + { 66.595627, -56.105263, 20.245136 }, + { 67.747414, -51.072182, 11.842639 }, + { 66.901131, -51.078220, 2.589370 }, + { 68.505608, -45.724178, -3.847238 }, + { 69.600746, -39.492409, -11.589989 }, + { 68.343346, -38.497150, -21.409761 }, + { 68.064705, -36.252441, -29.644789 }, + { 67.760056, -33.222675, -37.696499 }, + { 65.859482, -32.256382, -47.743076 }, + { 65.205177, -31.146301, -55.989521 } + }, + { + { 68.830605, -66.133865, 102.295685 }, + { 69.277855, -65.385056, 92.797516 }, + { 69.570038, -64.735893, 82.553261 }, + { 68.304474, -65.415176, 69.994453 }, + { 68.176727, -65.907387, 57.017563 }, + { 68.970131, -66.520721, 44.473366 }, + { 68.951057, -67.513199, 33.584301 }, + { 70.112953, -63.742645, 25.868015 }, + { 70.617668, -58.695599, 17.562489 }, + { 72.672623, -52.127785, 10.763945 }, + { 73.728226, -49.131294, 4.210668 }, + { 74.570709, -44.301090, -3.301145 }, + { 75.832809, -39.344677, -10.177533 }, + { 74.937584, -38.066475, -19.211422 }, + { 73.133118, -36.426620, -29.538193 }, + { 71.465042, -35.424408, -39.799858 }, + { 70.664848, -36.130226, -47.815746 } + }, + { + { 72.070488, -72.329025, 106.125923 }, + { 72.470345, -71.821289, 96.728493 }, + { 72.568130, -72.002190, 85.981384 }, + { 71.573715, -73.897270, 72.466797 }, + { 71.502594, -72.186699, 61.294292 }, + { 72.113678, -70.773376, 51.181156 }, + { 71.771637, -73.720551, 39.430214 }, + { 71.637932, -73.200218, 29.580080 }, + { 75.745583, -62.231239, 25.299610 }, + { 79.491180, -52.470627, 19.990473 }, + { 76.097382, -56.562153, 8.700616 }, + { 76.466805, -55.638657, 1.443376 }, + { 78.272491, -48.042385, -4.690130 }, + { 78.992287, -44.276165, -11.720604 }, + { 77.746315, -43.551891, -21.316235 }, + { 77.308472, -41.368240, -30.039696 }, + { 77.051773, -39.798817, -37.674088 } + }, + { + { 74.830170, -79.429886, 108.488655 }, + { 75.287315, -79.591125, 98.027199 }, + { 75.399078, -80.668465, 86.362595 }, + { 74.938820, -81.565163, 74.632843 }, + { 74.518730, -79.253998, 65.792290 }, + { 74.785667, -82.343147, 54.857883 }, + { 75.250526, -84.416733, 43.726566 }, + { 75.042877, -80.134140, 34.712891 }, + { 77.891724, -70.900543, 29.811001 }, + { 81.405296, -62.820969, 24.260235 }, + { 80.126129, -61.717327, 14.680842 }, + { 81.312592, -57.978424, 7.760292 }, + { 82.065132, -54.029743, 1.074864 }, + { 83.490257, -49.061722, -4.567120 }, + { 83.856453, -46.202591, -11.797847 }, + { 82.363029, -46.087372, -21.320351 }, + { 81.370270, -45.175522, -30.005693 } + }, + { + { 77.127289, -87.391907, 109.625977 }, + { 77.975044, -87.307503, 99.066124 }, + { 78.750832, -87.096779, 88.537422 }, + { 79.445038, -85.755295, 78.952095 }, + { 80.163101, -83.276100, 70.334534 }, + { 81.768799, -83.736168, 59.865997 }, + { 81.561165, -84.907997, 50.180916 }, + { 80.580643, -81.744545, 41.437111 }, + { 81.857925, -75.681305, 34.722118 }, + { 84.016594, -70.599365, 28.626301 }, + { 83.865601, -68.807426, 20.295877 }, + { 83.236534, -66.896507, 11.674018 }, + { 84.587769, -62.824379, 5.563080 }, + { 87.263138, -55.302902, 1.523878 }, + { 88.864319, -49.537407, -3.730699 }, + { 87.527359, -49.226357, -12.940825 }, + { 86.225815, -49.004475, -22.283945 } + }, + { + { 79.185631, -95.669052, 110.324493 }, + { 80.637337, -94.798019, 100.264923 }, + { 82.386795, -93.366081, 90.679993 }, + { 84.742004, -90.988647, 81.696899 }, + { 87.596840, -87.876350, 72.928963 }, + { 89.754982, -84.368439, 64.778366 }, + { 89.771133, -81.264816, 58.014950 }, + { 90.401199, -77.021202, 50.793304 }, + { 91.533852, -72.318443, 43.674297 }, + { 91.246941, -70.822891, 36.111324 }, + { 90.702904, -72.597351, 28.245832 }, + { 89.608337, -72.956856, 20.222080 }, + { 89.934181, -67.612831, 13.522446 }, + { 90.224098, -61.363117, 7.372761 }, + { 91.846024, -55.596848, 2.344141 }, + { 92.679237, -52.197529, -4.593371 }, + { 91.863312, -50.718525, -13.423651 } + } + }, + { + { + { 15.171535, 51.116253, 29.247040 }, + { 13.184265, 53.655426, 10.040959 }, + { 12.268023, 55.747299, -8.103042 }, + { 12.539178, 57.786572, -24.019669 }, + { 13.536759, 59.653328, -36.976196 }, + { 14.861300, 61.194454, -46.901623 }, + { 15.906568, 62.857727, -54.942768 }, + { 16.731459, 64.942108, -61.959385 }, + { 17.953699, 67.301559, -67.822151 }, + { 19.759565, 70.029198, -72.702095 }, + { 21.691589, 73.108086, -77.424980 }, + { 23.520828, 76.262222, -82.401085 }, + { 25.227987, 79.166588, -87.665993 }, + { 26.841341, 81.663177, -93.141373 }, + { 28.352764, 83.773315, -98.748573 }, + { 29.784285, 85.606918, -104.408379 }, + { 31.180830, 87.313736, -110.075226 } + }, + { + { 21.261637, 38.234680, 41.471004 }, + { 19.060095, 41.288086, 21.999981 }, + { 18.521610, 41.663757, 2.681612 }, + { 18.161961, 43.639877, -15.418224 }, + { 18.670986, 47.701458, -30.575905 }, + { 20.150053, 51.520092, -41.543777 }, + { 21.436949, 53.452507, -48.948563 }, + { 21.302105, 54.156902, -55.182590 }, + { 21.349895, 56.711468, -61.973763 }, + { 23.898972, 60.402199, -66.968475 }, + { 26.034878, 63.599335, -71.613258 }, + { 27.931141, 66.333344, -76.471306 }, + { 29.551073, 68.672974, -81.815178 }, + { 30.894396, 70.761086, -87.488281 }, + { 32.099747, 72.703857, -93.256027 }, + { 33.274307, 74.538414, -99.004990 }, + { 34.452766, 76.324120, -104.729774 } + }, + { + { 27.177967, 25.088507, 52.604343 }, + { 26.595186, 26.501245, 33.880806 }, + { 25.253735, 27.651640, 13.637393 }, + { 23.939644, 29.332691, -5.733518 }, + { 24.005289, 34.742844, -22.471970 }, + { 24.747044, 41.307941, -35.755970 }, + { 26.492706, 44.182671, -43.357246 }, + { 26.683985, 43.314285, -47.748383 }, + { 25.927219, 46.119778, -54.885841 }, + { 27.955147, 50.654915, -61.218723 }, + { 30.016973, 53.777687, -65.999290 }, + { 32.211445, 56.033436, -70.546143 }, + { 33.892796, 57.911919, -75.906326 }, + { 34.887390, 59.721371, -81.839706 }, + { 35.773895, 61.544067, -87.767387 }, + { 36.728828, 63.437710, -93.601669 }, + { 37.737415, 65.411476, -99.400803 } + }, + { + { 32.425632, 13.047461, 61.907333 }, + { 32.192646, 13.417386, 43.326698 }, + { 31.999411, 14.630102, 24.588945 }, + { 31.293152, 16.657337, 7.423706 }, + { 29.901037, 19.823711, -10.294174 }, + { 29.688967, 26.047039, -24.850920 }, + { 30.260469, 31.253548, -35.484772 }, + { 30.827305, 34.704765, -42.106960 }, + { 32.320198, 36.537331, -47.427418 }, + { 32.981220, 40.332851, -54.542152 }, + { 35.034164, 43.040806, -59.597843 }, + { 36.420361, 45.087776, -64.866692 }, + { 37.947441, 46.660324, -70.192055 }, + { 38.599728, 48.400932, -76.285400 }, + { 39.265736, 50.107998, -82.277138 }, + { 40.104942, 52.245724, -88.205627 }, + { 41.046600, 54.714027, -94.132919 } + }, + { + { 37.531731, 2.593933, 69.721901 }, + { 37.463905, 2.872678, 51.723965 }, + { 37.201969, 3.013987, 33.766075 }, + { 37.509560, 4.776138, 18.107302 }, + { 38.172981, 8.242288, 5.262514 }, + { 37.501213, 10.959918, -9.005936 }, + { 36.959965, 15.151305, -22.063185 }, + { 37.387924, 22.292717, -31.339088 }, + { 38.650356, 25.566254, -39.489643 }, + { 37.890347, 27.508865, -47.741676 }, + { 38.273308, 28.735567, -54.026772 }, + { 39.594414, 33.506180, -60.187843 }, + { 41.049297, 35.999172, -65.448822 }, + { 41.824013, 36.613098, -70.896454 }, + { 42.492027, 38.147324, -76.783173 }, + { 43.364883, 40.982307, -82.870796 }, + { 44.374760, 44.379299, -88.986977 } + }, + { + { 42.790516, -6.138625, 76.707527 }, + { 42.778091, -5.036102, 59.491562 }, + { 42.433228, -3.941388, 42.096657 }, + { 42.018017, -2.455482, 25.927553 }, + { 42.191715, -2.689432, 13.407433 }, + { 41.639065, 0.134130, -0.901397 }, + { 42.113083, 2.398638, -10.752243 }, + { 42.672859, 6.067034, -20.476099 }, + { 41.972488, 11.961906, -32.798065 }, + { 41.614632, 14.624765, -41.030437 }, + { 42.371067, 17.767159, -48.470436 }, + { 43.854500, 23.896564, -55.175255 }, + { 44.537907, 24.921423, -60.322296 }, + { 44.696152, 23.731743, -65.442490 }, + { 45.428848, 25.912668, -71.433609 }, + { 46.498661, 29.978226, -77.732872 }, + { 47.684959, 34.399353, -83.985207 } + }, + { + { 48.443211, -13.763400, 83.100700 }, + { 49.048397, -11.886261, 67.393929 }, + { 48.232689, -11.600213, 50.838352 }, + { 47.592499, -11.415878, 35.344753 }, + { 47.301178, -11.016311, 21.771540 }, + { 47.310440, -10.606135, 9.277176 }, + { 46.379341, -7.346323, -4.178150 }, + { 46.044380, -4.976894, -15.671826 }, + { 46.125404, -1.614655, -24.791096 }, + { 45.939636, 1.987963, -34.185513 }, + { 46.903042, 7.021880, -42.067520 }, + { 47.683537, 10.617798, -48.526707 }, + { 47.247673, 10.979310, -54.847706 }, + { 47.399441, 12.142595, -60.668274 }, + { 48.368065, 15.156878, -66.599556 }, + { 49.621460, 19.712208, -72.862183 }, + { 50.900509, 24.426441, -79.053558 } + }, + { + { 53.601414, -21.582518, 88.228249 }, + { 55.233204, -19.140266, 76.047493 }, + { 53.284317, -19.360411, 59.235271 }, + { 52.859161, -18.252472, 44.039158 }, + { 51.767754, -18.063086, 28.789248 }, + { 51.092236, -19.359201, 15.909953 }, + { 51.309685, -19.108953, 4.747419 }, + { 47.998795, -17.938093, -10.139971 }, + { 50.830948, -12.553975, -16.718109 }, + { 49.399464, -10.220109, -27.653168 }, + { 50.038750, -6.498425, -35.645332 }, + { 50.813366, -2.248663, -42.617889 }, + { 51.190628, 1.470468, -50.086159 }, + { 51.287117, 4.893336, -56.851318 }, + { 51.798454, 6.241453, -62.064316 }, + { 52.865971, 10.077030, -68.116974 }, + { 53.933735, 13.956697, -74.051910 } + }, + { + { 57.278793, -29.996033, 91.362312 }, + { 57.595490, -29.353128, 78.487595 }, + { 56.548031, -29.083374, 64.151001 }, + { 56.800190, -27.309122, 50.746315 }, + { 55.671963, -28.065762, 35.564526 }, + { 55.603096, -29.264875, 22.556105 }, + { 56.040783, -26.968807, 12.175274 }, + { 56.549759, -23.928793, 3.228627 }, + { 56.381752, -21.431168, -6.146933 }, + { 53.510220, -20.475225, -20.143126 }, + { 53.807690, -18.992413, -28.675516 }, + { 53.932957, -13.806589, -37.128368 }, + { 54.572479, -8.528724, -44.745586 }, + { 55.340500, -4.466234, -51.506386 }, + { 55.806858, -2.130621, -57.296227 }, + { 56.238010, 0.206538, -63.146770 }, + { 56.781776, 2.631722, -68.816124 } + }, + { + { 60.212791, -38.157043, 93.894127 }, + { 59.004967, -39.748547, 79.028137 }, + { 58.427048, -40.548615, 65.431190 }, + { 59.221722, -38.578388, 53.908398 }, + { 59.586029, -37.849182, 41.343948 }, + { 59.799694, -36.591976, 29.293777 }, + { 59.291435, -34.919460, 17.853476 }, + { 58.275642, -36.011017, 7.267899 }, + { 60.265091, -30.709497, 0.247331 }, + { 59.653801, -30.008652, -9.740839 }, + { 59.087433, -28.004183, -19.368567 }, + { 58.680794, -24.212685, -29.286285 }, + { 58.550449, -20.458855, -37.477718 }, + { 58.685211, -14.988180, -45.839081 }, + { 59.020531, -12.147471, -52.348736 }, + { 59.427055, -11.565362, -57.178921 }, + { 59.587574, -9.141247, -63.458073 } + }, + { + { 63.315788, -45.372917, 97.079887 }, + { 63.099751, -45.481800, 83.646675 }, + { 63.585030, -44.479496, 71.680115 }, + { 63.068180, -44.278141, 59.714535 }, + { 62.633015, -44.269203, 46.813416 }, + { 63.245644, -43.209255, 35.463478 }, + { 63.679813, -42.955791, 24.872061 }, + { 63.271400, -43.164673, 14.665695 }, + { 63.838238, -39.826969, 6.392663 }, + { 63.758541, -38.443390, -3.218791 }, + { 63.482910, -36.972061, -11.727401 }, + { 62.978607, -35.370350, -20.505636 }, + { 63.149059, -31.396929, -29.225237 }, + { 62.998783, -25.412037, -38.398453 }, + { 62.322979, -22.435949, -46.714252 }, + { 62.676662, -22.004869, -51.924206 }, + { 62.472496, -18.974174, -59.202522 } + }, + { + { 66.727013, -51.684471, 101.039932 }, + { 66.915131, -50.924301, 89.036179 }, + { 67.312553, -49.562649, 78.232300 }, + { 66.663849, -49.511826, 67.176437 }, + { 66.378036, -50.605595, 53.681393 }, + { 66.782310, -52.288750, 40.949615 }, + { 67.075287, -51.863510, 29.986593 }, + { 67.123009, -50.016556, 20.334219 }, + { 67.288368, -48.043816, 11.399524 }, + { 67.600922, -46.212494, 3.443305 }, + { 67.702530, -43.942688, -5.053601 }, + { 68.360260, -38.839802, -13.463100 }, + { 67.141891, -37.584736, -23.018967 }, + { 67.372765, -32.761574, -30.968979 }, + { 67.119713, -29.720833, -38.626038 }, + { 66.268898, -27.902147, -47.089046 }, + { 65.653641, -26.151730, -55.370129 } + }, + { + { 70.157761, -57.683495, 105.225723 }, + { 70.603485, -56.339458, 95.604836 }, + { 71.120544, -55.151386, 85.902641 }, + { 70.669182, -55.372387, 74.110443 }, + { 70.499992, -55.596012, 60.884842 }, + { 70.960480, -56.113686, 48.242031 }, + { 71.402176, -56.476109, 37.868240 }, + { 70.765244, -57.556717, 26.975601 }, + { 69.452194, -56.416542, 15.655796 }, + { 72.205505, -50.394650, 10.199559 }, + { 71.931602, -48.606647, 1.898732 }, + { 73.358589, -42.764797, -5.475290 }, + { 74.662239, -38.167072, -11.675998 }, + { 74.991783, -35.064121, -18.997124 }, + { 75.729797, -31.499870, -26.314262 }, + { 72.530235, -31.468716, -38.081955 }, + { 70.526352, -32.228596, -48.052589 } + }, + { + { 73.339386, -63.998039, 108.680710 }, + { 73.887604, -62.997318, 100.061432 }, + { 74.250603, -62.723984, 90.515717 }, + { 73.769081, -64.852234, 76.661537 }, + { 73.646591, -63.142246, 65.080475 }, + { 74.361557, -60.211227, 55.071903 }, + { 74.209061, -63.543308, 43.109047 }, + { 72.934677, -68.210411, 31.723492 }, + { 74.992676, -60.315441, 25.229677 }, + { 79.832428, -50.438061, 20.208681 }, + { 79.212708, -48.704678, 11.497374 }, + { 79.745895, -46.614990, 5.354442 }, + { 80.518555, -42.293221, -1.566539 }, + { 80.085915, -39.695698, -10.191355 }, + { 79.846909, -37.609840, -18.691387 }, + { 77.949371, -36.555855, -28.991995 }, + { 76.734062, -36.538002, -38.172523 } + }, + { + { 76.081223, -70.962761, 110.857964 }, + { 76.697250, -70.601242, 101.592163 }, + { 77.096176, -70.682861, 91.567146 }, + { 76.821465, -72.101791, 79.476425 }, + { 76.024773, -72.729843, 67.772774 }, + { 76.061890, -71.715088, 57.817734 }, + { 74.789223, -76.237091, 45.615170 }, + { 75.233315, -76.382713, 36.456875 }, + { 80.793495, -64.058350, 33.035873 }, + { 81.899826, -58.736763, 25.090233 }, + { 81.874596, -55.450092, 16.450014 }, + { 82.644653, -53.089642, 9.954061 }, + { 83.346725, -49.019512, 3.234946 }, + { 84.505264, -44.770443, -3.093738 }, + { 84.202934, -42.485233, -11.314644 }, + { 82.894844, -41.687126, -20.890644 }, + { 81.710373, -41.419697, -29.928415 } + }, + { + { 78.385612, -78.442879, 111.949028 }, + { 79.202728, -78.550011, 101.807610 }, + { 79.999435, -78.584221, 91.686752 }, + { 80.730247, -78.477043, 81.627617 }, + { 81.612236, -78.358673, 71.448540 }, + { 82.607002, -78.966988, 61.298401 }, + { 81.688698, -80.389427, 51.572922 }, + { 80.565590, -77.204109, 42.361088 }, + { 83.705399, -69.963242, 37.027374 }, + { 83.711266, -67.209167, 29.229139 }, + { 84.959541, -62.762032, 22.041525 }, + { 85.357216, -60.481693, 14.075327 }, + { 85.974571, -54.774204, 7.135396 }, + { 87.237686, -50.729660, 1.827203 }, + { 88.953072, -46.920734, -3.576680 }, + { 88.016342, -45.737972, -12.398099 }, + { 86.422600, -45.679787, -22.154167 } + }, + { + { 80.449974, -86.107094, 112.589050 }, + { 81.609520, -86.546509, 101.744202 }, + { 83.084793, -86.667824, 91.356773 }, + { 85.243141, -86.097946, 81.829498 }, + { 88.044014, -84.572639, 73.202591 }, + { 90.243843, -81.716225, 65.946480 }, + { 90.936996, -77.400291, 60.066841 }, + { 91.922333, -72.233170, 52.722866 }, + { 91.827194, -69.323875, 44.662212 }, + { 91.374817, -68.149353, 36.933880 }, + { 91.791168, -66.457352, 29.612379 }, + { 90.581787, -64.974136, 21.350443 }, + { 90.573715, -60.902378, 14.327712 }, + { 90.455696, -57.884319, 8.153493 }, + { 92.423027, -53.111992, 3.207753 }, + { 93.118599, -49.355648, -4.009439 }, + { 92.228096, -47.949505, -12.833318 } + } + }, + { + { + { 19.034538, 55.794464, 34.948952 }, + { 16.364002, 58.103600, 14.824910 }, + { 14.978411, 59.943146, -3.686313 }, + { 15.228142, 61.540451, -19.157833 }, + { 16.368336, 62.957863, -31.547512 }, + { 17.940754, 64.226303, -41.273922 }, + { 19.133850, 65.664093, -49.300461 }, + { 19.785538, 67.812225, -56.773735 }, + { 20.419201, 70.342072, -63.625179 }, + { 21.512993, 72.982979, -69.436256 }, + { 22.961273, 75.778709, -74.732178 }, + { 24.608727, 78.567245, -79.911438 }, + { 26.310045, 81.150345, -85.156044 }, + { 28.029253, 83.476852, -90.477081 }, + { 29.705936, 85.605812, -95.892052 }, + { 31.324781, 87.600311, -101.378464 }, + { 32.912258, 89.528053, -106.893532 } + }, + { + { 25.637766, 43.650597, 47.511311 }, + { 23.908987, 45.814251, 28.281658 }, + { 22.173576, 46.702087, 8.280941 }, + { 20.374342, 48.580902, -10.925291 }, + { 20.493999, 51.262077, -25.703995 }, + { 22.859112, 52.881031, -34.276554 }, + { 24.627245, 54.018234, -40.830864 }, + { 23.760069, 56.823330, -49.700420 }, + { 24.295036, 61.013729, -58.503624 }, + { 26.366560, 63.755520, -63.924438 }, + { 27.436979, 65.925674, -69.007477 }, + { 29.057062, 68.310959, -73.932861 }, + { 30.801884, 70.762535, -79.077423 }, + { 32.326939, 73.100006, -84.545082 }, + { 33.659721, 75.276733, -90.219101 }, + { 34.914066, 77.276993, -95.956543 }, + { 36.153072, 79.183182, -101.698036 } + }, + { + { 31.397179, 31.671803, 58.504593 }, + { 32.903469, 32.501293, 42.302139 }, + { 30.229212, 33.371964, 21.114813 }, + { 25.115168, 35.722004, -2.594494 }, + { 25.197536, 39.718399, -19.146631 }, + { 26.543022, 42.788349, -28.220964 }, + { 28.291285, 45.216618, -35.386833 }, + { 26.791779, 46.740726, -44.039734 }, + { 28.063614, 51.377735, -52.672909 }, + { 30.706631, 54.243633, -58.392223 }, + { 31.800362, 55.691536, -63.118969 }, + { 33.470570, 57.679226, -67.809235 }, + { 35.408337, 60.158665, -72.786072 }, + { 36.597713, 62.687595, -78.578880 }, + { 37.539906, 64.933517, -84.576653 }, + { 38.457817, 66.928490, -90.560120 }, + { 39.397640, 68.851326, -96.516106 } + }, + { + { 35.878220, 20.646679, 67.145386 }, + { 37.707504, 21.441824, 51.276245 }, + { 35.554138, 22.450064, 30.932764 }, + { 32.582787, 23.835394, 9.393064 }, + { 31.874016, 28.164154, -8.197860 }, + { 31.638256, 30.673218, -18.814413 }, + { 32.443333, 35.006386, -29.455605 }, + { 32.377281, 39.268459, -39.317455 }, + { 33.628193, 42.296780, -46.390018 }, + { 34.784653, 44.154736, -52.516151 }, + { 37.050705, 45.330704, -56.380844 }, + { 37.913906, 47.092381, -61.759678 }, + { 39.911476, 49.424446, -66.459373 }, + { 40.612167, 52.328335, -72.753883 }, + { 41.213676, 54.471664, -79.034843 }, + { 41.899868, 56.479126, -85.220016 }, + { 42.658848, 58.599937, -91.369270 } + }, + { + { 39.983021, 10.695342, 74.183853 }, + { 40.389122, 11.438374, 56.764015 }, + { 40.278191, 12.168593, 39.054417 }, + { 40.741940, 14.248710, 23.551594 }, + { 40.540440, 16.802883, 9.731924 }, + { 39.036728, 18.515253, -6.079650 }, + { 37.290527, 20.962702, -21.111143 }, + { 38.325661, 29.493248, -32.625290 }, + { 39.297592, 33.670559, -41.677322 }, + { 39.181965, 33.071377, -46.447071 }, + { 40.070782, 34.722969, -51.698265 }, + { 41.419918, 38.668949, -57.341656 }, + { 43.264160, 41.110958, -61.649216 }, + { 44.075577, 42.203278, -67.416336 }, + { 44.576828, 43.669239, -73.664536 }, + { 45.201488, 45.912556, -79.985176 }, + { 45.946129, 48.560841, -86.287079 } + }, + { + { 45.110703, 2.248554, 81.526428 }, + { 45.094456, 3.106265, 63.997684 }, + { 44.808941, 3.914896, 46.227791 }, + { 44.850704, 4.608475, 30.822945 }, + { 44.098549, 3.359068, 17.158653 }, + { 43.563175, 6.191427, 1.975811 }, + { 43.298908, 10.351061, -10.252332 }, + { 44.656372, 18.575195, -23.918438 }, + { 44.914127, 24.480682, -36.442577 }, + { 44.403728, 22.583565, -38.765503 }, + { 43.836605, 24.790651, -46.221653 }, + { 45.619324, 30.019415, -51.759789 }, + { 46.971828, 31.929829, -56.554600 }, + { 47.176918, 31.279234, -62.335007 }, + { 47.608677, 32.709064, -68.614906 }, + { 48.364510, 35.550800, -74.966301 }, + { 49.233265, 38.809242, -81.295296 } + }, + { + { 50.768288, -5.050275, 88.487762 }, + { 50.575573, -4.071877, 71.884186 }, + { 49.481644, -4.196733, 54.215614 }, + { 48.749962, -4.030553, 37.302940 }, + { 48.785107, -3.340346, 23.935827 }, + { 48.855339, -1.853385, 11.751066 }, + { 48.993690, 0.021251, 0.605007 }, + { 48.553944, 2.686957, -9.857680 }, + { 48.838802, 6.442230, -20.326260 }, + { 48.668530, 9.689689, -30.293995 }, + { 49.055107, 14.929786, -38.937824 }, + { 50.078220, 19.153624, -45.429287 }, + { 49.999973, 19.920715, -51.724533 }, + { 50.009060, 19.764284, -57.575279 }, + { 50.622787, 22.544392, -63.929756 }, + { 51.514313, 25.805288, -70.179893 }, + { 52.429684, 29.165018, -76.390930 } + }, + { + { 55.814316, -12.392011, 93.976334 }, + { 56.748859, -10.479889, 80.491920 }, + { 55.234360, -11.448774, 63.695190 }, + { 54.576397, -11.194774, 47.053570 }, + { 54.171432, -10.267787, 32.849602 }, + { 52.932232, -10.657630, 19.255049 }, + { 52.517433, -9.600789, 5.858270 }, + { 52.084057, -7.134286, -6.068578 }, + { 52.437912, -3.186725, -16.269077 }, + { 51.846226, -1.206105, -24.724976 }, + { 52.818493, 2.430471, -32.073601 }, + { 53.117512, 6.443723, -39.964607 }, + { 52.766762, 9.943978, -48.013859 }, + { 53.237747, 11.837888, -53.965569 }, + { 54.051594, 13.957688, -59.391029 }, + { 54.735020, 16.522703, -65.458855 }, + { 55.421703, 19.285957, -71.546295 } + }, + { + { 59.343079, -20.708681, 97.233299 }, + { 58.561954, -20.843771, 82.432648 }, + { 58.476631, -20.357260, 68.216339 }, + { 59.019650, -18.774920, 53.893761 }, + { 58.218365, -18.865339, 39.337605 }, + { 57.135437, -19.807945, 25.954597 }, + { 57.974518, -18.707443, 15.619370 }, + { 56.074230, -17.231468, 1.534578 }, + { 56.833965, -14.189935, -6.744204 }, + { 56.360798, -11.097221, -17.558916 }, + { 56.422791, -8.162517, -26.120060 }, + { 56.410633, -5.505872, -34.068989 }, + { 56.878216, -1.162407, -41.717491 }, + { 57.146675, 2.665321, -48.798553 }, + { 57.698128, 5.263307, -54.458138 }, + { 57.953121, 7.230540, -60.628830 }, + { 58.209221, 9.111048, -66.755936 } + }, + { + { 62.316898, -28.838322, 99.773705 }, + { 61.188629, -30.237556, 85.271873 }, + { 60.759773, -30.988791, 71.139969 }, + { 61.000927, -29.970963, 57.475483 }, + { 60.881268, -29.331371, 44.063683 }, + { 61.727345, -26.717340, 32.827011 }, + { 61.475941, -26.659370, 21.707800 }, + { 59.838245, -26.525032, 7.872996 }, + { 58.841309, -24.854527, -4.024179 }, + { 59.949078, -21.307909, -11.518022 }, + { 59.507740, -18.471682, -20.809664 }, + { 60.005253, -15.275764, -28.216574 }, + { 60.238861, -11.916437, -35.798866 }, + { 60.675217, -7.837579, -43.081284 }, + { 61.076870, -4.169600, -49.635635 }, + { 61.175632, -2.437851, -55.479408 }, + { 60.930439, -1.063104, -62.109695 } + }, + { + { 65.253036, -36.277145, 102.228401 }, + { 65.101768, -36.822308, 88.998779 }, + { 65.519981, -37.201759, 76.197403 }, + { 64.542717, -37.765728, 62.036121 }, + { 64.753998, -35.815063, 50.234329 }, + { 66.075882, -33.403553, 39.371235 }, + { 65.654053, -34.805984, 28.434584 }, + { 66.214706, -33.470554, 18.796627 }, + { 65.757439, -31.742125, 8.323832 }, + { 63.766048, -30.287333, -4.343806 }, + { 64.362221, -28.657085, -11.382602 }, + { 64.483994, -25.901878, -19.618805 }, + { 63.922359, -22.708250, -29.124546 }, + { 63.937370, -18.338228, -37.555687 }, + { 64.341713, -14.491919, -44.422600 }, + { 64.522034, -12.718247, -50.273609 }, + { 63.746719, -10.822021, -57.943398 } + }, + { + { 68.401512, -43.033588, 105.125870 }, + { 68.229492, -43.457859, 92.010963 }, + { 68.226418, -44.492371, 78.854156 }, + { 67.673477, -45.528591, 66.349808 }, + { 67.996300, -45.662132, 53.851776 }, + { 68.845360, -44.767254, 43.457607 }, + { 68.681702, -44.091946, 32.960941 }, + { 68.984657, -41.746349, 23.167225 }, + { 68.365295, -40.403076, 12.346539 }, + { 68.016907, -39.719330, 2.844789 }, + { 67.309746, -38.367863, -7.057399 }, + { 66.805428, -34.925072, -16.713654 }, + { 67.226288, -31.154984, -24.277145 }, + { 67.235596, -28.142117, -31.699152 }, + { 67.349289, -24.671150, -38.951714 }, + { 67.642509, -21.447685, -45.630360 }, + { 67.012184, -19.413673, -53.699406 } + }, + { + { 71.619850, -49.550117, 108.266876 }, + { 71.664024, -49.140591, 97.460770 }, + { 71.628258, -49.070004, 86.416878 }, + { 71.856743, -49.380020, 74.806923 }, + { 72.898109, -53.547604, 60.088757 }, + { 72.376595, -53.429237, 47.817993 }, + { 72.655098, -50.427139, 39.144192 }, + { 72.289902, -49.253124, 29.103632 }, + { 71.444923, -48.455791, 17.656567 }, + { 72.333679, -45.416859, 9.867221 }, + { 72.690231, -42.908115, 1.833045 }, + { 70.680412, -42.450439, -9.026088 }, + { 73.039017, -36.749905, -14.549061 }, + { 73.769310, -33.306480, -20.791410 }, + { 73.830444, -29.621799, -28.532333 }, + { 73.152603, -27.669134, -36.858570 }, + { 71.290840, -27.131208, -46.962791 } + }, + { + { 74.675369, -56.106964, 111.042473 }, + { 75.104424, -55.227757, 102.179802 }, + { 75.587578, -54.177773, 93.462845 }, + { 75.854820, -54.380871, 82.191551 }, + { 76.287018, -59.198933, 66.871620 }, + { 75.885658, -60.639656, 53.513985 }, + { 76.099731, -59.593281, 43.456913 }, + { 77.040909, -57.152187, 36.017582 }, + { 77.512909, -53.455868, 27.884350 }, + { 79.338860, -48.051392, 20.505379 }, + { 78.952698, -45.339073, 12.150318 }, + { 79.981804, -42.740562, 6.085728 }, + { 81.304138, -38.505394, -0.448045 }, + { 79.944954, -37.030148, -10.249756 }, + { 79.646805, -34.235149, -18.893562 }, + { 78.712997, -32.663376, -27.741959 }, + { 76.741478, -32.847225, -38.014332 } + }, + { + { 77.424110, -62.781876, 113.017448 }, + { 77.951607, -62.366570, 103.788269 }, + { 78.552017, -61.390537, 95.062790 }, + { 79.157524, -59.445004, 86.797096 }, + { 78.880409, -60.003654, 74.506676 }, + { 78.536636, -63.765354, 59.810024 }, + { 76.438141, -69.096298, 47.922573 }, + { 78.641525, -66.432434, 40.977886 }, + { 82.136841, -58.822517, 34.968971 }, + { 81.029907, -55.898121, 25.140202 }, + { 82.337349, -51.399994, 17.794121 }, + { 82.798393, -48.785885, 10.959743 }, + { 84.166954, -44.519974, 4.702731 }, + { 85.028137, -41.201061, -2.253874 }, + { 84.129318, -39.229931, -11.266446 }, + { 83.770622, -37.274479, -19.627340 }, + { 81.847282, -37.532425, -29.627520 } + }, + { + { 79.823341, -69.481667, 114.218529 }, + { 80.410217, -69.972710, 103.765884 }, + { 81.065506, -70.241806, 93.614441 }, + { 81.887428, -70.864899, 83.559540 }, + { 82.943222, -74.090668, 71.838806 }, + { 83.920197, -75.713737, 61.804726 }, + { 82.514877, -75.313293, 53.665710 }, + { 82.156662, -71.323807, 45.655216 }, + { 84.309113, -65.377769, 39.727234 }, + { 84.123695, -63.244267, 30.381268 }, + { 87.414291, -57.008141, 24.116892 }, + { 86.232857, -54.681206, 15.489945 }, + { 87.288055, -48.955585, 9.400198 }, + { 88.370819, -46.891762, 3.649668 }, + { 89.228233, -44.043232, -2.811900 }, + { 88.959892, -41.457874, -11.221086 }, + { 87.201599, -41.212635, -21.119699 } + }, + { + { 81.997658, -76.195587, 114.969208 }, + { 82.749046, -77.929733, 103.171219 }, + { 83.764786, -79.703285, 91.747421 }, + { 85.404968, -81.244576, 81.457756 }, + { 87.772072, -81.333069, 73.380363 }, + { 90.320923, -78.005852, 67.875320 }, + { 92.257042, -72.102859, 62.349037 }, + { 93.016663, -67.758835, 55.109409 }, + { 91.541061, -66.873718, 46.264114 }, + { 91.507996, -65.057701, 37.804356 }, + { 91.923897, -62.007954, 30.423775 }, + { 91.376053, -59.447937, 22.684221 }, + { 91.890686, -54.599739, 15.924855 }, + { 92.590393, -51.712933, 10.484353 }, + { 93.270569, -49.100937, 4.310921 }, + { 93.210564, -46.606762, -3.538566 }, + { 92.558090, -44.673969, -12.221533 } + } + }, + { + { + { 21.242029, 58.671375, 38.098557 }, + { 18.647627, 61.062901, 18.032415 }, + { 17.384050, 63.144939, -0.116550 }, + { 17.881090, 64.812630, -14.735127 }, + { 19.246916, 66.370872, -26.285084 }, + { 20.606205, 68.120636, -36.358562 }, + { 21.605947, 69.790100, -44.856079 }, + { 22.260300, 71.571075, -52.407757 }, + { 22.543472, 73.622055, -59.588966 }, + { 22.992462, 75.803558, -66.020462 }, + { 24.134348, 78.273117, -71.793991 }, + { 25.692661, 80.746513, -77.259293 }, + { 27.395988, 83.047638, -82.614357 }, + { 29.169426, 85.233719, -87.934006 }, + { 30.973192, 87.398300, -93.277359 }, + { 32.774101, 89.565758, -98.668983 }, + { 34.564594, 91.730377, -104.090652 } + }, + { + { 28.160099, 47.325104, 50.999489 }, + { 26.019794, 49.413723, 31.407772 }, + { 24.892672, 51.274521, 12.257419 }, + { 23.468517, 53.559879, -6.060460 }, + { 23.021708, 55.756550, -20.385765 }, + { 25.145407, 57.745842, -29.628597 }, + { 26.490824, 59.070049, -36.983669 }, + { 27.137503, 60.489708, -44.263737 }, + { 26.302504, 63.294746, -53.221188 }, + { 26.790834, 65.378441, -60.101406 }, + { 28.574263, 68.259323, -66.075058 }, + { 30.250381, 70.702194, -71.437233 }, + { 31.915974, 73.070251, -76.631256 }, + { 33.530727, 75.494728, -81.982262 }, + { 35.036251, 77.852379, -87.550453 }, + { 36.453259, 80.067123, -93.252998 }, + { 37.833668, 82.193054, -99.001305 } + }, + { + { 33.554668, 36.915577, 61.870712 }, + { 34.309090, 38.212025, 45.205563 }, + { 33.856224, 39.290562, 26.528578 }, + { 28.900831, 42.566284, 3.218098 }, + { 25.501646, 45.409241, -15.838064 }, + { 29.217695, 47.863663, -23.251318 }, + { 31.112864, 49.066174, -30.186045 }, + { 30.977709, 50.358910, -38.372158 }, + { 29.657990, 53.031097, -47.359570 }, + { 31.485401, 55.800301, -54.346237 }, + { 33.068371, 58.360245, -60.648987 }, + { 34.596367, 60.502396, -65.737137 }, + { 36.356537, 63.099133, -70.633728 }, + { 37.861309, 65.866928, -76.036758 }, + { 39.058708, 68.366692, -81.862778 }, + { 40.096706, 70.560654, -87.872025 }, + { 41.093704, 72.621582, -93.923767 } + }, + { + { 37.631844, 27.151466, 70.215889 }, + { 39.374569, 28.387907, 54.712559 }, + { 40.665386, 29.310165, 38.567337 }, + { 39.091789, 32.162636, 19.057812 }, + { 33.122265, 34.506943, -3.452259 }, + { 34.194519, 36.512756, -14.084903 }, + { 35.486877, 38.634224, -23.721954 }, + { 36.768326, 41.919216, -33.348000 }, + { 35.304928, 44.849251, -42.807331 }, + { 35.501369, 47.308628, -50.826782 }, + { 36.742149, 48.407349, -56.209133 }, + { 38.532288, 50.533291, -60.371990 }, + { 40.647114, 53.656147, -64.785126 }, + { 42.049316, 56.582573, -70.252831 }, + { 42.930984, 58.934212, -76.321739 }, + { 43.644428, 60.997330, -82.579468 }, + { 44.350410, 63.019669, -88.862709 } + }, + { + { 41.484703, 17.848423, 77.217911 }, + { 42.091267, 19.295946, 60.127544 }, + { 44.078068, 19.885513, 45.134167 }, + { 42.615669, 20.983412, 28.602468 }, + { 42.385139, 23.546741, 12.655882 }, + { 41.214184, 25.043404, -2.248081 }, + { 39.008373, 27.058624, -18.565428 }, + { 39.756699, 33.021885, -30.767305 }, + { 38.576279, 36.716064, -40.567459 }, + { 38.900669, 38.334751, -47.433235 }, + { 40.040981, 39.242519, -52.223373 }, + { 42.471882, 42.180080, -55.344372 }, + { 44.723232, 45.572132, -59.440186 }, + { 45.887459, 47.680908, -64.920418 }, + { 46.511482, 49.432243, -71.077599 }, + { 47.050900, 51.360546, -77.432007 }, + { 47.626747, 53.472958, -83.814980 } + }, + { + { 46.629177, 9.286631, 84.991302 }, + { 47.536926, 10.426832, 68.371994 }, + { 48.262432, 11.442033, 51.862564 }, + { 47.727455, 11.976811, 35.366844 }, + { 48.360130, 12.912247, 23.065294 }, + { 48.278000, 14.161425, 9.645643 }, + { 46.968796, 18.885843, -6.229538 }, + { 45.802811, 23.570934, -21.530659 }, + { 45.157482, 26.526829, -31.566513 }, + { 45.304302, 28.037117, -37.405842 }, + { 45.320866, 30.874302, -44.405468 }, + { 47.093616, 34.587269, -49.346748 }, + { 48.509266, 37.338547, -54.492310 }, + { 49.184460, 38.532124, -60.251282 }, + { 49.755146, 39.851692, -66.252052 }, + { 50.337341, 41.817764, -72.478477 }, + { 50.920570, 44.089161, -78.794876 } + }, + { + { 52.327404, 1.802078, 92.670486 }, + { 53.001522, 2.329279, 77.158562 }, + { 53.204021, 3.344283, 60.727524 }, + { 51.319820, 3.588214, 41.814999 }, + { 50.766422, 3.683778, 27.702496 }, + { 50.640182, 2.594172, 15.483907 }, + { 50.563999, 7.428292, 1.673794 }, + { 50.089275, 9.562977, -10.138584 }, + { 50.497021, 13.280174, -17.714634 }, + { 51.031116, 18.112179, -26.937054 }, + { 51.325336, 21.996506, -35.493187 }, + { 51.915714, 25.330851, -42.613907 }, + { 51.227753, 27.574192, -50.714199 }, + { 51.836750, 28.872726, -56.398212 }, + { 52.879021, 30.493879, -61.778431 }, + { 53.587551, 32.616161, -67.734238 }, + { 54.146904, 34.862396, -73.869865 } + }, + { + { 57.284794, -5.278331, 98.610481 }, + { 57.032101, -4.934063, 83.353409 }, + { 57.094711, -4.635664, 67.874748 }, + { 56.178959, -4.147811, 50.049759 }, + { 55.962509, -4.079034, 35.934227 }, + { 55.257557, -5.197304, 23.146034 }, + { 54.064556, -3.825206, 9.126607 }, + { 54.695000, -0.865704, 0.207445 }, + { 53.968987, 2.434925, -11.982265 }, + { 55.206306, 7.193859, -20.409134 }, + { 55.066467, 10.054757, -28.813541 }, + { 55.527798, 13.679075, -36.600159 }, + { 55.350292, 17.552004, -45.290127 }, + { 55.423244, 19.608093, -51.867664 }, + { 56.278778, 21.845955, -57.428432 }, + { 56.777424, 23.800512, -63.245808 }, + { 57.164280, 25.672028, -69.166397 } + }, + { + { 61.348145, -12.792622, 102.753555 }, + { 60.585163, -13.113472, 87.616287 }, + { 60.591133, -12.830815, 72.975365 }, + { 60.237778, -12.109795, 56.711536 }, + { 59.438137, -12.170056, 41.843189 }, + { 58.868591, -11.764441, 29.086685 }, + { 58.954758, -10.545603, 17.329546 }, + { 59.286163, -8.923271, 7.000441 }, + { 59.209194, -6.253306, -3.026552 }, + { 57.202347, -5.684169, -15.364072 }, + { 58.140430, -1.104546, -23.588757 }, + { 58.732765, 3.008621, -31.326845 }, + { 59.298618, 6.459970, -38.505230 }, + { 59.259373, 10.419160, -46.564499 }, + { 59.969501, 13.427204, -52.779766 }, + { 59.865910, 15.085155, -58.897873 }, + { 59.930660, 16.467985, -64.799461 } + }, + { + { 64.571938, -20.414406, 105.474457 }, + { 63.823742, -21.180201, 91.091072 }, + { 63.475163, -21.898968, 76.391747 }, + { 63.631329, -21.603689, 62.269020 }, + { 63.063156, -21.495016, 47.801426 }, + { 62.904209, -20.158907, 35.562962 }, + { 62.356571, -19.493986, 22.427639 }, + { 60.614029, -18.859890, 7.762762 }, + { 61.606037, -16.002468, -0.330170 }, + { 61.721420, -14.054977, -7.763490 }, + { 62.360989, -10.565592, -15.871692 }, + { 62.159966, -6.795721, -25.539904 }, + { 62.385567, -3.662393, -33.211739 }, + { 62.847805, -0.156859, -40.293259 }, + { 63.086555, 3.599843, -47.608971 }, + { 62.886959, 6.105682, -54.428730 }, + { 62.516216, 7.198389, -60.773129 } + }, + { + { 67.370102, -27.890945, 107.281158 }, + { 66.801949, -28.759846, 93.201973 }, + { 66.847496, -29.263878, 79.863228 }, + { 66.537254, -29.865034, 65.750175 }, + { 66.699570, -28.858755, 53.091068 }, + { 67.526878, -28.031555, 42.132118 }, + { 67.196732, -27.721407, 30.390858 }, + { 65.963554, -26.954388, 17.482035 }, + { 64.997421, -25.368252, 5.990734 }, + { 66.443687, -22.278423, -0.222201 }, + { 66.511055, -19.624739, -8.691319 }, + { 65.689308, -16.692709, -19.206881 }, + { 65.552589, -14.249682, -27.432945 }, + { 65.646881, -11.188313, -34.888599 }, + { 66.312065, -7.097910, -41.563492 }, + { 66.546188, -3.550147, -48.871326 }, + { 65.036598, -2.342919, -56.819710 } + }, + { + { 70.284592, -34.959034, 109.300621 }, + { 69.934280, -35.941544, 95.848381 }, + { 69.668602, -37.073154, 82.692444 }, + { 69.531555, -37.602551, 69.632980 }, + { 69.557518, -37.017860, 57.057098 }, + { 69.678314, -36.779480, 46.351070 }, + { 70.017189, -35.734451, 35.509880 }, + { 68.727066, -35.416698, 22.292242 }, + { 67.258568, -34.491596, 8.648561 }, + { 67.377548, -32.448418, -0.390660 }, + { 67.648712, -29.634050, -8.075483 }, + { 67.904884, -27.159584, -15.782437 }, + { 69.268074, -24.051737, -21.209251 }, + { 68.983910, -21.200445, -29.228401 }, + { 69.107407, -17.749487, -36.544437 }, + { 69.294472, -14.446359, -43.637066 }, + { 68.978302, -12.017539, -51.110981 } + }, + { + { 73.295776, -41.757282, 111.643776 }, + { 73.178070, -42.229801, 99.787338 }, + { 73.176399, -42.509007, 88.322556 }, + { 73.220940, -42.762104, 76.166527 }, + { 74.001389, -44.869343, 62.483299 }, + { 74.152733, -44.661430, 51.580173 }, + { 73.242607, -44.266392, 40.055641 }, + { 72.598053, -43.567532, 28.820049 }, + { 72.069466, -41.575771, 17.815071 }, + { 71.276161, -40.211803, 7.926930 }, + { 74.748993, -34.960556, 4.472855 }, + { 72.539246, -35.028469, -7.234648 }, + { 71.393669, -33.222916, -17.150360 }, + { 71.895073, -30.876669, -23.597635 }, + { 72.865738, -26.019325, -30.249760 }, + { 72.978180, -23.076387, -37.171936 }, + { 72.448273, -21.187256, -45.189518 } + }, + { + { 76.268997, -48.267338, 113.956642 }, + { 76.404617, -48.392010, 103.506950 }, + { 76.655983, -48.175571, 93.236366 }, + { 77.156288, -47.897129, 82.560661 }, + { 77.929756, -50.838455, 69.002388 }, + { 78.011848, -53.012993, 56.907211 }, + { 77.508446, -53.215729, 45.461388 }, + { 77.338142, -51.139069, 36.118961 }, + { 78.343010, -47.660637, 28.996298 }, + { 78.604568, -44.192097, 20.960020 }, + { 78.647751, -41.680622, 12.572932 }, + { 78.267715, -39.962353, 3.714340 }, + { 79.602531, -36.008438, -3.624578 }, + { 79.491158, -34.046913, -11.405669 }, + { 79.390190, -30.727394, -19.692642 }, + { 78.512543, -28.835051, -28.154161 }, + { 76.821075, -28.360714, -37.807793 } + }, + { + { 79.047768, -54.490494, 115.745613 }, + { 79.144638, -55.025524, 104.663322 }, + { 79.190651, -55.194351, 93.730804 }, + { 79.135262, -54.645302, 83.622658 }, + { 79.197716, -54.700108, 71.979736 }, + { 80.176918, -58.787758, 59.897488 }, + { 81.087730, -60.190338, 52.194035 }, + { 81.398781, -57.981262, 43.120155 }, + { 81.488731, -55.129032, 34.821140 }, + { 81.614937, -51.054920, 27.139435 }, + { 83.484871, -46.915684, 19.871271 }, + { 84.229149, -43.385658, 12.720697 }, + { 84.368881, -39.974163, 4.824435 }, + { 85.499924, -37.493015, -1.447459 }, + { 84.661186, -35.067036, -10.603116 }, + { 84.544670, -32.800446, -18.609152 }, + { 82.748039, -32.662365, -28.423271 } + }, + { + { 81.519875, -60.459637, 116.841370 }, + { 81.679306, -61.843075, 104.984886 }, + { 81.758881, -63.137207, 93.079506 }, + { 81.840530, -64.978241, 81.191833 }, + { 82.012329, -69.482971, 68.575485 }, + { 82.618713, -70.032394, 60.183876 }, + { 83.602577, -68.091011, 55.778343 }, + { 86.454384, -60.310925, 51.464279 }, + { 86.684235, -58.978699, 42.726753 }, + { 86.097260, -57.932060, 32.424545 }, + { 88.425446, -52.446751, 25.665751 }, + { 86.711029, -50.700222, 17.922495 }, + { 87.985931, -44.506031, 11.076668 }, + { 89.226700, -42.720467, 5.047579 }, + { 89.738144, -39.808197, -2.052273 }, + { 89.565056, -37.388283, -10.161007 }, + { 88.032379, -36.722309, -19.753677 } + }, + { + { 83.768600, -66.312790, 117.458328 }, + { 84.171097, -68.960510, 104.973923 }, + { 84.767227, -71.800385, 92.891197 }, + { 85.964455, -74.417236, 82.369057 }, + { 88.090744, -74.942284, 75.171806 }, + { 90.656822, -70.907486, 71.467339 }, + { 91.542969, -66.114624, 64.949585 }, + { 91.169067, -62.752789, 57.172794 }, + { 90.331917, -63.507023, 48.111320 }, + { 91.320129, -61.139301, 38.716896 }, + { 91.736877, -58.372959, 31.098906 }, + { 90.878334, -56.562820, 24.001402 }, + { 92.605667, -50.709686, 18.063587 }, + { 93.827560, -46.625515, 12.816621 }, + { 93.953003, -44.499645, 5.404109 }, + { 93.627007, -42.893295, -2.932820 }, + { 93.252998, -40.807869, -11.335409 } + } + }, + { + { + { 22.233261, 61.381172, 39.479225 }, + { 20.198397, 63.924400, 20.139065 }, + { 19.627892, 66.257126, 2.815093 }, + { 20.498571, 68.301636, -11.157679 }, + { 21.913271, 70.426727, -22.293200 }, + { 23.056396, 72.671700, -32.405704 }, + { 23.703993, 74.558464, -41.423546 }, + { 24.346081, 75.938698, -49.063305 }, + { 24.446268, 77.298302, -56.154945 }, + { 24.552280, 78.955795, -62.762192 }, + { 25.458206, 80.993027, -68.796196 }, + { 26.927034, 83.097435, -74.499794 }, + { 28.605307, 85.118271, -80.028130 }, + { 30.392344, 87.167679, -85.460312 }, + { 32.267529, 89.345840, -90.862106 }, + { 34.191311, 91.641914, -96.280228 }, + { 36.127720, 93.990158, -101.719139 } + }, + { + { 28.570162, 51.351055, 52.534332 }, + { 25.360645, 53.568565, 31.938477 }, + { 26.346964, 55.918606, 14.319298 }, + { 28.284502, 58.526070, -0.462777 }, + { 27.805767, 60.993305, -13.933685 }, + { 28.379484, 63.370785, -25.069202 }, + { 27.506037, 65.269981, -35.402153 }, + { 28.955416, 66.088608, -42.507286 }, + { 28.962873, 67.471619, -49.825821 }, + { 29.138094, 69.357727, -56.781548 }, + { 30.236502, 71.585403, -63.100613 }, + { 31.606815, 73.637360, -68.793831 }, + { 33.095612, 75.785095, -74.208885 }, + { 34.717506, 78.145042, -79.626488 }, + { 36.356510, 80.577827, -85.192688 }, + { 37.933670, 82.967834, -90.907463 }, + { 39.464222, 85.311043, -96.693001 } + }, + { + { 34.319492, 42.086193, 64.138336 }, + { 32.034039, 43.602032, 44.213921 }, + { 33.464550, 45.513248, 26.925381 }, + { 35.604488, 48.898960, 10.874666 }, + { 32.668076, 51.189701, -6.636473 }, + { 33.344261, 53.361874, -18.051075 }, + { 32.773533, 54.724361, -28.373755 }, + { 33.006004, 56.283436, -36.966995 }, + { 33.578403, 58.478470, -44.281254 }, + { 34.673103, 60.699326, -51.139679 }, + { 34.982040, 62.310772, -57.899696 }, + { 35.921284, 64.066940, -63.347443 }, + { 37.441589, 66.588631, -68.482491 }, + { 39.045647, 69.332336, -73.835190 }, + { 40.448975, 71.926369, -79.568466 }, + { 41.653961, 74.305222, -85.572975 }, + { 42.773987, 76.571022, -91.679810 } + }, + { + { 39.222282, 33.137245, 73.340019 }, + { 39.693985, 34.275482, 56.236320 }, + { 41.435677, 35.373863, 40.599892 }, + { 38.249786, 37.776909, 19.952599 }, + { 35.062637, 40.229534, -0.046389 }, + { 36.410774, 42.405869, -11.448063 }, + { 35.849369, 44.287441, -23.397053 }, + { 35.314289, 46.975845, -33.875404 }, + { 37.911179, 50.380878, -39.853672 }, + { 38.497776, 52.267735, -47.273720 }, + { 38.104523, 51.918911, -53.497929 }, + { 39.546612, 54.399105, -58.250053 }, + { 41.708469, 57.966995, -62.945892 }, + { 43.375595, 60.970959, -68.206551 }, + { 44.473907, 63.444218, -74.100662 }, + { 45.293484, 65.632690, -80.339882 }, + { 46.047390, 67.732201, -86.679283 } + }, + { + { 43.201641, 24.107630, 80.613327 }, + { 44.204460, 25.331579, 64.465843 }, + { 46.970497, 26.054340, 50.712654 }, + { 45.576942, 26.738562, 33.251106 }, + { 45.272930, 28.699244, 16.505136 }, + { 43.042969, 30.846701, 0.168094 }, + { 40.395882, 33.621578, -16.763741 }, + { 39.993198, 36.129471, -27.210968 }, + { 42.103382, 39.888760, -33.707428 }, + { 40.649509, 42.262226, -43.537407 }, + { 40.941959, 41.551731, -48.549530 }, + { 43.516838, 46.235115, -53.285152 }, + { 46.068752, 50.280243, -57.715771 }, + { 47.537148, 52.974899, -62.939068 }, + { 48.275028, 55.024570, -68.931129 }, + { 48.801235, 56.919453, -75.260010 }, + { 49.316280, 58.834873, -81.669891 } + }, + { + { 47.978260, 15.582159, 88.209007 }, + { 50.079704, 16.872740, 73.768509 }, + { 52.091835, 17.563772, 59.540222 }, + { 51.530502, 18.435993, 42.449787 }, + { 49.993176, 20.080406, 26.184364 }, + { 50.076336, 22.357746, 13.321969 }, + { 48.257889, 24.118984, -2.240062 }, + { 48.568836, 25.772430, -11.917989 }, + { 46.760284, 28.183489, -25.117485 }, + { 46.700172, 32.312195, -35.122704 }, + { 46.625889, 36.768620, -43.301342 }, + { 48.034248, 39.775417, -48.420975 }, + { 50.215294, 43.027626, -52.947784 }, + { 51.229824, 45.006981, -58.245960 }, + { 51.775013, 46.536934, -64.129028 }, + { 52.211216, 48.192062, -70.333267 }, + { 52.613571, 49.968334, -76.641083 } + }, + { + { 53.753548, 8.122277, 96.340240 }, + { 55.319729, 9.097333, 81.705681 }, + { 55.302593, 9.595975, 65.565437 }, + { 55.121212, 10.140774, 48.972389 }, + { 52.524338, 9.941346, 32.248936 }, + { 52.609364, 11.375159, 19.462379 }, + { 51.683537, 15.249152, -2.210033 }, + { 51.534546, 17.326174, -9.355920 }, + { 51.682297, 19.257179, -16.302111 }, + { 52.562267, 24.356882, -25.196072 }, + { 52.269657, 27.604280, -34.175968 }, + { 52.751202, 31.859867, -41.851643 }, + { 53.846836, 35.596600, -48.555672 }, + { 54.331005, 37.131241, -54.320820 }, + { 55.128181, 38.039707, -59.649185 }, + { 55.603996, 39.547546, -65.549309 }, + { 55.889103, 41.177044, -71.654099 } + }, + { + { 58.931782, 1.159312, 102.968475 }, + { 58.863579, 1.888667, 86.978142 }, + { 58.837818, 2.166058, 70.462936 }, + { 57.778667, 1.883877, 52.964218 }, + { 56.985661, 1.941160, 37.934387 }, + { 57.557114, 2.774801, 26.876730 }, + { 57.026085, 4.252969, 13.317321 }, + { 57.868412, 7.459407, 3.629254 }, + { 57.458099, 9.231683, -5.239428 }, + { 56.751057, 13.362001, -17.732365 }, + { 57.184921, 17.017202, -25.893906 }, + { 57.767120, 20.867817, -33.364273 }, + { 57.718323, 24.938145, -41.863319 }, + { 57.643055, 28.467964, -50.125111 }, + { 58.541149, 29.686718, -55.437096 }, + { 58.873829, 31.060003, -61.037136 }, + { 59.008057, 32.410419, -66.859680 } + }, + { + { 63.527649, -5.758629, 107.983017 }, + { 63.531952, -5.543822, 93.235039 }, + { 62.144520, -6.247365, 76.149673 }, + { 60.530869, -6.930553, 58.646793 }, + { 60.795319, -6.078186, 44.841484 }, + { 60.858791, -5.352928, 31.605366 }, + { 60.078587, -5.124370, 19.345955 }, + { 59.883236, -2.275414, 8.018429 }, + { 60.457756, 0.446914, -1.498143 }, + { 58.430347, -0.252345, -12.256646 }, + { 60.088848, 6.126780, -20.916039 }, + { 60.496971, 9.614503, -28.690090 }, + { 60.917343, 12.621602, -35.879917 }, + { 61.332394, 16.468441, -43.393448 }, + { 61.638657, 19.904299, -50.528687 }, + { 61.800373, 22.326252, -56.783165 }, + { 61.922401, 23.546492, -62.363914 } + }, + { + { 66.733536, -12.974520, 110.444786 }, + { 66.846176, -13.025797, 96.261993 }, + { 65.804901, -13.963538, 80.160782 }, + { 65.280548, -14.213439, 65.406387 }, + { 65.748093, -13.288476, 52.011677 }, + { 65.205940, -12.603716, 38.763802 }, + { 64.211449, -12.664260, 25.525415 }, + { 63.142174, -11.111007, 12.063438 }, + { 64.455421, -8.470541, 5.360389 }, + { 64.901726, -6.682566, -2.151389 }, + { 64.383232, -3.840443, -12.439588 }, + { 63.865425, -0.456259, -22.792124 }, + { 64.196556, 2.418413, -30.294230 }, + { 64.622604, 5.541286, -37.180096 }, + { 65.053726, 9.630558, -44.773178 }, + { 64.785652, 12.713727, -52.086056 }, + { 64.719673, 14.284692, -57.950775 } + }, + { + { 69.441124, -20.307877, 111.928391 }, + { 68.960007, -20.911278, 97.177589 }, + { 68.519569, -21.589457, 82.686005 }, + { 68.559052, -21.879587, 69.319130 }, + { 68.328018, -21.588833, 56.054169 }, + { 68.472763, -21.588648, 43.937717 }, + { 68.977089, -20.529018, 33.043022 }, + { 66.580429, -19.608747, 18.097511 }, + { 67.302574, -17.899616, 10.019985 }, + { 68.146645, -14.670630, 2.568020 }, + { 67.666664, -12.582806, -7.319764 }, + { 67.159950, -10.729312, -16.678013 }, + { 67.292564, -7.969920, -24.533251 }, + { 67.522354, -4.612776, -31.989208 }, + { 68.029953, -0.681761, -39.071857 }, + { 68.559349, 2.790170, -45.831612 }, + { 67.480522, 4.671145, -53.377098 } + }, + { + { 72.295341, -27.427048, 113.630814 }, + { 71.973038, -28.420502, 99.464806 }, + { 71.834534, -29.383507, 86.315590 }, + { 71.802284, -29.648380, 73.836494 }, + { 71.660423, -28.374796, 61.700375 }, + { 71.117920, -28.770288, 48.920132 }, + { 71.643761, -27.482374, 37.585674 }, + { 69.583511, -27.848612, 22.916515 }, + { 69.402275, -26.464781, 12.241356 }, + { 69.246620, -24.243692, 3.113623 }, + { 70.752937, -21.141960, -2.629330 }, + { 70.807388, -18.947535, -10.493711 }, + { 70.781731, -16.401628, -18.720413 }, + { 70.991722, -13.751744, -26.278454 }, + { 71.118919, -10.520143, -33.650208 }, + { 71.182358, -7.718868, -40.778610 }, + { 71.181076, -5.007509, -47.805679 } + }, + { + { 75.255653, -34.192226, 115.644974 }, + { 74.805656, -35.461979, 101.758919 }, + { 74.756195, -36.408333, 88.922691 }, + { 74.775253, -36.626255, 76.668777 }, + { 74.933594, -37.145245, 64.852432 }, + { 75.588417, -35.251770, 55.312813 }, + { 75.703690, -35.552650, 43.723240 }, + { 74.432663, -35.486477, 30.999527 }, + { 73.899849, -34.006924, 21.478933 }, + { 74.779602, -32.075516, 13.455732 }, + { 74.945999, -28.904444, 5.152813 }, + { 74.616264, -27.451628, -4.136810 }, + { 74.146629, -25.700262, -12.823167 }, + { 73.380035, -23.048746, -22.269676 }, + { 73.888321, -20.173685, -28.822903 }, + { 74.323982, -16.799322, -35.287186 }, + { 74.327019, -14.534536, -42.398872 } + }, + { + { 78.155411, -40.432568, 117.560852 }, + { 77.674973, -41.965279, 103.843941 }, + { 77.396667, -43.495262, 90.178543 }, + { 77.506989, -44.340740, 77.630280 }, + { 78.952820, -43.350033, 68.528534 }, + { 80.205368, -40.659786, 61.251511 }, + { 78.712822, -45.322845, 48.195923 }, + { 78.452530, -43.509773, 37.547520 }, + { 79.359871, -40.659378, 31.292709 }, + { 78.896805, -38.628494, 22.002499 }, + { 78.430237, -36.800537, 11.582246 }, + { 77.490082, -35.263470, 1.531599 }, + { 78.285637, -32.420643, -5.735914 }, + { 78.427818, -29.252731, -13.396750 }, + { 78.534515, -27.192913, -20.773666 }, + { 79.041512, -24.090137, -27.477026 }, + { 77.789467, -22.655169, -36.223515 } + }, + { + { 80.900818, -46.170341, 119.020462 }, + { 80.447113, -48.096798, 105.233818 }, + { 79.673370, -50.137280, 90.297890 }, + { 78.672760, -51.215893, 75.055290 }, + { 79.982841, -48.569492, 67.780472 }, + { 81.867569, -49.797421, 61.560993 }, + { 83.429268, -50.990768, 54.461159 }, + { 83.149651, -50.688873, 44.869415 }, + { 83.130127, -48.314796, 36.928848 }, + { 83.334023, -44.064240, 28.872965 }, + { 83.956894, -42.512016, 20.652357 }, + { 83.937653, -39.665565, 12.847577 }, + { 83.790642, -37.388634, 4.483292 }, + { 86.276627, -32.948952, -0.555250 }, + { 85.559654, -30.826410, -9.389339 }, + { 84.750130, -29.030441, -18.070053 }, + { 83.540894, -27.827675, -27.145737 } + }, + { + { 83.385818, -51.553661, 119.796295 }, + { 83.210884, -53.865250, 106.500748 }, + { 82.742905, -56.247429, 92.609528 }, + { 82.178207, -57.879734, 79.019356 }, + { 82.772232, -56.675144, 70.150162 }, + { 83.929634, -53.881889, 64.247513 }, + { 85.422485, -55.748676, 58.416321 }, + { 87.204887, -54.141254, 51.266396 }, + { 86.343193, -54.563942, 41.913853 }, + { 86.680901, -51.221581, 33.695618 }, + { 88.078972, -47.869335, 26.323996 }, + { 86.294182, -47.491585, 18.853821 }, + { 89.065216, -41.861702, 12.876225 }, + { 90.209305, -38.342556, 6.700346 }, + { 89.695503, -35.994843, -1.864177 }, + { 89.339249, -34.243382, -10.326885 }, + { 88.783401, -32.482193, -18.554493 } + }, + { + { 85.663246, -56.783649, 120.125916 }, + { 86.014824, -59.612011, 107.766663 }, + { 86.504395, -62.625870, 95.927773 }, + { 87.518562, -65.387283, 85.933067 }, + { 89.440727, -66.102829, 79.458260 }, + { 91.395950, -63.295391, 75.694397 }, + { 90.903885, -61.921116, 67.663010 }, + { 90.901787, -57.779095, 58.429546 }, + { 90.735962, -57.958569, 48.656040 }, + { 90.927307, -55.590115, 39.784889 }, + { 92.248032, -52.919529, 32.479084 }, + { 91.169762, -52.561005, 25.822456 }, + { 92.778931, -47.830685, 19.611174 }, + { 94.061996, -43.202812, 13.385343 }, + { 94.418816, -40.111801, 6.190876 }, + { 94.252151, -39.009155, -1.982836 }, + { 93.708244, -37.158936, -10.344365 } + } + }, + { + { + { 23.412098, 65.039368, 41.024754 }, + { 21.611906, 67.490128, 22.104921 }, + { 21.719557, 69.887947, 5.495251 }, + { 23.160534, 72.134003, -7.818851 }, + { 24.599606, 74.461548, -18.707153 }, + { 25.589952, 76.717598, -28.583107 }, + { 26.112144, 78.609192, -37.796562 }, + { 26.707705, 79.982666, -45.644234 }, + { 26.660839, 81.166786, -52.787453 }, + { 26.453346, 82.498672, -59.547722 }, + { 27.118670, 84.115776, -65.785141 }, + { 28.476889, 85.836639, -71.692459 }, + { 30.094322, 87.575020, -77.419708 }, + { 31.841772, 89.464409, -83.039581 }, + { 33.702454, 91.605309, -88.616776 }, + { 35.637428, 93.958122, -94.199394 }, + { 37.598919, 96.407104, -99.797089 } + }, + { + { 29.830727, 56.157654, 55.224014 }, + { 26.407715, 58.094757, 34.014389 }, + { 26.922644, 60.632908, 15.454075 }, + { 29.425444, 62.971958, 1.739683 }, + { 30.802530, 65.330002, -9.690248 }, + { 30.412731, 68.170059, -21.692730 }, + { 30.039160, 70.152573, -32.699528 }, + { 32.216076, 71.159332, -39.759785 }, + { 32.234047, 72.016464, -46.233418 }, + { 31.557087, 73.541389, -53.361401 }, + { 32.326740, 75.265030, -59.796654 }, + { 33.342274, 76.934792, -65.841751 }, + { 34.545971, 78.831108, -71.633972 }, + { 36.091293, 81.076981, -77.304871 }, + { 37.771706, 83.529625, -83.035164 }, + { 39.420837, 86.036163, -88.882256 }, + { 41.022583, 88.537987, -94.796730 } + }, + { + { 36.336849, 47.592506, 68.200417 }, + { 34.071281, 49.365227, 47.632862 }, + { 32.595383, 51.343945, 26.600996 }, + { 34.596535, 53.537312, 11.387937 }, + { 37.136093, 55.346764, -0.309255 }, + { 35.359180, 57.946560, -14.288342 }, + { 35.808708, 59.857433, -24.672016 }, + { 36.739140, 61.382408, -32.993984 }, + { 37.472797, 62.483326, -39.219090 }, + { 38.155697, 64.713448, -46.280056 }, + { 37.912216, 66.466743, -53.747780 }, + { 37.938492, 68.092438, -60.194607 }, + { 38.922039, 70.326569, -65.958496 }, + { 40.406845, 72.944550, -71.622498 }, + { 41.880821, 75.594894, -77.501404 }, + { 43.188915, 78.134064, -83.605087 }, + { 44.400036, 80.593925, -89.812485 } + }, + { + { 42.258934, 39.035580, 78.494797 }, + { 42.693748, 40.449509, 60.593372 }, + { 41.946033, 41.687222, 41.490936 }, + { 38.578568, 43.174889, 20.739519 }, + { 37.696491, 45.147903, 4.605770 }, + { 38.524300, 47.272648, -8.432681 }, + { 41.956024, 49.644844, -16.511272 }, + { 39.061928, 51.965939, -28.259838 }, + { 40.872978, 52.692444, -32.948078 }, + { 41.523361, 55.148251, -40.683594 }, + { 41.259079, 57.317612, -48.875557 }, + { 41.881920, 59.608341, -54.968273 }, + { 43.429245, 62.491604, -60.438786 }, + { 44.874908, 65.302795, -66.079643 }, + { 45.986805, 67.871452, -72.118790 }, + { 46.879837, 70.235977, -78.433174 }, + { 47.700859, 72.511177, -84.847244 } + }, + { + { 46.834900, 30.151939, 86.580887 }, + { 48.731758, 31.476402, 71.098015 }, + { 50.461250, 32.526802, 55.480946 }, + { 48.415230, 33.398113, 36.667465 }, + { 46.061230, 35.059486, 18.797882 }, + { 43.556835, 37.336708, 1.055432 }, + { 43.877346, 40.536045, -11.206631 }, + { 42.844929, 41.782898, -22.463974 }, + { 45.021744, 43.909748, -28.286249 }, + { 42.897797, 46.104763, -38.100739 }, + { 43.851341, 48.922634, -44.974491 }, + { 46.169765, 52.503063, -50.075882 }, + { 48.214794, 55.485619, -55.143639 }, + { 49.303455, 58.037968, -60.835625 }, + { 49.914818, 60.249092, -67.014214 }, + { 50.429966, 62.291061, -73.415291 }, + { 50.955769, 64.292679, -79.872818 } + }, + { + { 51.155544, 21.775232, 93.665558 }, + { 53.795082, 23.130915, 80.118393 }, + { 54.798908, 24.395023, 63.972412 }, + { 53.449760, 25.993490, 46.004471 }, + { 52.237133, 26.311287, 30.030128 }, + { 51.316021, 28.369825, 15.615261 }, + { 50.384361, 30.443657, 2.576066 }, + { 48.920609, 31.561419, -11.627506 }, + { 47.003036, 33.872242, -25.683661 }, + { 47.028210, 36.326672, -33.168331 }, + { 48.785900, 40.818375, -39.253567 }, + { 51.035248, 45.144512, -44.794800 }, + { 52.794132, 48.482086, -50.095207 }, + { 53.246082, 50.677456, -56.028805 }, + { 53.537060, 52.513962, -62.223839 }, + { 53.875515, 54.251617, -68.520126 }, + { 54.231503, 55.983925, -74.844254 } + }, + { + { 55.955650, 14.210527, 100.585930 }, + { 57.205456, 15.375341, 85.065758 }, + { 56.996780, 16.186579, 67.707932 }, + { 57.463551, 16.747389, 52.542618 }, + { 55.973141, 16.321228, 37.101784 }, + { 55.121021, 16.853506, 23.647316 }, + { 55.925964, 20.141315, 12.813906 }, + { 53.949909, 22.339924, -0.517519 }, + { 52.917591, 24.766338, -14.107433 }, + { 53.232330, 27.119019, -22.444090 }, + { 53.426117, 30.613113, -31.249044 }, + { 54.671318, 35.790844, -38.699261 }, + { 56.002762, 40.367859, -45.258572 }, + { 56.387886, 42.534428, -51.530739 }, + { 57.027847, 44.433983, -57.543530 }, + { 57.377354, 46.078636, -63.596260 }, + { 57.541588, 47.572220, -69.740196 } + }, + { + { 60.657612, 7.101519, 106.714455 }, + { 60.979027, 7.951259, 90.193153 }, + { 60.519695, 8.589045, 72.631805 }, + { 60.395790, 9.026114, 57.230179 }, + { 60.696465, 10.056228, 43.363350 }, + { 58.983711, 8.840920, 31.431303 }, + { 58.660267, 11.364512, 14.274028 }, + { 60.096127, 14.181482, 5.284166 }, + { 58.782795, 17.604820, -8.189269 }, + { 57.833126, 18.608469, -16.264664 }, + { 58.453388, 23.139177, -24.356987 }, + { 59.041176, 27.330175, -31.808622 }, + { 59.444111, 30.820007, -39.303474 }, + { 59.397133, 33.522305, -46.921402 }, + { 60.732479, 35.781830, -52.610546 }, + { 60.962715, 37.646542, -58.488857 }, + { 60.798695, 38.881298, -64.581802 } + }, + { + { 64.773811, 0.259441, 111.203461 }, + { 64.593094, 0.542267, 94.777946 }, + { 65.001068, 1.066077, 79.182991 }, + { 64.838600, 1.292001, 64.417931 }, + { 63.271149, 1.306726, 49.429981 }, + { 63.423801, 1.248771, 36.954247 }, + { 61.646450, 0.257949, 23.467422 }, + { 61.226471, 4.374916, 9.928648 }, + { 62.261063, 7.710450, -0.255517 }, + { 61.877556, 10.034693, -9.531917 }, + { 61.795067, 12.853320, -18.601381 }, + { 62.351814, 16.392628, -26.337473 }, + { 62.838333, 19.245361, -33.068821 }, + { 63.273964, 23.076077, -40.405685 }, + { 63.668831, 25.910566, -47.427559 }, + { 63.925072, 28.473595, -53.636768 }, + { 63.948193, 29.629322, -59.356319 } + }, + { + { 68.057777, -6.657614, 113.866226 }, + { 67.986694, -6.626807, 98.060188 }, + { 68.714539, -6.501266, 84.429070 }, + { 68.839928, -6.297818, 70.568367 }, + { 67.333565, -5.732305, 55.083214 }, + { 67.319160, -4.888361, 42.949772 }, + { 65.926407, -4.621775, 28.958605 }, + { 66.150383, -4.166753, 18.969570 }, + { 66.557411, -2.015568, 10.528715 }, + { 66.690788, 0.284221, 0.481741 }, + { 66.334091, 2.602130, -9.466049 }, + { 66.369568, 5.936941, -18.599394 }, + { 66.234535, 8.669911, -26.777996 }, + { 66.058502, 11.679163, -34.805801 }, + { 66.582458, 15.326474, -42.100140 }, + { 66.746696, 18.009691, -48.706032 }, + { 67.190063, 19.843208, -53.848366 } + }, + { + { 71.188095, -13.584580, 116.135895 }, + { 71.091438, -13.764445, 101.191269 }, + { 71.522186, -14.311315, 87.415459 }, + { 70.496727, -14.462589, 72.486580 }, + { 68.648239, -14.814835, 56.932415 }, + { 69.762482, -13.982756, 46.495560 }, + { 69.503792, -13.201355, 34.515137 }, + { 68.054451, -12.400944, 21.121201 }, + { 68.980255, -10.422908, 13.147013 }, + { 69.481705, -8.306414, 4.908546 }, + { 69.088272, -5.768641, -5.296941 }, + { 68.910774, -3.367719, -14.062294 }, + { 69.565216, -1.068692, -20.989040 }, + { 69.670784, 2.034774, -28.706064 }, + { 69.879379, 5.114336, -36.200928 }, + { 70.079445, 8.238202, -43.101055 }, + { 70.721077, 10.348651, -48.309875 } + }, + { + { 74.383308, -20.411808, 118.351646 }, + { 74.341606, -21.102236, 103.663292 }, + { 74.463722, -21.926397, 89.402557 }, + { 74.201569, -21.855906, 76.437309 }, + { 74.423927, -20.371279, 65.610725 }, + { 73.400772, -21.304836, 52.470379 }, + { 72.497757, -21.559914, 39.288017 }, + { 71.265427, -20.643339, 25.773987 }, + { 72.767982, -18.520800, 18.787903 }, + { 72.922585, -16.515749, 9.973615 }, + { 73.471298, -13.891831, 2.427691 }, + { 73.245369, -12.319766, -5.454950 }, + { 72.800278, -9.365343, -15.301738 }, + { 72.621422, -6.647183, -23.820974 }, + { 72.806511, -4.166758, -31.052971 }, + { 72.609398, -1.516843, -38.632900 }, + { 73.328682, 1.157101, -44.051617 } + }, + { + { 77.475296, -26.915995, 120.306870 }, + { 76.663269, -28.429958, 104.513374 }, + { 74.990944, -30.021608, 86.890419 }, + { 73.862984, -31.294836, 71.022865 }, + { 76.871407, -29.364363, 67.257973 }, + { 77.693047, -28.303263, 58.795280 }, + { 75.373291, -28.799631, 43.734997 }, + { 75.046471, -27.979643, 31.760000 }, + { 75.646599, -26.707670, 23.557598 }, + { 75.327873, -24.613256, 14.284280 }, + { 76.636536, -22.125040, 7.727673 }, + { 76.429588, -20.788153, -0.306090 }, + { 76.608269, -18.526485, -8.346106 }, + { 75.813858, -15.555935, -18.383053 }, + { 75.971497, -13.115920, -25.757746 }, + { 76.076904, -10.416206, -32.817562 }, + { 75.335854, -8.659841, -40.107811 } + }, + { + { 80.209724, -32.865864, 121.489204 }, + { 79.295914, -35.058151, 105.660797 }, + { 78.264771, -37.033745, 89.457703 }, + { 77.965424, -37.638802, 75.738876 }, + { 81.225861, -36.254883, 71.904861 }, + { 80.806107, -36.387218, 62.986679 }, + { 80.472572, -36.945805, 51.744915 }, + { 78.803856, -36.252014, 37.778008 }, + { 78.209145, -34.596546, 28.038088 }, + { 80.180611, -32.081825, 22.652855 }, + { 78.550049, -30.768814, 11.346856 }, + { 79.476997, -27.997650, 3.678406 }, + { 78.649384, -26.590210, -5.374319 }, + { 79.947739, -23.505293, -11.168122 }, + { 79.115257, -21.622684, -19.678186 }, + { 79.475777, -18.710041, -26.839607 }, + { 79.257668, -16.823723, -34.056736 } + }, + { + { 82.787109, -38.164608, 122.286156 }, + { 82.148140, -40.681667, 107.217422 }, + { 81.697945, -43.202614, 92.468758 }, + { 81.224365, -45.170513, 78.561455 }, + { 82.893562, -45.345188, 71.694237 }, + { 83.484093, -45.679699, 64.685936 }, + { 84.192017, -45.264439, 57.132168 }, + { 84.002731, -44.418930, 46.068100 }, + { 83.888321, -41.000492, 36.902946 }, + { 85.313927, -38.145805, 30.536810 }, + { 83.288788, -37.501984, 19.931849 }, + { 84.905357, -34.072899, 13.688304 }, + { 82.623894, -32.937813, 2.110718 }, + { 87.289215, -27.571396, 0.268299 }, + { 85.815025, -26.343197, -8.765968 }, + { 84.947861, -24.586096, -17.778563 }, + { 84.196045, -23.015114, -26.168451 } + }, + { + { 85.271446, -43.052429, 122.846283 }, + { 85.163635, -45.433922, 109.403580 }, + { 84.867828, -48.202141, 95.834946 }, + { 84.103111, -52.482399, 81.707161 }, + { 84.547340, -55.965378, 72.747398 }, + { 85.610344, -54.508034, 66.680573 }, + { 87.297134, -50.051254, 61.394131 }, + { 87.247231, -48.945015, 51.476715 }, + { 87.636879, -46.236134, 43.736046 }, + { 87.342155, -43.726334, 34.771854 }, + { 87.530174, -44.052528, 27.062418 }, + { 88.145569, -41.399017, 20.887493 }, + { 88.062912, -38.625431, 11.875647 }, + { 90.287659, -34.152878, 7.028690 }, + { 90.829514, -31.557795, -0.280717 }, + { 90.087822, -30.021772, -9.271255 }, + { 88.924538, -28.378687, -18.103491 } + }, + { + { 87.611656, -47.857334, 123.118279 }, + { 88.248322, -50.165211, 111.738853 }, + { 89.027916, -52.579937, 100.928284 }, + { 90.062775, -55.419334, 91.507751 }, + { 90.917610, -58.962433, 83.669708 }, + { 91.243004, -60.316383, 76.564186 }, + { 91.518295, -57.591370, 68.357597 }, + { 92.147049, -53.657009, 59.390919 }, + { 91.837921, -52.282242, 50.499702 }, + { 91.440392, -50.556084, 41.436031 }, + { 92.180687, -48.297699, 33.686180 }, + { 92.539246, -46.705994, 27.095684 }, + { 92.445801, -44.277313, 20.125080 }, + { 93.605164, -40.190285, 14.191375 }, + { 95.229057, -36.454411, 7.783226 }, + { 95.207100, -34.713223, -0.738582 }, + { 94.178101, -33.071693, -9.688408 } + } + }, + { + { + { 25.007967, 69.464005, 43.422165 }, + { 23.364790, 71.789742, 24.868448 }, + { 24.118303, 74.025200, 8.851120 }, + { 26.240593, 75.928696, -3.539302 }, + { 27.843405, 77.689659, -13.897122 }, + { 28.622723, 79.422653, -23.531513 }, + { 29.075781, 81.205338, -32.662304 }, + { 29.484919, 82.893181, -40.804794 }, + { 29.375208, 84.426559, -48.318935 }, + { 29.037685, 85.945160, -55.593403 }, + { 29.448395, 87.522072, -62.401676 }, + { 30.615078, 89.024895, -68.715942 }, + { 32.075943, 90.500816, -74.736145 }, + { 33.666393, 92.203568, -80.637878 }, + { 35.369701, 94.262726, -86.516640 }, + { 37.156261, 96.608749, -92.408905 }, + { 38.977520, 99.082092, -98.314774 } + }, + { + { 31.892046, 61.345623, 59.167629 }, + { 29.355358, 63.543800, 39.187199 }, + { 29.116659, 66.046677, 18.029247 }, + { 31.324451, 67.440010, 4.481884 }, + { 31.965761, 69.132004, -6.994662 }, + { 31.815756, 70.933044, -18.098680 }, + { 32.741112, 72.853004, -27.963467 }, + { 34.534248, 74.564476, -35.382675 }, + { 35.222450, 75.995903, -41.911377 }, + { 35.515823, 77.651657, -48.762436 }, + { 35.283035, 79.211273, -56.010029 }, + { 35.459309, 80.441917, -62.659409 }, + { 36.386574, 82.082306, -68.864578 }, + { 37.812954, 84.254791, -74.918694 }, + { 39.399300, 86.727768, -80.986626 }, + { 40.969494, 89.301285, -87.116425 }, + { 42.502323, 91.890022, -93.285690 } + }, + { + { 38.913120, 53.199162, 73.216148 }, + { 39.721397, 55.388912, 55.992340 }, + { 35.740253, 57.201759, 30.928585 }, + { 35.755028, 58.233139, 13.587786 }, + { 35.527306, 60.156376, -0.314968 }, + { 34.781017, 62.391289, -13.036380 }, + { 36.574326, 63.936020, -21.849476 }, + { 38.566586, 65.165459, -28.739990 }, + { 40.253513, 66.872719, -35.114098 }, + { 42.999870, 69.330910, -41.314457 }, + { 41.740574, 70.929863, -49.362629 }, + { 40.229115, 71.872810, -56.609673 }, + { 40.731789, 73.915550, -63.038128 }, + { 42.075840, 76.580772, -69.245132 }, + { 43.488178, 79.340096, -75.504021 }, + { 44.769314, 82.010002, -81.861984 }, + { 45.966316, 84.612984, -88.274635 } + }, + { + { 45.441463, 44.651951, 84.139046 }, + { 47.289669, 46.172192, 67.507408 }, + { 43.921989, 47.398956, 44.898079 }, + { 40.395264, 48.541916, 23.346449 }, + { 39.387814, 50.042419, 6.840150 }, + { 38.884407, 52.770229, -7.570076 }, + { 41.424572, 54.941990, -14.919759 }, + { 41.152946, 55.147583, -22.689144 }, + { 43.570881, 57.127594, -29.354103 }, + { 46.733276, 60.208504, -35.902424 }, + { 44.901764, 61.854317, -44.138527 }, + { 44.644886, 63.857815, -50.871082 }, + { 45.479786, 66.538773, -57.276028 }, + { 46.592613, 69.422882, -63.681732 }, + { 47.604870, 72.155029, -70.156647 }, + { 48.489937, 74.702194, -76.703423 }, + { 49.318890, 77.165565, -83.287842 } + }, + { + { 50.950405, 35.651489, 92.899040 }, + { 51.961220, 36.906124, 76.313957 }, + { 50.619690, 38.512787, 57.027771 }, + { 49.720043, 39.931210, 39.219994 }, + { 46.732334, 40.328312, 20.609516 }, + { 44.665234, 42.863045, 3.935264 }, + { 45.090748, 45.678631, -7.063705 }, + { 45.572247, 46.915325, -17.921329 }, + { 45.548321, 49.402988, -28.196365 }, + { 44.250206, 51.602707, -37.488342 }, + { 47.196175, 54.383862, -40.922115 }, + { 49.826237, 57.666248, -45.503250 }, + { 50.654819, 60.131859, -51.755722 }, + { 51.118980, 62.635300, -58.402710 }, + { 51.560596, 65.032005, -65.056770 }, + { 52.051754, 67.299202, -71.682808 }, + { 52.575508, 69.513756, -78.294853 } + }, + { + { 54.275810, 27.399700, 98.585129 }, + { 54.894577, 28.626717, 82.197350 }, + { 55.449085, 30.116003, 65.199318 }, + { 56.437027, 31.508162, 50.188568 }, + { 56.431740, 31.537140, 36.134270 }, + { 53.937485, 33.884647, 20.089373 }, + { 51.855652, 36.133049, 5.761715 }, + { 50.599224, 37.463192, -9.213829 }, + { 49.067448, 39.857677, -22.777660 }, + { 48.652603, 42.287224, -31.533270 }, + { 51.141716, 45.971596, -35.215313 }, + { 54.013458, 50.762783, -40.667168 }, + { 55.162189, 53.657940, -46.932335 }, + { 55.134697, 55.664875, -53.584202 }, + { 55.184044, 57.704098, -60.243542 }, + { 55.444130, 59.712589, -66.777084 }, + { 55.809288, 61.645344, -73.223381 } + }, + { + { 57.994461, 19.984388, 103.978012 }, + { 58.254784, 21.068808, 86.735519 }, + { 58.065983, 22.113817, 68.646881 }, + { 59.082825, 22.431826, 55.123695 }, + { 60.582500, 23.338833, 43.134789 }, + { 60.187325, 24.506983, 30.148380 }, + { 59.474922, 26.013798, 17.935059 }, + { 57.533592, 28.938419, 3.309183 }, + { 56.110477, 31.256676, -9.358533 }, + { 54.634678, 33.510036, -21.187288 }, + { 55.471462, 37.778278, -29.140774 }, + { 56.147717, 41.150238, -35.929401 }, + { 57.871170, 45.297794, -42.469910 }, + { 58.303139, 47.543526, -48.984844 }, + { 58.515434, 49.766319, -55.537151 }, + { 58.774509, 51.809086, -61.827431 }, + { 59.092281, 53.460159, -67.965683 } + }, + { + { 62.214386, 12.955357, 109.464493 }, + { 62.421715, 13.449973, 92.531296 }, + { 61.952969, 13.856644, 75.310608 }, + { 61.323696, 14.619529, 59.513798 }, + { 61.394749, 16.096025, 44.764393 }, + { 60.440807, 16.155579, 32.932014 }, + { 57.354038, 15.074121, 17.432964 }, + { 59.216816, 20.388004, 6.395698 }, + { 60.176437, 22.512596, -1.824601 }, + { 59.857822, 24.600956, -12.767461 }, + { 60.231869, 28.942030, -21.717096 }, + { 60.970493, 33.137638, -29.187841 }, + { 61.251923, 36.084469, -36.814167 }, + { 61.082329, 37.854382, -44.138592 }, + { 61.972610, 40.783794, -50.370220 }, + { 62.335735, 43.216122, -56.375328 }, + { 62.444378, 44.666080, -62.388336 } + }, + { + { 65.907272, 6.069897, 113.835533 }, + { 65.104149, 5.922807, 96.017586 }, + { 65.189880, 6.240343, 79.002052 }, + { 66.108879, 7.595717, 64.264313 }, + { 65.226761, 8.079943, 50.780010 }, + { 65.854370, 8.444172, 40.997166 }, + { 63.948250, 8.638453, 26.610451 }, + { 64.342476, 11.139557, 14.532111 }, + { 64.371780, 13.495421, 5.117900 }, + { 65.257759, 15.026484, -2.936281 }, + { 63.340641, 17.948792, -15.510667 }, + { 64.212334, 21.991552, -23.419954 }, + { 64.668739, 25.757444, -30.563803 }, + { 64.847084, 28.446585, -37.814976 }, + { 65.639755, 31.244284, -44.157543 }, + { 65.889473, 33.700500, -50.405296 }, + { 65.833344, 34.963390, -56.401882 } + }, + { + { 69.438644, -0.803112, 117.515167 }, + { 68.870071, -1.169786, 100.852875 }, + { 69.313713, -1.042704, 86.059708 }, + { 68.454590, -1.353031, 70.057320 }, + { 67.351997, -0.740641, 55.191898 }, + { 69.557045, 1.898953, 46.079128 }, + { 67.660583, 2.381584, 31.770943 }, + { 67.981964, 2.761379, 21.590689 }, + { 68.688896, 4.391176, 13.236986 }, + { 69.341759, 6.433136, 4.944002 }, + { 67.793900, 8.077922, -7.094666 }, + { 67.431290, 10.875298, -16.712900 }, + { 68.167007, 14.632334, -23.766298 }, + { 68.115112, 17.406786, -31.624493 }, + { 68.440613, 21.510239, -39.227249 }, + { 68.986679, 23.646143, -44.909218 }, + { 69.327126, 24.731777, -50.081783 } + }, + { + { 72.977760, -7.511087, 120.714355 }, + { 72.994560, -7.796461, 105.700775 }, + { 73.725464, -7.592741, 91.856110 }, + { 72.245209, -8.025189, 76.025795 }, + { 71.567337, -8.106616, 62.061478 }, + { 72.422737, -6.254228, 50.514439 }, + { 70.608009, -5.449243, 36.015137 }, + { 70.376961, -4.781026, 24.990898 }, + { 70.374664, -2.846995, 15.115644 }, + { 70.979706, -2.271999, 7.891921 }, + { 71.021263, -0.169337, -1.241519 }, + { 70.734245, 3.106444, -11.274156 }, + { 71.083984, 5.785175, -19.036058 }, + { 71.155830, 7.582331, -26.259529 }, + { 71.386765, 11.143704, -34.145542 }, + { 71.929642, 14.050611, -40.112915 }, + { 72.645355, 15.529947, -44.600544 } + }, + { + { 76.440338, -13.949052, 123.184349 }, + { 76.238197, -14.704484, 107.712906 }, + { 75.140442, -16.017778, 90.903236 }, + { 76.059464, -14.315316, 80.472275 }, + { 77.610680, -12.242366, 72.590866 }, + { 76.085106, -14.019412, 57.498138 }, + { 74.807365, -13.833044, 43.024738 }, + { 75.363579, -12.455353, 33.912308 }, + { 73.913582, -11.355096, 21.620285 }, + { 75.041832, -11.155926, 14.902818 }, + { 74.960106, -8.744184, 5.979811 }, + { 75.265518, -5.542122, -2.639218 }, + { 74.721069, -3.791111, -11.920462 }, + { 74.497276, -1.738834, -20.224245 }, + { 74.594002, 1.861402, -28.514706 }, + { 74.338539, 4.738355, -36.113956 }, + { 75.430466, 6.654724, -40.313274 } + }, + { + { 79.457146, -20.120087, 124.563919 }, + { 78.850693, -21.498943, 108.671631 }, + { 77.624916, -22.818111, 91.436401 }, + { 77.139420, -21.893957, 77.792145 }, + { 80.025642, -21.152300, 74.432220 }, + { 79.194595, -21.686518, 62.542557 }, + { 78.225319, -21.718866, 49.000584 }, + { 76.680817, -21.600269, 35.410160 }, + { 76.266747, -20.192253, 24.994980 }, + { 78.060120, -17.243908, 18.902832 }, + { 78.411804, -15.576947, 10.976819 }, + { 78.960335, -13.175617, 3.179472 }, + { 78.342529, -11.566710, -5.785654 }, + { 77.685768, -10.011792, -14.882775 }, + { 77.731110, -6.703271, -22.875017 }, + { 77.833359, -4.053360, -30.141006 }, + { 77.602715, -2.492078, -36.483665 } + }, + { + { 82.117142, -25.707586, 125.193619 }, + { 81.434616, -27.631680, 109.345306 }, + { 80.726372, -29.199757, 93.464699 }, + { 80.761620, -28.955439, 81.436440 }, + { 81.349884, -29.766499, 73.868576 }, + { 82.277168, -29.242220, 64.973122 }, + { 82.760162, -27.764271, 55.197605 }, + { 79.401428, -29.027132, 39.032860 }, + { 79.934242, -27.962957, 30.085892 }, + { 82.181366, -24.776962, 25.228275 }, + { 80.790825, -23.748217, 14.887594 }, + { 79.886574, -21.694105, 4.922039 }, + { 80.327660, -20.130560, -2.850766 }, + { 80.408821, -18.271904, -10.080324 }, + { 80.645378, -15.273351, -17.763857 }, + { 80.810303, -12.949855, -24.732086 }, + { 80.927940, -10.963624, -31.247665 } + }, + { + { 84.671539, -30.649927, 125.670746 }, + { 84.131874, -32.809994, 110.738960 }, + { 83.397133, -34.925655, 95.918404 }, + { 82.743088, -37.206131, 83.409439 }, + { 83.880295, -38.220650, 75.187187 }, + { 84.475357, -35.430847, 66.964035 }, + { 83.673668, -34.511078, 56.494457 }, + { 82.951385, -36.037548, 44.494762 }, + { 83.633690, -34.507801, 36.042278 }, + { 84.841255, -32.855274, 30.376818 }, + { 84.241173, -31.514208, 21.263172 }, + { 85.507660, -28.453672, 14.405935 }, + { 84.742149, -27.279686, 4.896705 }, + { 85.615234, -24.000864, -0.770090 }, + { 85.786034, -22.061895, -8.699727 }, + { 84.967361, -19.994146, -17.587982 }, + { 84.492516, -18.360004, -25.331232 } + }, + { + { 87.165230, -35.222401, 126.140907 }, + { 87.295425, -37.154919, 113.411774 }, + { 87.383163, -39.269794, 100.664398 }, + { 87.515236, -42.396336, 88.743645 }, + { 87.826744, -44.405743, 80.551910 }, + { 87.956352, -41.767754, 71.969635 }, + { 88.398476, -40.037216, 63.147995 }, + { 88.191170, -38.995235, 53.821518 }, + { 88.345970, -37.525116, 45.018848 }, + { 88.523254, -36.540401, 36.146214 }, + { 88.890289, -36.602024, 28.152132 }, + { 87.800468, -36.153778, 20.019840 }, + { 90.826721, -32.227257, 14.835686 }, + { 91.108566, -28.648891, 9.342751 }, + { 92.788185, -25.902777, 3.142650 }, + { 91.291679, -24.816679, -7.631957 }, + { 89.394470, -24.036978, -17.453638 } + }, + { + { 89.613396, -39.751347, 126.507233 }, + { 90.550819, -41.546623, 116.277184 }, + { 91.700607, -43.150185, 106.605232 }, + { 93.016029, -44.618073, 97.986023 }, + { 92.976433, -48.297546, 88.518501 }, + { 91.950333, -53.082310, 77.867325 }, + { 92.375824, -51.722019, 68.654221 }, + { 94.045189, -45.182533, 61.604927 }, + { 93.277580, -44.706333, 52.781040 }, + { 93.435692, -43.486782, 44.346863 }, + { 93.202621, -41.198311, 36.149662 }, + { 92.585388, -41.339500, 27.802120 }, + { 93.822662, -38.739204, 21.378626 }, + { 94.367416, -35.659489, 15.142886 }, + { 95.283066, -32.576412, 8.065529 }, + { 95.241486, -30.796267, -0.972884 }, + { 94.767021, -28.985113, -9.019497 } + } + }, + { + { + { 26.351654, 74.282837, 46.054790 }, + { 25.913986, 76.257156, 29.072365 }, + { 27.532913, 77.971512, 14.144938 }, + { 30.235426, 79.196129, 2.655995 }, + { 31.625452, 80.316994, -7.659795 }, + { 31.897173, 81.486732, -17.448868 }, + { 32.255314, 82.966270, -26.273668 }, + { 32.605499, 84.805801, -34.420315 }, + { 32.560280, 86.859093, -42.503601 }, + { 32.365082, 88.997093, -50.678413 }, + { 32.654060, 90.943069, -58.390842 }, + { 33.574516, 92.440262, -65.324562 }, + { 34.718735, 93.766708, -71.825279 }, + { 35.960201, 95.342216, -78.189705 }, + { 37.315666, 97.329224, -84.533157 }, + { 38.770226, 99.638031, -90.881729 }, + { 40.270947, 102.086571, -97.235313 } + }, + { + { 32.908688, 66.591721, 61.758854 }, + { 32.051369, 68.474434, 44.069355 }, + { 33.110264, 70.448509, 23.622545 }, + { 35.641331, 71.095161, 10.556567 }, + { 35.023762, 72.177147, -2.043510 }, + { 33.839577, 73.128891, -13.502933 }, + { 35.538029, 75.226715, -22.722912 }, + { 36.681389, 77.505760, -30.447554 }, + { 37.526886, 79.255280, -37.251186 }, + { 38.016182, 81.083710, -44.490177 }, + { 37.065697, 82.917427, -52.771923 }, + { 37.859940, 83.921417, -59.319023 }, + { 38.807919, 85.482758, -65.877167 }, + { 39.972588, 87.664970, -72.461807 }, + { 41.275520, 90.158958, -79.012794 }, + { 42.601685, 92.753975, -85.547760 }, + { 43.915268, 95.367622, -92.083961 } + }, + { + { 40.151424, 58.775597, 76.077438 }, + { 41.333008, 59.955929, 60.289944 }, + { 41.770817, 61.148308, 39.541370 }, + { 39.635899, 62.652065, 18.440424 }, + { 37.849457, 64.186897, 2.989131 }, + { 37.500759, 65.726357, -8.971111 }, + { 39.497890, 68.306740, -18.978588 }, + { 40.419395, 70.554337, -26.817781 }, + { 42.164642, 71.782646, -32.475216 }, + { 44.298290, 72.871834, -37.699966 }, + { 42.376377, 73.887054, -45.949673 }, + { 42.134655, 74.938988, -52.983795 }, + { 42.915726, 77.352478, -59.944775 }, + { 44.097675, 80.254570, -66.785400 }, + { 45.302471, 83.127708, -73.530327 }, + { 46.424660, 85.875267, -80.241302 }, + { 47.492874, 88.556458, -86.950333 } + }, + { + { 47.404438, 50.323456, 87.513008 }, + { 49.288006, 51.123802, 72.479034 }, + { 46.918282, 51.951103, 50.607349 }, + { 41.698524, 53.416691, 25.268270 }, + { 41.926121, 55.257504, 10.261526 }, + { 40.961906, 57.446754, -3.528602 }, + { 42.230469, 60.349155, -14.202133 }, + { 43.177631, 61.821335, -22.689360 }, + { 45.540524, 63.801758, -28.723408 }, + { 48.150280, 64.136917, -32.318512 }, + { 45.749844, 62.749195, -39.072674 }, + { 46.032185, 65.872719, -46.707783 }, + { 47.365414, 69.907143, -54.082401 }, + { 48.476608, 73.322548, -61.196487 }, + { 49.377151, 76.256386, -68.141121 }, + { 50.176708, 78.942810, -75.002464 }, + { 50.938187, 81.546112, -81.842285 } + }, + { + { 54.637455, 41.079052, 97.850212 }, + { 55.316067, 41.590557, 81.801720 }, + { 53.042591, 42.983753, 61.496937 }, + { 52.136070, 44.451992, 42.684700 }, + { 48.886726, 46.318794, 24.058582 }, + { 45.674667, 48.787254, 7.039194 }, + { 47.897240, 50.992065, -3.289209 }, + { 45.612343, 52.470669, -17.999046 }, + { 46.897060, 54.981281, -26.880684 }, + { 47.080879, 54.995869, -31.659754 }, + { 49.371246, 55.422100, -34.821095 }, + { 51.375996, 59.618801, -41.056770 }, + { 52.398956, 63.526924, -48.437153 }, + { 52.880161, 66.661362, -55.827473 }, + { 53.309898, 69.358040, -62.932861 }, + { 53.768688, 71.843781, -69.860367 }, + { 54.243649, 74.260834, -76.729042 } + }, + { + { 58.440125, 32.821079, 104.307579 }, + { 59.042603, 33.184628, 88.956291 }, + { 58.660770, 34.871525, 70.277809 }, + { 58.451069, 35.864536, 53.944908 }, + { 58.440384, 36.699497, 39.795498 }, + { 55.583145, 38.157249, 22.844913 }, + { 55.531090, 40.896717, 10.894418 }, + { 51.957172, 41.953888, -5.862464 }, + { 50.767830, 45.151928, -19.686340 }, + { 53.062916, 47.441238, -25.314528 }, + { 54.715649, 50.643517, -31.066290 }, + { 56.889149, 53.964737, -35.985294 }, + { 56.938068, 57.264042, -43.563328 }, + { 56.819801, 59.801449, -50.938038 }, + { 56.924751, 62.186928, -57.967670 }, + { 57.149300, 64.463867, -64.801453 }, + { 57.462536, 66.629105, -71.528336 } + }, + { + { 60.924023, 25.931244, 108.367424 }, + { 60.792053, 26.980116, 91.417099 }, + { 62.292328, 27.645771, 75.999100 }, + { 61.484524, 27.839846, 59.800228 }, + { 60.990864, 28.557320, 45.113365 }, + { 58.114052, 28.894320, 29.311800 }, + { 59.612728, 32.017719, 18.433598 }, + { 58.138355, 33.978661, 5.101844 }, + { 57.389099, 36.031963, -7.055630 }, + { 56.108440, 38.434914, -19.230646 }, + { 56.704334, 42.411251, -27.173285 }, + { 58.939186, 45.581398, -32.286461 }, + { 59.174744, 49.354992, -39.986046 }, + { 60.121685, 52.116440, -46.384102 }, + { 60.178711, 54.429302, -53.155926 }, + { 60.314964, 56.646759, -59.744560 }, + { 60.680614, 58.508995, -66.111389 } + }, + { + { 64.253601, 19.164999, 112.739883 }, + { 64.622887, 20.116644, 96.307007 }, + { 65.333138, 20.191437, 81.768150 }, + { 64.546234, 20.080067, 65.136024 }, + { 63.697052, 21.450920, 49.140305 }, + { 64.294029, 22.824596, 37.818665 }, + { 60.260223, 22.124716, 21.943392 }, + { 60.526443, 25.851137, 8.636040 }, + { 61.252930, 27.885906, -0.531921 }, + { 60.543259, 30.134155, -11.908601 }, + { 61.718212, 34.688251, -19.475567 }, + { 62.674747, 38.476330, -26.809889 }, + { 61.552532, 40.731117, -35.733913 }, + { 63.406548, 43.169521, -41.221634 }, + { 63.195118, 45.611671, -48.127514 }, + { 63.508301, 47.886211, -54.349358 }, + { 63.992695, 49.667202, -60.323090 } + }, + { + { 67.776848, 12.147257, 117.400253 }, + { 67.822235, 12.417422, 100.957726 }, + { 68.208496, 12.466556, 85.982124 }, + { 68.043922, 13.257519, 70.357841 }, + { 68.128197, 14.028598, 56.351036 }, + { 68.018860, 14.410491, 45.080933 }, + { 66.978432, 15.005687, 31.390064 }, + { 64.889420, 15.128798, 18.686832 }, + { 67.550743, 19.054811, 10.577631 }, + { 66.542450, 21.715752, -0.385467 }, + { 65.720207, 23.153378, -11.271565 }, + { 65.807388, 27.077784, -20.616201 }, + { 66.405937, 31.177004, -27.938356 }, + { 66.940674, 33.771568, -34.773960 }, + { 66.926270, 35.961617, -41.876949 }, + { 66.923485, 38.251770, -48.430092 }, + { 67.431343, 40.035831, -54.099918 } + }, + { + { 71.449654, 5.113166, 122.099983 }, + { 71.046494, 4.771172, 105.678947 }, + { 70.518440, 4.529061, 89.079002 }, + { 70.992912, 5.435867, 74.919266 }, + { 70.983055, 6.509124, 60.948284 }, + { 70.905365, 7.645839, 48.456375 }, + { 69.228828, 7.667200, 35.280479 }, + { 68.924095, 7.711247, 24.136127 }, + { 70.001694, 9.841759, 15.141670 }, + { 70.543892, 13.053610, 6.555123 }, + { 69.304153, 14.513955, -5.103370 }, + { 68.354637, 16.673639, -15.820370 }, + { 69.371048, 20.329355, -22.293394 }, + { 69.621635, 24.111851, -29.852989 }, + { 70.150589, 27.078165, -36.758556 }, + { 70.448792, 28.849226, -42.571087 }, + { 71.001724, 30.057327, -47.602268 } + }, + { + { 75.036118, -1.624073, 125.851448 }, + { 75.118958, -1.705128, 111.003471 }, + { 74.905304, -1.671213, 94.147217 }, + { 75.292465, -1.014112, 81.452675 }, + { 75.329445, -0.577583, 68.084015 }, + { 73.373512, -0.135392, 52.196167 }, + { 72.405487, 0.759259, 38.641960 }, + { 72.109482, 1.655148, 27.688370 }, + { 71.979301, 3.241300, 17.399471 }, + { 72.185196, 3.538825, 10.260357 }, + { 73.473450, 6.201486, 2.916248 }, + { 73.144241, 8.578148, -6.982240 }, + { 72.694122, 11.639373, -16.438938 }, + { 73.122963, 14.045359, -23.616646 }, + { 73.052017, 17.085407, -31.627655 }, + { 73.681557, 19.613543, -37.316708 }, + { 74.149292, 20.854475, -42.024258 } + }, + { + { 78.280701, -7.948785, 127.728271 }, + { 78.660477, -8.214056, 113.315193 }, + { 78.900063, -8.135404, 98.598167 }, + { 77.568962, -7.712784, 85.273674 }, + { 78.904144, -7.056312, 75.103325 }, + { 76.864716, -7.899720, 59.490894 }, + { 76.322357, -7.248685, 46.317581 }, + { 75.908241, -6.210074, 35.084202 }, + { 76.737679, -4.257768, 26.825771 }, + { 76.540543, -3.558687, 17.564074 }, + { 76.644623, -1.226961, 8.373695 }, + { 77.130554, -0.036326, 0.568014 }, + { 76.265617, 2.250453, -9.473095 }, + { 76.632080, 4.670366, -16.886034 }, + { 76.202324, 8.025668, -26.174667 }, + { 76.094345, 10.578829, -33.322891 }, + { 77.006310, 11.974966, -37.412346 } + }, + { + { 81.109039, -13.783945, 128.280121 }, + { 81.187965, -14.887539, 113.845100 }, + { 81.687813, -15.351720, 101.431610 }, + { 80.273277, -14.422202, 87.809959 }, + { 80.827400, -14.525190, 75.848663 }, + { 80.265656, -15.412390, 63.422115 }, + { 79.715004, -15.042517, 50.963032 }, + { 79.158363, -13.721757, 39.806538 }, + { 79.614487, -13.313353, 30.592739 }, + { 79.000931, -11.654818, 20.881538 }, + { 80.224823, -9.791836, 14.705762 }, + { 79.985329, -7.819576, 5.375648 }, + { 79.451782, -5.478598, -4.091660 }, + { 79.393410, -3.979418, -11.962180 }, + { 79.294830, -1.011921, -20.398760 }, + { 79.439240, 1.562109, -27.559746 }, + { 79.570656, 2.930991, -33.141178 } + }, + { + { 83.816696, -18.978056, 128.739395 }, + { 83.378349, -20.884031, 113.908813 }, + { 82.938339, -22.708714, 99.677505 }, + { 83.510445, -21.493986, 88.319832 }, + { 82.494202, -21.904905, 76.057724 }, + { 82.625671, -21.790504, 65.314507 }, + { 82.534431, -21.489923, 54.542454 }, + { 81.348389, -21.469578, 42.705540 }, + { 81.684372, -21.171715, 33.907990 }, + { 81.154541, -19.452320, 24.269367 }, + { 83.390625, -17.377327, 19.985826 }, + { 83.322563, -15.771656, 11.069608 }, + { 82.932526, -13.542207, 2.088606 }, + { 82.947403, -11.471736, -5.909942 }, + { 82.061508, -9.254006, -15.449494 }, + { 82.651657, -6.924056, -21.990507 }, + { 82.801567, -5.169322, -27.971844 } + }, + { + { 86.445183, -23.711655, 129.181763 }, + { 86.265175, -25.368652, 115.695107 }, + { 86.312874, -26.804962, 102.641319 }, + { 85.554184, -29.615185, 88.262840 }, + { 85.433655, -28.590906, 78.309662 }, + { 85.257240, -26.981339, 68.507851 }, + { 86.000755, -27.357851, 59.720078 }, + { 85.416214, -27.899193, 49.087551 }, + { 86.318398, -27.656605, 40.852581 }, + { 85.169846, -26.713058, 30.800051 }, + { 86.904991, -24.811754, 25.269497 }, + { 87.660240, -22.480265, 18.159054 }, + { 86.759575, -20.890743, 8.913417 }, + { 87.878593, -17.999716, 3.032734 }, + { 86.779602, -16.434050, -6.995498 }, + { 85.673912, -15.006666, -16.482714 }, + { 85.770248, -13.025072, -23.197727 } + }, + { + { 89.048347, -28.188982, 129.615845 }, + { 89.432159, -29.725164, 118.219452 }, + { 90.050873, -31.459944, 107.066895 }, + { 89.841103, -35.344761, 93.778000 }, + { 89.401138, -33.798130, 83.932487 }, + { 88.708931, -30.980247, 73.837990 }, + { 88.326607, -31.701872, 63.329784 }, + { 89.043892, -32.350544, 55.256157 }, + { 89.413979, -32.322601, 46.165806 }, + { 89.667953, -30.018860, 37.383106 }, + { 89.323418, -31.259150, 27.745817 }, + { 89.914543, -29.188772, 21.035374 }, + { 90.592758, -26.175180, 14.516978 }, + { 91.479393, -23.957165, 9.283149 }, + { 92.661552, -22.000874, 2.658437 }, + { 91.629677, -20.634771, -7.389530 }, + { 89.868378, -19.780340, -16.458124 } + }, + { + { 91.669159, -32.659683, 130.083542 }, + { 92.562874, -34.493126, 120.366623 }, + { 93.442719, -36.484867, 110.572624 }, + { 93.941933, -38.962139, 100.187103 }, + { 93.558144, -41.666553, 89.217216 }, + { 93.002373, -44.388439, 78.667770 }, + { 93.069420, -43.074135, 69.247093 }, + { 93.615646, -39.792099, 61.277847 }, + { 93.493767, -38.749821, 52.535633 }, + { 94.564667, -36.227482, 46.108345 }, + { 94.509247, -36.712101, 38.425930 }, + { 94.773346, -35.641140, 30.699978 }, + { 95.395927, -34.050320, 22.105692 }, + { 94.833611, -32.128971, 13.451624 }, + { 94.350334, -29.740150, 5.682088 }, + { 95.724167, -26.806129, -0.768476 }, + { 95.355064, -24.844921, -7.891024 } + } + }, + { + { + { 27.925890, 79.308090, 48.903442 }, + { 29.203428, 80.458466, 34.479736 }, + { 31.910540, 81.458084, 21.593855 }, + { 34.715725, 82.229721, 10.359000 }, + { 35.686134, 83.004440, -0.658385 }, + { 35.598576, 83.884148, -10.867059 }, + { 35.900780, 84.991295, -19.453968 }, + { 36.248554, 86.727341, -27.557894 }, + { 36.318180, 89.004822, -36.100563 }, + { 36.457024, 91.588272, -45.000423 }, + { 36.786816, 93.899025, -53.526150 }, + { 37.361000, 95.636711, -61.291191 }, + { 38.001766, 97.110527, -68.571396 }, + { 38.703629, 98.753792, -75.645050 }, + { 39.533047, 100.748276, -82.629532 }, + { 40.486900, 103.030701, -89.569305 }, + { 41.502052, 105.441246, -96.491875 } + }, + { + { 34.567726, 71.900719, 63.343224 }, + { 34.639168, 72.520164, 48.076775 }, + { 37.826382, 73.320221, 32.978508 }, + { 39.654171, 73.979462, 18.449701 }, + { 38.332626, 75.236099, 3.817724 }, + { 36.705265, 76.234100, -8.174713 }, + { 38.652306, 77.761040, -16.223284 }, + { 39.161411, 79.868103, -24.434696 }, + { 39.669125, 81.701744, -31.966278 }, + { 40.755745, 83.892006, -39.849178 }, + { 40.769119, 85.756859, -48.030422 }, + { 41.241623, 87.223091, -55.456944 }, + { 41.747784, 89.038925, -62.803909 }, + { 42.466503, 91.288300, -70.028099 }, + { 43.359386, 93.777222, -77.112221 }, + { 44.318588, 96.352547, -84.114380 }, + { 45.288071, 98.946968, -91.090225 } + }, + { + { 42.251587, 64.332375, 78.421623 }, + { 43.464226, 64.649139, 63.602745 }, + { 43.301334, 65.188698, 44.135109 }, + { 40.713177, 66.047287, 22.773685 }, + { 40.109982, 67.609222, 7.532554 }, + { 39.971645, 68.323387, -3.278451 }, + { 41.644936, 71.393120, -13.428162 }, + { 41.417736, 73.752113, -23.250820 }, + { 43.479877, 75.132690, -29.219551 }, + { 45.355453, 75.735413, -34.331291 }, + { 45.140179, 76.561989, -41.515568 }, + { 45.034294, 78.324066, -49.338943 }, + { 45.458675, 81.040146, -57.068481 }, + { 46.318657, 84.016365, -64.443726 }, + { 47.256104, 86.905746, -71.603584 }, + { 48.149994, 89.665077, -78.669182 }, + { 49.008327, 92.360779, -85.707420 } + }, + { + { 50.347969, 55.879402, 90.721298 }, + { 52.157253, 55.570507, 76.183975 }, + { 49.965778, 56.322620, 55.667847 }, + { 42.242836, 56.960587, 28.274488 }, + { 43.354847, 58.753128, 14.041889 }, + { 43.884399, 61.501251, 2.199585 }, + { 45.240780, 64.713615, -9.184464 }, + { 44.064850, 66.746216, -21.268532 }, + { 46.443279, 68.064842, -27.174875 }, + { 48.563477, 66.726540, -29.254543 }, + { 47.522362, 66.488136, -35.828873 }, + { 47.899109, 69.349007, -43.756798 }, + { 49.272419, 73.490715, -51.465603 }, + { 50.394264, 77.074806, -58.872597 }, + { 51.230782, 80.123833, -66.110542 }, + { 51.931061, 82.890373, -73.252319 }, + { 52.587154, 85.560341, -80.357140 } + }, + { + { 56.951385, 47.237396, 99.929451 }, + { 56.416367, 48.183636, 82.104195 }, + { 55.991783, 48.774719, 65.914421 }, + { 54.120850, 48.826126, 46.298428 }, + { 50.551136, 51.103046, 26.703760 }, + { 48.418377, 53.231083, 11.003249 }, + { 47.191620, 55.550594, -2.876891 }, + { 45.770664, 56.896042, -17.033371 }, + { 47.483536, 58.922367, -25.072594 }, + { 49.328236, 58.089012, -26.996264 }, + { 50.362118, 59.127171, -32.254696 }, + { 51.794704, 62.519375, -38.894684 }, + { 53.587273, 66.759216, -45.975143 }, + { 54.567078, 70.301750, -53.362835 }, + { 55.133678, 73.247215, -60.687325 }, + { 55.575356, 75.889885, -67.882751 }, + { 55.992458, 78.433815, -75.018684 } + }, + { + { 61.630142, 38.869549, 108.416893 }, + { 60.953701, 39.709728, 91.549179 }, + { 59.653954, 41.091682, 73.029076 }, + { 60.266365, 41.496639, 57.175041 }, + { 59.412212, 42.308556, 41.933578 }, + { 58.507385, 44.582523, 26.967093 }, + { 56.112556, 45.820000, 11.559952 }, + { 53.958961, 46.739586, -3.696073 }, + { 51.527748, 49.982086, -17.716877 }, + { 54.589245, 51.617184, -21.988985 }, + { 54.670631, 54.603195, -29.391401 }, + { 56.686970, 56.777763, -33.917904 }, + { 57.994541, 60.202393, -40.679264 }, + { 58.549011, 63.350815, -48.095226 }, + { 58.828041, 66.052361, -55.392029 }, + { 59.034710, 68.510826, -62.542099 }, + { 59.251652, 70.877602, -69.622276 } + }, + { + { 64.154839, 32.054306, 113.539352 }, + { 63.220238, 33.082504, 96.507065 }, + { 63.614601, 33.436516, 79.537521 }, + { 62.823299, 35.274391, 62.264683 }, + { 63.466457, 34.896095, 48.581276 }, + { 61.827610, 35.549309, 34.151115 }, + { 59.575726, 36.805798, 19.665718 }, + { 59.892750, 39.111706, 8.113769 }, + { 58.705853, 40.995586, -4.920856 }, + { 59.073792, 43.159851, -14.094546 }, + { 59.907307, 47.986340, -22.744490 }, + { 61.003212, 50.092743, -28.649052 }, + { 61.291977, 52.854000, -36.228687 }, + { 62.204079, 55.849667, -43.077488 }, + { 62.342846, 58.303509, -50.115990 }, + { 62.344116, 60.585552, -57.141445 }, + { 62.438519, 62.785339, -64.066315 } + }, + { + { 67.150696, 25.299534, 117.896156 }, + { 67.032532, 26.156504, 101.025024 }, + { 67.313019, 25.947983, 84.840698 }, + { 67.536308, 26.151041, 70.205025 }, + { 68.188629, 26.907295, 56.505600 }, + { 67.738251, 27.755404, 43.776413 }, + { 67.433128, 28.779659, 31.037706 }, + { 64.632599, 30.785288, 15.016459 }, + { 62.652363, 33.455349, 1.981467 }, + { 62.380695, 35.891548, -8.194896 }, + { 63.774796, 39.622448, -16.028522 }, + { 64.245590, 43.214264, -24.028088 }, + { 63.879425, 44.674667, -32.041027 }, + { 65.780312, 47.390602, -37.626835 }, + { 65.829086, 49.757179, -44.587204 }, + { 65.608597, 51.971504, -51.572613 }, + { 65.645401, 54.089890, -58.257072 } + }, + { + { 70.235176, 18.074360, 122.390137 }, + { 70.341660, 18.353453, 106.059914 }, + { 70.820633, 18.486605, 90.451248 }, + { 71.052948, 18.401011, 75.805977 }, + { 70.312363, 18.682680, 60.704758 }, + { 70.021629, 20.284056, 47.479591 }, + { 67.891693, 21.167240, 32.623295 }, + { 65.246643, 20.793428, 19.002302 }, + { 69.407959, 24.171343, 13.542713 }, + { 68.188240, 26.752274, 2.311311 }, + { 66.909286, 29.071388, -9.620070 }, + { 67.288460, 31.957817, -18.296089 }, + { 67.859077, 36.248623, -25.798429 }, + { 68.711212, 38.384750, -32.022015 }, + { 69.359177, 40.629406, -38.878796 }, + { 68.871529, 42.885078, -45.896843 }, + { 68.931091, 44.876736, -52.170582 } + }, + { + { 73.742035, 10.924883, 127.102562 }, + { 73.792000, 10.742606, 111.013641 }, + { 73.181595, 10.503487, 93.979492 }, + { 73.639229, 11.137333, 79.287590 }, + { 72.415886, 11.546495, 63.667561 }, + { 71.559418, 12.418291, 51.396717 }, + { 70.874130, 12.817727, 38.488544 }, + { 69.864052, 13.415972, 25.190491 }, + { 69.255646, 14.936735, 15.289963 }, + { 70.093849, 18.455990, 6.176843 }, + { 70.877113, 20.892469, -2.934625 }, + { 70.330399, 22.695250, -12.308628 }, + { 71.149498, 26.057365, -19.630424 }, + { 71.309479, 29.263971, -27.323397 }, + { 71.569496, 31.543638, -34.241127 }, + { 71.974152, 33.870457, -40.407234 }, + { 72.270844, 35.426170, -45.959782 } + }, + { + { 77.145760, 4.125189, 130.718674 }, + { 76.680145, 3.803329, 115.015900 }, + { 75.634331, 3.557642, 96.422913 }, + { 75.406433, 4.073395, 81.921562 }, + { 74.609993, 4.102752, 67.945038 }, + { 74.598549, 5.015407, 55.305561 }, + { 73.839668, 6.498601, 41.716160 }, + { 74.421738, 7.556156, 32.296730 }, + { 74.256004, 9.062078, 21.715811 }, + { 75.747917, 10.021764, 15.879640 }, + { 75.957336, 11.929209, 7.172163 }, + { 75.945007, 14.079113, -2.089643 }, + { 74.444351, 16.961361, -13.542546 }, + { 74.582054, 19.684536, -21.454826 }, + { 75.028854, 22.742880, -28.637413 }, + { 74.945602, 24.781666, -35.134159 }, + { 75.387741, 26.108290, -40.143330 } + }, + { + { 80.156059, -2.082860, 132.219208 }, + { 79.544388, -2.559040, 116.390266 }, + { 78.546051, -3.142647, 99.541534 }, + { 78.128487, -3.585875, 85.620613 }, + { 78.652191, -2.928148, 74.675064 }, + { 79.089905, -1.202862, 64.110909 }, + { 78.865707, -1.114442, 51.628864 }, + { 79.042053, -0.520996, 41.433865 }, + { 77.491119, 1.073581, 28.259165 }, + { 78.340736, 1.240029, 21.571667 }, + { 78.173775, 3.241282, 11.751502 }, + { 79.363968, 5.602848, 4.302393 }, + { 77.392487, 7.074341, -7.635738 }, + { 77.720047, 11.185871, -15.858249 }, + { 77.784241, 13.769923, -23.756874 }, + { 78.045868, 16.067657, -30.187927 }, + { 78.386063, 17.123993, -34.938210 } + }, + { + { 82.795921, -7.691807, 132.405563 }, + { 82.526527, -8.807979, 117.188271 }, + { 83.033844, -9.544059, 104.292915 }, + { 82.112732, -9.540751, 91.167412 }, + { 81.631126, -10.191689, 77.322777 }, + { 81.510849, -9.547421, 65.783401 }, + { 80.740501, -9.658425, 53.051872 }, + { 81.297653, -8.410630, 44.120411 }, + { 80.602966, -7.164869, 33.513256 }, + { 81.809608, -6.057765, 26.848551 }, + { 81.774734, -4.055008, 17.420506 }, + { 81.577721, -2.676889, 8.326609 }, + { 81.555984, -0.193320, -0.479574 }, + { 80.978859, 2.485130, -9.846404 }, + { 81.027466, 4.789695, -17.787258 }, + { 81.026947, 7.089911, -24.801300 }, + { 81.216057, 8.644979, -30.323374 } + }, + { + { 85.479446, -12.716874, 132.675690 }, + { 85.120232, -14.447991, 118.080177 }, + { 85.160126, -15.772091, 104.688248 }, + { 85.501587, -15.895485, 93.371948 }, + { 84.955994, -16.858603, 80.862434 }, + { 82.801918, -17.551847, 66.073410 }, + { 82.438988, -16.303961, 54.535744 }, + { 84.024033, -15.294338, 47.562458 }, + { 83.906693, -14.320156, 38.017776 }, + { 84.547943, -13.667382, 30.911058 }, + { 84.356361, -11.073001, 20.614401 }, + { 84.168686, -10.170210, 11.514575 }, + { 85.505348, -7.264184, 6.381373 }, + { 84.928864, -5.748574, -2.289391 }, + { 84.346077, -3.718380, -11.079125 }, + { 84.152405, -1.077293, -19.586811 }, + { 84.276375, 0.560696, -25.498037 } + }, + { + { 88.223900, -17.428873, 132.957779 }, + { 87.885780, -19.306015, 119.701294 }, + { 87.256416, -21.306150, 106.378784 }, + { 86.682976, -24.695976, 92.337090 }, + { 87.439552, -24.782314, 81.582832 }, + { 86.959633, -24.102861, 70.661232 }, + { 87.136894, -23.620529, 60.566422 }, + { 86.476082, -22.251194, 51.366814 }, + { 88.174187, -21.494530, 44.600235 }, + { 87.565308, -20.400558, 35.054276 }, + { 86.821098, -18.769255, 24.379831 }, + { 86.762909, -16.852394, 16.067953 }, + { 87.203430, -14.714560, 8.956574 }, + { 88.601288, -12.572814, 3.892202 }, + { 88.438629, -11.464252, -3.730318 }, + { 87.040749, -9.336700, -14.456283 }, + { 87.299530, -7.420515, -20.520845 } + }, + { + { 90.914017, -22.178473, 133.023880 }, + { 90.987846, -24.121855, 121.763458 }, + { 90.967148, -26.308052, 111.087975 }, + { 90.516701, -31.575163, 96.547729 }, + { 90.006523, -31.967581, 84.925987 }, + { 90.216850, -28.793781, 75.692444 }, + { 90.309799, -27.703766, 66.188034 }, + { 89.975746, -26.361549, 56.743351 }, + { 91.056183, -25.045124, 49.219528 }, + { 90.131516, -26.025410, 38.093521 }, + { 88.203865, -25.964912, 25.525908 }, + { 88.823914, -23.626913, 18.967491 }, + { 90.397781, -22.186487, 13.124538 }, + { 90.304344, -19.959538, 6.126504 }, + { 91.150581, -18.535589, -0.404581 }, + { 91.687454, -16.363934, -7.204952 }, + { 91.339394, -14.423957, -13.844597 } + }, + { + { 93.612740, -27.011936, 133.183456 }, + { 94.092293, -29.447321, 122.862801 }, + { 94.417320, -32.333569, 112.049545 }, + { 94.461128, -36.311378, 99.897285 }, + { 93.792290, -40.031467, 88.274513 }, + { 94.136665, -38.605949, 79.925728 }, + { 94.751633, -36.634022, 72.659912 }, + { 94.687180, -34.827419, 63.346638 }, + { 94.529716, -33.404095, 53.671299 }, + { 94.148216, -34.426041, 44.152557 }, + { 94.177818, -32.919258, 36.708885 }, + { 95.778465, -30.315229, 31.499483 }, + { 95.812202, -29.688925, 21.998251 }, + { 93.705482, -28.107695, 10.493930 }, + { 94.879929, -25.341000, 5.124275 }, + { 96.995857, -21.754984, 0.952446 }, + { 95.850311, -20.442719, -6.572329 } + } + }, + { + { + { 30.062647, 84.432045, 52.523933 }, + { 32.664944, 84.797958, 40.100929 }, + { 35.640671, 85.169151, 28.349367 }, + { 38.228966, 85.581726, 17.144398 }, + { 39.327961, 86.155060, 5.943547 }, + { 39.495590, 86.838638, -4.254900 }, + { 39.881653, 87.749939, -12.975139 }, + { 40.298439, 89.298943, -21.401516 }, + { 40.691196, 91.420662, -30.101168 }, + { 41.190166, 93.930290, -39.121342 }, + { 41.551823, 96.378235, -48.122128 }, + { 41.705997, 98.486511, -56.767052 }, + { 41.735985, 100.368217, -65.024017 }, + { 41.787067, 102.289200, -72.991196 }, + { 41.973633, 104.406395, -80.756729 }, + { 42.302834, 106.712776, -88.399834 }, + { 42.704887, 109.111031, -95.993927 } + }, + { + { 37.014954, 77.254074, 66.731651 }, + { 38.173992, 77.440254, 51.988430 }, + { 40.463032, 77.397926, 38.011532 }, + { 42.189823, 77.502495, 24.376709 }, + { 41.494709, 78.688354, 9.936312 }, + { 41.546108, 79.613312, -0.524954 }, + { 43.175411, 80.660530, -8.115521 }, + { 43.596088, 82.680016, -17.464235 }, + { 43.800518, 84.695229, -26.447718 }, + { 44.597607, 86.894341, -35.127346 }, + { 45.016876, 88.800232, -43.470089 }, + { 45.000565, 90.674080, -51.721046 }, + { 44.975060, 92.747284, -59.813683 }, + { 45.190628, 95.055016, -67.648788 }, + { 45.605576, 97.516335, -75.265892 }, + { 46.113930, 100.044769, -82.759811 }, + { 46.647888, 102.590897, -90.210983 } + }, + { + { 44.113281, 69.912682, 80.218071 }, + { 44.227108, 70.203011, 63.735264 }, + { 45.068237, 69.801285, 47.125984 }, + { 44.034664, 69.826683, 29.469381 }, + { 42.376896, 71.291138, 14.032463 }, + { 44.375935, 72.449181, 4.123113 }, + { 45.816673, 74.517998, -5.148723 }, + { 46.430336, 76.604317, -15.073074 }, + { 47.147057, 78.542389, -23.852039 }, + { 47.592468, 79.932938, -31.692564 }, + { 48.044788, 81.003006, -38.927750 }, + { 48.079979, 82.740807, -46.709789 }, + { 48.178967, 85.173508, -54.634434 }, + { 48.676617, 87.909279, -62.286797 }, + { 49.308887, 90.666695, -69.744118 }, + { 49.931744, 93.352577, -77.112228 }, + { 50.528851, 95.990234, -84.453575 } + }, + { + { 51.987366, 61.445313, 92.514488 }, + { 51.966850, 61.807220, 75.767014 }, + { 51.817474, 61.729782, 58.143692 }, + { 46.734970, 62.593884, 34.955608 }, + { 46.462597, 63.547844, 20.466396 }, + { 48.013569, 65.440208, 9.149424 }, + { 48.345840, 67.886566, -2.236615 }, + { 48.232410, 69.779495, -13.228966 }, + { 49.696915, 72.066269, -21.642015 }, + { 49.063019, 72.892822, -29.339310 }, + { 48.520290, 73.418976, -36.023170 }, + { 50.229313, 75.042839, -42.403851 }, + { 51.420650, 77.841965, -49.534935 }, + { 52.369843, 80.914261, -56.836124 }, + { 53.119881, 83.829094, -64.152794 }, + { 53.723740, 86.553917, -71.457458 }, + { 54.265450, 89.189407, -78.751343 } + }, + { + { 58.372208, 52.916885, 102.434624 }, + { 57.141422, 53.893887, 84.531067 }, + { 56.489048, 54.457977, 67.382469 }, + { 55.635651, 54.739227, 48.742992 }, + { 53.559769, 56.029797, 30.794041 }, + { 50.758484, 57.592384, 15.481993 }, + { 49.497475, 59.254066, 1.597943 }, + { 47.479984, 60.652683, -11.722110 }, + { 52.329891, 63.772064, -18.110826 }, + { 50.338436, 65.457062, -27.419579 }, + { 51.550781, 66.393021, -32.636013 }, + { 53.222507, 68.016922, -38.137955 }, + { 55.038078, 70.910713, -44.346100 }, + { 56.252499, 74.005814, -51.263390 }, + { 56.959621, 76.868797, -58.504436 }, + { 57.417423, 79.514145, -65.812050 }, + { 57.801723, 82.068298, -73.111809 } + }, + { + { 62.847313, 44.773815, 110.771576 }, + { 61.979084, 45.394783, 92.851089 }, + { 61.945534, 45.896812, 76.309311 }, + { 62.379761, 46.499554, 59.811699 }, + { 59.740231, 48.000294, 42.741058 }, + { 61.457558, 49.529987, 31.766737 }, + { 57.634727, 50.757854, 14.304282 }, + { 54.789043, 51.760235, -0.896434 }, + { 53.905933, 53.362041, -12.376724 }, + { 54.483845, 55.926140, -22.198902 }, + { 56.511005, 59.037716, -28.308182 }, + { 57.490295, 61.341213, -33.137337 }, + { 59.255814, 64.130692, -38.725319 }, + { 60.268372, 66.952667, -45.569527 }, + { 60.722000, 69.595016, -52.852894 }, + { 60.953377, 72.091835, -60.188690 }, + { 61.137280, 74.534355, -67.501099 } + }, + { + { 66.138725, 37.464993, 117.381683 }, + { 65.243523, 37.695702, 98.954857 }, + { 64.171837, 38.231911, 80.345070 }, + { 63.217529, 39.834827, 62.740192 }, + { 62.837982, 40.344219, 49.090893 }, + { 64.851616, 40.082024, 39.442261 }, + { 62.297672, 41.638229, 23.687323 }, + { 61.564934, 45.088234, 10.077301 }, + { 59.022148, 45.121761, -3.661938 }, + { 58.738789, 46.257786, -14.181799 }, + { 59.341442, 49.342136, -22.184439 }, + { 62.175011, 54.271542, -27.181250 }, + { 63.570698, 56.864212, -32.838421 }, + { 64.207245, 59.421150, -39.905994 }, + { 64.330566, 61.842182, -47.247444 }, + { 64.330872, 64.199554, -54.573246 }, + { 64.329971, 66.544792, -61.849319 } + }, + { + { 69.401642, 30.538509, 123.017502 }, + { 69.492424, 30.979706, 105.245941 }, + { 68.189369, 31.118032, 86.414505 }, + { 69.184273, 31.609581, 72.666695 }, + { 70.385315, 32.383305, 60.607090 }, + { 69.423592, 33.036758, 47.017960 }, + { 68.411240, 34.021759, 32.649281 }, + { 64.124710, 35.764488, 15.175400 }, + { 63.711681, 37.682220, 4.083631 }, + { 64.180435, 39.365204, -4.904817 }, + { 64.424370, 42.716640, -14.671511 }, + { 65.967003, 47.321777, -21.648548 }, + { 66.363167, 48.722984, -28.329966 }, + { 67.491341, 51.217468, -34.699535 }, + { 67.669350, 53.604210, -41.788265 }, + { 67.561737, 55.882404, -48.983955 }, + { 67.460289, 58.122322, -56.085236 } + }, + { + { 72.666206, 23.506348, 127.969658 }, + { 72.499031, 23.694738, 110.394646 }, + { 72.219543, 23.856808, 93.481987 }, + { 73.733620, 24.045805, 80.152512 }, + { 72.172867, 24.654125, 64.011681 }, + { 71.603493, 26.105276, 50.423004 }, + { 69.060616, 27.433615, 34.028385 }, + { 66.999619, 27.950535, 19.659721 }, + { 69.871857, 29.991777, 14.137149 }, + { 69.225342, 31.534288, 4.003752 }, + { 68.475647, 33.421654, -6.329688 }, + { 69.045845, 37.985115, -15.505653 }, + { 69.219803, 40.962059, -23.801281 }, + { 70.109955, 42.600662, -29.814686 }, + { 70.537300, 45.194122, -36.792152 }, + { 70.576035, 47.328491, -43.547134 }, + { 70.570564, 49.341969, -50.183498 } + }, + { + { 76.034378, 16.455753, 132.191177 }, + { 74.963989, 15.971539, 113.700661 }, + { 73.770332, 15.570451, 95.573158 }, + { 75.721092, 16.734188, 83.030128 }, + { 73.848534, 17.323000, 66.359161 }, + { 75.164360, 18.562658, 55.770039 }, + { 72.201439, 19.233038, 39.131817 }, + { 71.012131, 20.621521, 26.174261 }, + { 73.251305, 21.377895, 20.821779 }, + { 72.181671, 23.544018, 9.136081 }, + { 72.701584, 25.145643, 0.726014 }, + { 72.238213, 27.840338, -8.766940 }, + { 72.806915, 31.516449, -17.023329 }, + { 73.148178, 34.819153, -24.848103 }, + { 73.321671, 36.954155, -31.954693 }, + { 73.406395, 38.676712, -38.226715 }, + { 73.637184, 40.292950, -44.212864 } + }, + { + { 79.198326, 9.694394, 135.037445 }, + { 78.236244, 9.085491, 117.299797 }, + { 77.665901, 9.020238, 100.514870 }, + { 77.998024, 9.833652, 86.991806 }, + { 77.919838, 10.551506, 73.555573 }, + { 77.839867, 11.626030, 61.067780 }, + { 76.998947, 12.439543, 47.104988 }, + { 76.925957, 13.138169, 36.132477 }, + { 77.308258, 14.216971, 27.014124 }, + { 76.634369, 15.981724, 16.370623 }, + { 77.496475, 17.401417, 9.024132 }, + { 77.163933, 19.369453, 0.110649 }, + { 75.856285, 20.963354, -10.883494 }, + { 76.368965, 24.817347, -18.547047 }, + { 76.735291, 28.435942, -26.247158 }, + { 76.276749, 29.969870, -32.936432 }, + { 76.678818, 31.075520, -38.273643 } + }, + { + { 82.088341, 3.558457, 136.514145 }, + { 81.302673, 2.933882, 119.797455 }, + { 80.439568, 2.566452, 103.665398 }, + { 80.559807, 2.632506, 90.388863 }, + { 80.264671, 2.346449, 76.273941 }, + { 80.334221, 4.041986, 65.088249 }, + { 79.966057, 5.235857, 52.970341 }, + { 80.052971, 6.201694, 42.086578 }, + { 79.270393, 6.100523, 31.913315 }, + { 78.293396, 8.381777, 19.108316 }, + { 78.503494, 9.977179, 10.880462 }, + { 79.327667, 11.715846, 4.225945 }, + { 79.157219, 12.919312, -5.064711 }, + { 79.366280, 16.214785, -13.163797 }, + { 79.305412, 18.619688, -21.325979 }, + { 79.222168, 20.352642, -27.813866 }, + { 79.955482, 21.951214, -32.356461 } + }, + { + { 84.715843, -1.935343, 137.025513 }, + { 83.847771, -3.158774, 120.574257 }, + { 82.807114, -4.632569, 103.628708 }, + { 82.466599, -4.957335, 90.215790 }, + { 82.200211, -5.485223, 78.705925 }, + { 82.835716, -4.364386, 67.821480 }, + { 82.448936, -3.608069, 56.505856 }, + { 82.870407, -1.895870, 47.232300 }, + { 83.255730, -3.596864, 41.490356 }, + { 82.944038, -0.337902, 28.495604 }, + { 82.170525, 2.132328, 17.422829 }, + { 82.498131, 3.903182, 9.823831 }, + { 83.205750, 5.981963, 2.116350 }, + { 83.000473, 7.805793, -6.347284 }, + { 82.484322, 10.249771, -15.350457 }, + { 82.607185, 12.509711, -22.362326 }, + { 82.867043, 13.869382, -27.465961 } + }, + { + { 87.265709, -7.021381, 137.019272 }, + { 86.571091, -8.756639, 121.762779 }, + { 86.016624, -11.127107, 105.651390 }, + { 85.773270, -14.610926, 90.807381 }, + { 85.972763, -14.253723, 81.995125 }, + { 85.631912, -12.455323, 71.931900 }, + { 85.646408, -10.097755, 61.720261 }, + { 84.625557, -9.676972, 49.565548 }, + { 85.973305, -8.875876, 42.796188 }, + { 86.442299, -8.237524, 34.432564 }, + { 85.676994, -6.079780, 23.796209 }, + { 86.537430, -4.479478, 17.093664 }, + { 86.444969, -2.597003, 8.582292 }, + { 86.642136, -0.474022, 0.613404 }, + { 86.278366, 1.961852, -7.817488 }, + { 86.206345, 4.297342, -15.920435 }, + { 85.853142, 5.817212, -22.666578 } + }, + { + { 89.906700, -12.056197, 136.670975 }, + { 89.377197, -14.735887, 122.334290 }, + { 88.747719, -18.855162, 106.727356 }, + { 88.389610, -25.031736, 90.973946 }, + { 88.373116, -24.778078, 81.277679 }, + { 88.492867, -22.438169, 72.739212 }, + { 87.370140, -18.040453, 61.754314 }, + { 87.429222, -16.022633, 52.177723 }, + { 88.662895, -14.996266, 46.064396 }, + { 88.743454, -14.378586, 37.434925 }, + { 89.248116, -12.922210, 29.666935 }, + { 89.532310, -11.082338, 21.877398 }, + { 88.591331, -9.159850, 11.348819 }, + { 89.247597, -7.861586, 5.739451 }, + { 89.669098, -6.138183, -1.726242 }, + { 88.687157, -3.465939, -11.853051 }, + { 89.081711, -1.993769, -17.302700 } + }, + { + { 92.581085, -17.461937, 135.949326 }, + { 92.322060, -20.520540, 123.112122 }, + { 91.937027, -24.303690, 109.793411 }, + { 91.674843, -28.991726, 95.451920 }, + { 91.296295, -28.803314, 85.234612 }, + { 92.032387, -27.946814, 77.341309 }, + { 92.279816, -27.803844, 68.236702 }, + { 91.196007, -26.685093, 57.929508 }, + { 91.690643, -21.968130, 49.653580 }, + { 92.115837, -21.694038, 40.835743 }, + { 92.342834, -19.181198, 34.075752 }, + { 92.679848, -17.403208, 26.572742 }, + { 90.716606, -17.017084, 13.773561 }, + { 91.901703, -14.531446, 8.486763 }, + { 92.373314, -13.351661, 0.570496 }, + { 92.382584, -11.884997, -7.231421 }, + { 92.484436, -9.365681, -11.534941 } + }, + { + { 95.274139, -23.086273, 135.186493 }, + { 95.335960, -26.271584, 123.435730 }, + { 95.279037, -29.492870, 111.243538 }, + { 95.012619, -32.680870, 98.891075 }, + { 94.701866, -35.057613, 88.707146 }, + { 95.184288, -33.185085, 81.024986 }, + { 95.928596, -33.758579, 73.647537 }, + { 95.270355, -35.142658, 63.783787 }, + { 95.254234, -31.214428, 53.913357 }, + { 95.991692, -30.543467, 45.276081 }, + { 96.183296, -27.322306, 38.461346 }, + { 96.939697, -24.580149, 34.133701 }, + { 96.169060, -24.358864, 23.880737 }, + { 94.909813, -21.703121, 12.793077 }, + { 95.849594, -19.080359, 6.366665 }, + { 96.667183, -17.750521, 0.700279 }, + { 96.828316, -15.439892, -5.042284 } + } + }, + { + { + { 32.579304, 89.552208, 56.035770 }, + { 35.426388, 89.488846, 44.574711 }, + { 38.177250, 89.473007, 33.356766 }, + { 40.526928, 89.613411, 22.358313 }, + { 42.051685, 90.010017, 11.521840 }, + { 42.994728, 90.544472, 1.527666 }, + { 43.812145, 91.325844, -7.546438 }, + { 44.625137, 92.566719, -16.199070 }, + { 45.487404, 94.272568, -24.758690 }, + { 46.207878, 96.416031, -33.624264 }, + { 46.495056, 98.810326, -42.848858 }, + { 46.253342, 101.219788, -52.182831 }, + { 45.690262, 103.549156, -61.359009 }, + { 45.073734, 105.843269, -70.252388 }, + { 44.568924, 108.177238, -78.869888 }, + { 44.202412, 110.577301, -87.297653 }, + { 43.910271, 113.016777, -95.645515 } + }, + { + { 39.791721, 81.999588, 70.136841 }, + { 40.376461, 82.292046, 54.669304 }, + { 41.579372, 82.324707, 40.356228 }, + { 43.400711, 82.215004, 27.938007 }, + { 44.010365, 82.949562, 15.663681 }, + { 45.534691, 83.741982, 5.904171 }, + { 47.577629, 84.687019, -2.298124 }, + { 48.726421, 86.230713, -11.326203 }, + { 49.005123, 88.187431, -21.036921 }, + { 49.131802, 90.255249, -30.504982 }, + { 49.034534, 92.282715, -39.549141 }, + { 48.677975, 94.368233, -48.372711 }, + { 48.298065, 96.573677, -56.978733 }, + { 48.058292, 98.904137, -65.328445 }, + { 47.970016, 101.324181, -73.454926 }, + { 47.974495, 103.788025, -81.443489 }, + { 48.012451, 106.264458, -89.380028 } + }, + { + { 46.357113, 74.486656, 82.783615 }, + { 44.851826, 75.294678, 63.913174 }, + { 44.534809, 75.625259, 46.439545 }, + { 45.277760, 75.529007, 32.009739 }, + { 45.585472, 75.959183, 19.786049 }, + { 48.196884, 76.969795, 10.366276 }, + { 51.602627, 78.127975, 3.045268 }, + { 53.411415, 79.745216, -5.807544 }, + { 52.702690, 82.272781, -17.456924 }, + { 51.764492, 84.401932, -27.951704 }, + { 51.076641, 85.923439, -36.691296 }, + { 50.852627, 87.565132, -44.729214 }, + { 50.894878, 89.605110, -52.587360 }, + { 51.127392, 91.966042, -60.329063 }, + { 51.441582, 94.460281, -67.975822 }, + { 51.756729, 96.965965, -75.572502 }, + { 52.055618, 99.455177, -83.154724 } + }, + { + { 53.245369, 66.310692, 94.718002 }, + { 50.714935, 67.724205, 74.571732 }, + { 49.516506, 68.643173, 55.047947 }, + { 48.299770, 69.324226, 36.869804 }, + { 48.814289, 68.692451, 24.756687 }, + { 51.266933, 70.192543, 14.602763 }, + { 53.653934, 71.905312, 6.199538 }, + { 56.588688, 73.192177, -1.206575 }, + { 56.040733, 76.142876, -13.917078 }, + { 53.461624, 78.635628, -26.023994 }, + { 52.362492, 79.678902, -34.368576 }, + { 52.810104, 80.815926, -41.240116 }, + { 53.620644, 82.662041, -48.080772 }, + { 54.402969, 85.026329, -55.138546 }, + { 55.037426, 87.544670, -62.362907 }, + { 55.529099, 90.040016, -69.678978 }, + { 55.952396, 92.497726, -77.027016 } + }, + { + { 59.253834, 57.879299, 105.147926 }, + { 58.367641, 58.570015, 87.155609 }, + { 58.629440, 58.853966, 70.186478 }, + { 57.144020, 60.200245, 50.775890 }, + { 54.455845, 60.977272, 33.334293 }, + { 54.430000, 62.250702, 20.820799 }, + { 54.072132, 64.697609, 9.045743 }, + { 56.141777, 65.631523, 1.702120 }, + { 57.741558, 68.761337, -10.679706 }, + { 54.849548, 71.704491, -23.514170 }, + { 54.415947, 72.837334, -31.320635 }, + { 55.389168, 73.910934, -37.276497 }, + { 56.789886, 75.739998, -43.194328 }, + { 57.966259, 78.052635, -49.650948 }, + { 58.734455, 80.491203, -56.597923 }, + { 59.229332, 82.909370, -63.788620 }, + { 59.626213, 85.297943, -71.045586 } + }, + { + { 64.135864, 49.961254, 113.891243 }, + { 64.549583, 49.882751, 96.357079 }, + { 65.922058, 50.007530, 81.885422 }, + { 64.737732, 51.544022, 62.803650 }, + { 59.504047, 53.171295, 42.527969 }, + { 62.108788, 54.209068, 33.486950 }, + { 58.471584, 56.612579, 17.069542 }, + { 57.772217, 58.389759, 4.162331 }, + { 57.138126, 59.259655, -7.967973 }, + { 56.891857, 61.750099, -18.768013 }, + { 57.493011, 64.576828, -26.823381 }, + { 58.910542, 66.703209, -32.361481 }, + { 60.631092, 68.769485, -37.637394 }, + { 61.813583, 70.906494, -43.818306 }, + { 62.431496, 73.167831, -50.744232 }, + { 62.779087, 75.477631, -57.955513 }, + { 63.049423, 77.793388, -65.221115 } + }, + { + { 67.860489, 42.351601, 121.351509 }, + { 67.808273, 42.401276, 102.136864 }, + { 67.700676, 42.844772, 85.176491 }, + { 64.982315, 44.563274, 66.532555 }, + { 63.940571, 45.563782, 51.317612 }, + { 69.634949, 44.833385, 45.544712 }, + { 64.379768, 46.989311, 27.359346 }, + { 64.340187, 50.281986, 14.239681 }, + { 60.686932, 50.615723, -0.793160 }, + { 59.118370, 51.289707, -12.750944 }, + { 60.151875, 54.667927, -21.152220 }, + { 62.974445, 59.324078, -26.508749 }, + { 64.941414, 61.458122, -31.399519 }, + { 65.654739, 63.328026, -37.844456 }, + { 65.953056, 65.469345, -44.969406 }, + { 66.128708, 67.710136, -52.236561 }, + { 66.258591, 69.971626, -59.509041 } + }, + { + { 71.132408, 35.265224, 127.874184 }, + { 71.452782, 35.610317, 109.642303 }, + { 71.213280, 35.971931, 91.729729 }, + { 71.304672, 36.794064, 76.068268 }, + { 72.159264, 37.851089, 63.416775 }, + { 72.978867, 38.019432, 52.147556 }, + { 69.936096, 39.452358, 35.329716 }, + { 68.305885, 41.082378, 21.406406 }, + { 66.124199, 42.974403, 7.612558 }, + { 65.072540, 44.750431, -3.971272 }, + { 64.692986, 46.350502, -13.690434 }, + { 67.104607, 51.879387, -19.958780 }, + { 68.721077, 53.112873, -25.166355 }, + { 68.852692, 55.233994, -32.338444 }, + { 69.156647, 57.449581, -39.470997 }, + { 69.278534, 59.661518, -46.662884 }, + { 69.321243, 61.853458, -53.825951 } + }, + { + { 74.976860, 28.513649, 133.665955 }, + { 75.497253, 28.917431, 116.493996 }, + { 75.439560, 29.200321, 99.257927 }, + { 75.382385, 29.841337, 82.363174 }, + { 73.432076, 30.704262, 65.799438 }, + { 72.507729, 31.784481, 52.519035 }, + { 72.154968, 32.818520, 38.413570 }, + { 68.619560, 33.692905, 22.196930 }, + { 68.927963, 35.485455, 12.453566 }, + { 69.334747, 37.334740, 3.786029 }, + { 71.432297, 39.266438, -1.881215 }, + { 70.719292, 43.006783, -12.993345 }, + { 71.291573, 45.759659, -20.641867 }, + { 71.374146, 47.370323, -27.712275 }, + { 72.154510, 49.288864, -34.250153 }, + { 72.238136, 51.424931, -41.234795 }, + { 72.292694, 53.461544, -48.086651 } + }, + { + { 78.458221, 21.743614, 137.742493 }, + { 78.312675, 21.873280, 120.258354 }, + { 78.131905, 22.111078, 102.771210 }, + { 77.291786, 22.701187, 85.382584 }, + { 76.041672, 23.030130, 69.353569 }, + { 77.041389, 24.020767, 58.682995 }, + { 74.322052, 25.017729, 42.942280 }, + { 75.048561, 26.172079, 32.791111 }, + { 75.252449, 27.050873, 23.396910 }, + { 74.061234, 28.983372, 11.782925 }, + { 72.878670, 30.510792, 1.162015 }, + { 73.659973, 32.970078, -6.723539 }, + { 74.349747, 36.286827, -14.640405 }, + { 74.590408, 39.351120, -22.521017 }, + { 74.740067, 41.377102, -29.597559 }, + { 75.050972, 43.148682, -35.886566 }, + { 75.254211, 44.830231, -42.217159 } + }, + { + { 81.438133, 15.193307, 139.907394 }, + { 80.860657, 15.301330, 122.486244 }, + { 80.201485, 15.483819, 105.647530 }, + { 79.826096, 15.840078, 89.991333 }, + { 80.522247, 16.203064, 76.675751 }, + { 80.447594, 17.060053, 64.939041 }, + { 77.929634, 17.963978, 49.399979 }, + { 77.110405, 18.884802, 36.728634 }, + { 76.141884, 20.118477, 25.156723 }, + { 77.520287, 21.450893, 17.638306 }, + { 77.182770, 23.316341, 8.283276 }, + { 78.049522, 24.638170, 1.263085 }, + { 76.833275, 26.657694, -9.190142 }, + { 77.841377, 29.831444, -16.210226 }, + { 77.821213, 32.858673, -24.367830 }, + { 78.195328, 34.787003, -30.151512 }, + { 78.298721, 36.089943, -36.253155 } + }, + { + { 84.146278, 9.011322, 141.077927 }, + { 83.438362, 8.644821, 124.894859 }, + { 82.921921, 8.583144, 108.954826 }, + { 82.867569, 9.129299, 94.435356 }, + { 82.002335, 8.925883, 79.091637 }, + { 81.270660, 9.194602, 66.832794 }, + { 81.306358, 10.923456, 53.878719 }, + { 79.483047, 11.711132, 39.859737 }, + { 80.204422, 12.609529, 31.159622 }, + { 80.755371, 14.056147, 22.743826 }, + { 80.041603, 15.180361, 13.116800 }, + { 80.796547, 17.088343, 5.824527 }, + { 80.672966, 18.911036, -2.796141 }, + { 80.961632, 21.169455, -10.363100 }, + { 81.196732, 23.824848, -18.229797 }, + { 81.121803, 26.033592, -24.813824 }, + { 81.446548, 27.441526, -30.395037 } + }, + { + { 86.687035, 3.269228, 141.373108 }, + { 85.926697, 2.360647, 125.766495 }, + { 85.039597, 1.361880, 109.645866 }, + { 83.970863, 1.324487, 94.181145 }, + { 84.106270, 2.075510, 83.068924 }, + { 85.064339, 3.132785, 72.971550 }, + { 83.951927, 3.090848, 58.405323 }, + { 83.776535, 4.250571, 47.738003 }, + { 84.283272, 5.469511, 39.028294 }, + { 83.949265, 6.361766, 29.421879 }, + { 85.867096, 8.004305, 23.653601 }, + { 84.842049, 9.778213, 12.690528 }, + { 84.579109, 11.553860, 4.275308 }, + { 84.340996, 13.159204, -4.194589 }, + { 84.230476, 15.453726, -12.515244 }, + { 84.381966, 17.691807, -19.253601 }, + { 84.499519, 19.232872, -24.956514 } + }, + { + { 89.069206, -2.316162, 140.739471 }, + { 88.424088, -3.819083, 125.982506 }, + { 87.953911, -5.445848, 111.245071 }, + { 86.746704, -8.363253, 94.733032 }, + { 87.367737, -6.371851, 86.385323 }, + { 87.542747, -4.472991, 76.797226 }, + { 86.810097, -3.613122, 64.083313 }, + { 87.292191, -3.653660, 54.115067 }, + { 87.404541, -1.388531, 44.884388 }, + { 87.015617, -0.610703, 34.620388 }, + { 87.942299, 1.016125, 27.437696 }, + { 87.174408, 2.336501, 17.330320 }, + { 88.931938, 3.619892, 12.261378 }, + { 88.654373, 4.783853, 4.047585 }, + { 87.382591, 7.395928, -6.722178 }, + { 87.479149, 9.678512, -13.975009 }, + { 87.261208, 11.077826, -20.242617 } + }, + { + { 91.505638, -8.029830, 139.521927 }, + { 90.976616, -10.822413, 124.865891 }, + { 90.627319, -14.175793, 109.899406 }, + { 90.599777, -17.207226, 95.879486 }, + { 89.611534, -18.573246, 83.649498 }, + { 90.259552, -17.102844, 75.486176 }, + { 88.968605, -12.109780, 64.372108 }, + { 89.152969, -9.820655, 55.759209 }, + { 89.765175, -8.771997, 47.743279 }, + { 89.586777, -7.973629, 38.371342 }, + { 90.146172, -6.470567, 31.663570 }, + { 90.726753, -4.890988, 23.835268 }, + { 89.976585, -3.259384, 13.689215 }, + { 91.052086, -2.659057, 9.253434 }, + { 91.117950, -0.305192, 0.583791 }, + { 90.593323, 2.025963, -8.462281 }, + { 90.725433, 3.225935, -14.874564 } + }, + { + { 94.034470, -14.197973, 137.794342 }, + { 93.703308, -17.563051, 124.001579 }, + { 93.514595, -20.938421, 110.260353 }, + { 93.281090, -23.768316, 96.612526 }, + { 92.085487, -25.459448, 83.528046 }, + { 92.588814, -26.155840, 75.529434 }, + { 93.205589, -24.154205, 68.194206 }, + { 92.279762, -19.850941, 59.609745 }, + { 92.073814, -19.919588, 49.099873 }, + { 92.849075, -19.391876, 40.599472 }, + { 93.540695, -14.644145, 35.547894 }, + { 94.358040, -11.510344, 30.220623 }, + { 92.910965, -10.883237, 17.769566 }, + { 93.279633, -9.133171, 10.688870 }, + { 94.101868, -7.660027, 5.360925 }, + { 93.675758, -6.084884, -3.506273 }, + { 93.594910, -4.058439, -9.923721 } + }, + { + { 96.629280, -20.626291, 135.871109 }, + { 96.460548, -24.128927, 123.072029 }, + { 96.190208, -27.369205, 110.247131 }, + { 95.731071, -29.838331, 97.924370 }, + { 95.336586, -30.894073, 87.467644 }, + { 95.514534, -30.875423, 79.235672 }, + { 96.139565, -31.637053, 72.245995 }, + { 95.865288, -30.983143, 63.391613 }, + { 95.285339, -27.824547, 53.753719 }, + { 95.713013, -26.042336, 43.280968 }, + { 96.218536, -22.050125, 36.068275 }, + { 96.677719, -19.320829, 33.062695 }, + { 96.577843, -19.182669, 24.935883 }, + { 97.263222, -16.929379, 16.798399 }, + { 97.107239, -14.513421, 9.530219 }, + { 97.419983, -12.642540, 3.178150 }, + { 98.321411, -9.744149, -2.772919 } + } + }, + { + { + { 34.774040, 94.723923, 58.604267 }, + { 37.205898, 94.593025, 47.476303 }, + { 39.552464, 94.478806, 36.543777 }, + { 41.848934, 94.450706, 25.972393 }, + { 44.050800, 94.573105, 15.871240 }, + { 46.060791, 94.842377, 6.362512 }, + { 47.826153, 95.331009, -2.601663 }, + { 49.377163, 96.153526, -11.172142 }, + { 50.651379, 97.418617, -19.655272 }, + { 51.392197, 99.191483, -28.528372 }, + { 51.444805, 101.451302, -37.960087 }, + { 50.797489, 104.031616, -47.800747 }, + { 49.695454, 106.719574, -57.726261 }, + { 48.445858, 109.379364, -67.474998 }, + { 47.248329, 111.975273, -76.952904 }, + { 46.158257, 114.526321, -86.210640 }, + { 45.132412, 117.060753, -95.367371 } + }, + { + { 41.707844, 86.752197, 72.119400 }, + { 41.784504, 87.231438, 56.637932 }, + { 42.455906, 87.588112, 42.267712 }, + { 43.907562, 87.832092, 29.807781 }, + { 45.758553, 88.202034, 19.094311 }, + { 48.249012, 88.662163, 10.102296 }, + { 50.866096, 89.299133, 1.907016 }, + { 52.804218, 90.295464, -6.713494 }, + { 53.652592, 91.743217, -16.171844 }, + { 53.734554, 93.628410, -25.920345 }, + { 53.240753, 95.816353, -35.617340 }, + { 52.488861, 98.115906, -45.067139 }, + { 51.705261, 100.447639, -54.210384 }, + { 50.999165, 102.799667, -63.059597 }, + { 50.397972, 105.171356, -71.674522 }, + { 49.875668, 107.556068, -80.145790 }, + { 49.387211, 109.945694, -88.562080 } + }, + { + { 48.487885, 78.751549, 85.248703 }, + { 46.063820, 79.833015, 65.642075 }, + { 45.472977, 80.742889, 47.982666 }, + { 46.181259, 81.351128, 33.512810 }, + { 47.425697, 81.876274, 22.090834 }, + { 50.276203, 82.446571, 13.741330 }, + { 53.966263, 83.181946, 6.688350 }, + { 56.469967, 84.410866, -1.852795 }, + { 56.649754, 86.141731, -12.806070 }, + { 56.053963, 88.273529, -23.537462 }, + { 54.828842, 90.326775, -33.481480 }, + { 54.078789, 92.206749, -42.363384 }, + { 53.755959, 94.110870, -50.594131 }, + { 53.645256, 96.152504, -58.515736 }, + { 53.616737, 98.319214, -66.308372 }, + { 53.603134, 100.553055, -74.064339 }, + { 53.583805, 102.808044, -81.819321 } + }, + { + { 55.536858, 70.479248, 98.135201 }, + { 51.909939, 71.838448, 76.557159 }, + { 50.733135, 73.104652, 56.592770 }, + { 50.231422, 74.146118, 39.815006 }, + { 50.158398, 74.873299, 26.753271 }, + { 52.390762, 75.846588, 17.866951 }, + { 56.669342, 76.823532, 11.380933 }, + { 59.333538, 78.373009, 2.911109 }, + { 58.972015, 80.813568, -9.888577 }, + { 57.653801, 83.265770, -21.612495 }, + { 56.096855, 84.804550, -31.400345 }, + { 55.721931, 86.109810, -39.426445 }, + { 56.027229, 87.585579, -46.638866 }, + { 56.518898, 89.361908, -53.666191 }, + { 56.968449, 91.360954, -60.760921 }, + { 57.325603, 93.467705, -67.966599 }, + { 57.630013, 95.606682, -75.233376 } + }, + { + { 60.835617, 62.287186, 108.720810 }, + { 58.574310, 63.090485, 88.442451 }, + { 58.632076, 63.610458, 70.191788 }, + { 57.587654, 64.959602, 52.252445 }, + { 56.786499, 66.198250, 37.274319 }, + { 57.142612, 67.595573, 25.797831 }, + { 59.024761, 69.571693, 16.294189 }, + { 61.665577, 70.889435, 8.374887 }, + { 60.929363, 74.194748, -5.421461 }, + { 57.860466, 77.243713, -19.318659 }, + { 57.246773, 78.482849, -28.677536 }, + { 57.789234, 79.487404, -35.748596 }, + { 58.769154, 80.757904, -42.042507 }, + { 59.726368, 82.373650, -48.366081 }, + { 60.454777, 84.242393, -54.999664 }, + { 60.986080, 86.245728, -61.893181 }, + { 61.433384, 88.294586, -68.897163 } + }, + { + { 66.152626, 54.728863, 118.419174 }, + { 65.451439, 55.174313, 99.628922 }, + { 65.574692, 55.527443, 82.401100 }, + { 65.027634, 56.286190, 64.758034 }, + { 62.761868, 57.458168, 47.745918 }, + { 63.968323, 59.320637, 36.684692 }, + { 63.738571, 61.626553, 23.884340 }, + { 62.048912, 63.327644, 10.845825 }, + { 60.989609, 66.370674, -2.782341 }, + { 59.164078, 69.071800, -15.253602 }, + { 59.230465, 70.776108, -24.359180 }, + { 60.584633, 72.163383, -30.889900 }, + { 62.108665, 73.564903, -36.599239 }, + { 63.244358, 75.124565, -42.591801 }, + { 63.981453, 76.905251, -49.095810 }, + { 64.498566, 78.840973, -55.922268 }, + { 64.941475, 80.835503, -62.860661 } + }, + { + { 70.533173, 47.026287, 126.781021 }, + { 70.670006, 47.323288, 108.234634 }, + { 70.586021, 48.191380, 90.278442 }, + { 69.276093, 49.287022, 72.529541 }, + { 68.664490, 50.515930, 57.527279 }, + { 68.627258, 51.199047, 45.146477 }, + { 64.758331, 52.708828, 28.376612 }, + { 65.339172, 54.419094, 17.194853 }, + { 64.482262, 56.923347, 4.357445 }, + { 63.488491, 59.443333, -7.477627 }, + { 62.071716, 62.020397, -18.473246 }, + { 64.161232, 64.251869, -24.810232 }, + { 65.923737, 65.938919, -30.356882 }, + { 66.826492, 67.528633, -36.538982 }, + { 67.374374, 69.309746, -43.227570 }, + { 67.792656, 71.233864, -50.134270 }, + { 68.166611, 73.208839, -57.096157 } + }, + { + { 73.939934, 39.866127, 133.503311 }, + { 74.280457, 40.201031, 114.975929 }, + { 74.623413, 40.956791, 96.343849 }, + { 71.292961, 42.718601, 76.590363 }, + { 71.627800, 43.874702, 62.779766 }, + { 72.951675, 43.995926, 52.728321 }, + { 69.413620, 44.959126, 36.006973 }, + { 69.083672, 46.172497, 24.252304 }, + { 68.446320, 48.536282, 11.912823 }, + { 68.628586, 51.115795, 1.505455 }, + { 67.225105, 53.292290, -10.192417 }, + { 68.382698, 55.863350, -17.726076 }, + { 69.587059, 57.896118, -23.914392 }, + { 70.092896, 59.619385, -30.626682 }, + { 70.515945, 61.489513, -37.585487 }, + { 70.864883, 63.432163, -44.554520 }, + { 71.171707, 65.395912, -51.496876 } + }, + { + { 77.459930, 33.389442, 138.909225 }, + { 77.643188, 34.207474, 120.537880 }, + { 76.730408, 34.601128, 100.607864 }, + { 75.827820, 35.661236, 83.329651 }, + { 75.609306, 36.129303, 69.305710 }, + { 74.893913, 36.704548, 56.538475 }, + { 74.224815, 37.623642, 43.095333 }, + { 74.302284, 38.698273, 31.930655 }, + { 72.851616, 41.070049, 18.897787 }, + { 72.271248, 43.026901, 8.202063 }, + { 72.177193, 45.016754, -1.820263 }, + { 72.077530, 47.150394, -10.797093 }, + { 73.118141, 50.124336, -17.979189 }, + { 73.162987, 51.735378, -25.162161 }, + { 73.475533, 53.542442, -32.246208 }, + { 73.770630, 55.451645, -39.130299 }, + { 74.042282, 57.375195, -45.914577 } + }, + { + { 80.697540, 26.943811, 142.739319 }, + { 80.454338, 27.482140, 124.555565 }, + { 79.779663, 27.904547, 105.693771 }, + { 78.772293, 28.623030, 88.167900 }, + { 77.800255, 28.845112, 72.593651 }, + { 78.183121, 29.680038, 61.610630 }, + { 78.658607, 30.237059, 50.943748 }, + { 77.909271, 31.065199, 38.987003 }, + { 77.996765, 32.668633, 28.423588 }, + { 77.230537, 34.246727, 17.454695 }, + { 75.450470, 36.590130, 4.673000 }, + { 75.238144, 38.213917, -4.392149 }, + { 75.782875, 41.156994, -12.441341 }, + { 76.341270, 43.939987, -20.030560 }, + { 76.343506, 45.546459, -27.210552 }, + { 76.615242, 47.331116, -33.741413 }, + { 76.888046, 49.155640, -40.223724 } + }, + { + { 83.610336, 20.569952, 144.912766 }, + { 82.496559, 20.676317, 126.464432 }, + { 81.376839, 20.864479, 107.652878 }, + { 81.616272, 21.249910, 92.266243 }, + { 81.271210, 21.582018, 78.669212 }, + { 82.938789, 22.651941, 70.114784 }, + { 82.570847, 23.424118, 57.898521 }, + { 80.858009, 24.172062, 43.752327 }, + { 80.229103, 25.692499, 32.034809 }, + { 81.948334, 26.496731, 25.254341 }, + { 80.110931, 28.192329, 13.232217 }, + { 79.036453, 29.082348, 3.402195 }, + { 79.096375, 32.132870, -5.899352 }, + { 79.208931, 34.958199, -14.216118 }, + { 79.346008, 37.331806, -22.005264 }, + { 79.577980, 39.075371, -28.191719 }, + { 79.793808, 40.811565, -34.436527 } + }, + { + { 86.310371, 14.305269, 145.775070 }, + { 84.864708, 14.035273, 127.665421 }, + { 83.163528, 13.907498, 109.474541 }, + { 83.840134, 14.252025, 95.793411 }, + { 84.018166, 14.225272, 82.996414 }, + { 85.252121, 15.372043, 73.502899 }, + { 83.145332, 15.937057, 58.298229 }, + { 81.983795, 17.237209, 44.538807 }, + { 81.616272, 18.604029, 33.910397 }, + { 82.762993, 19.852448, 26.991571 }, + { 82.209915, 20.412176, 17.127321 }, + { 81.873726, 21.732948, 8.222581 }, + { 82.376823, 24.338131, 0.036372 }, + { 82.769989, 26.678829, -7.665060 }, + { 82.541191, 29.041466, -16.154619 }, + { 82.470253, 30.773294, -22.756468 }, + { 82.752739, 32.439934, -28.704720 } + }, + { + { 88.716400, 8.078192, 145.447937 }, + { 87.786942, 7.744143, 129.649139 }, + { 86.498070, 7.313774, 113.158730 }, + { 86.197281, 7.458539, 99.408768 }, + { 87.373940, 7.927577, 87.944847 }, + { 87.857292, 8.748639, 77.295929 }, + { 86.176628, 9.406921, 62.265202 }, + { 84.742706, 10.177112, 48.930237 }, + { 85.993462, 11.479807, 41.211060 }, + { 86.243668, 12.492562, 33.259769 }, + { 86.283119, 13.734988, 24.581404 }, + { 85.813988, 15.049564, 14.738050 }, + { 86.554291, 16.797874, 7.588712 }, + { 86.121330, 18.519869, -1.251622 }, + { 85.895439, 20.799885, -9.977022 }, + { 85.745445, 22.689367, -16.978657 }, + { 85.728592, 24.129206, -23.110125 } + }, + { + { 90.870033, 1.674960, 143.867218 }, + { 90.217918, 0.841768, 129.644333 }, + { 89.827744, 0.337822, 115.945763 }, + { 89.642502, 0.865822, 103.628685 }, + { 89.080299, 1.599789, 91.079132 }, + { 89.022148, 1.717696, 79.840042 }, + { 89.169930, 2.383740, 68.599930 }, + { 89.011078, 3.321553, 57.534733 }, + { 89.214813, 4.140051, 48.821674 }, + { 89.418823, 4.810682, 39.828049 }, + { 89.957382, 7.016832, 31.401020 }, + { 89.794861, 7.817846, 22.352604 }, + { 90.629784, 9.329934, 15.438860 }, + { 89.107040, 11.128892, 4.459541 }, + { 88.945518, 12.479973, -4.248758 }, + { 88.808136, 14.752637, -11.844296 }, + { 88.468315, 15.874557, -18.063000 } + }, + { + { 93.089706, -4.920960, 141.618011 }, + { 92.549927, -6.822685, 127.639893 }, + { 91.930321, -8.983277, 113.009964 }, + { 91.746651, -10.007743, 99.709030 }, + { 91.831970, -8.759332, 90.341927 }, + { 91.701508, -6.822004, 81.732506 }, + { 91.583725, -4.443367, 71.928764 }, + { 91.563530, -3.280141, 61.731621 }, + { 92.285324, -3.099315, 54.009174 }, + { 92.453278, -2.610423, 45.394402 }, + { 92.300430, -0.315785, 35.897743 }, + { 92.729515, -0.094676, 27.993155 }, + { 92.376984, 1.137195, 19.531956 }, + { 92.844994, 3.719659, 11.079104 }, + { 92.223839, 4.776293, 1.963733 }, + { 91.898216, 5.875350, -5.877737 }, + { 91.859802, 8.305871, -13.048352 } + }, + { + { 95.389038, -11.887012, 138.733490 }, + { 95.024551, -14.562854, 125.112938 }, + { 94.637260, -17.469717, 111.004051 }, + { 94.293877, -20.342054, 97.086647 }, + { 94.369949, -20.079315, 88.326431 }, + { 94.518585, -18.899935, 80.476196 }, + { 94.084290, -16.015785, 70.989960 }, + { 93.635017, -10.989694, 62.743744 }, + { 94.089104, -11.183307, 54.320065 }, + { 94.869812, -12.691097, 45.907139 }, + { 94.877419, -8.977646, 38.931377 }, + { 95.294907, -7.480052, 33.306877 }, + { 95.153755, -7.082741, 24.539446 }, + { 95.130432, -4.066227, 15.134933 }, + { 95.572708, -1.759585, 8.184630 }, + { 95.640121, -0.389897, 0.858053 }, + { 95.292290, 1.468389, -7.590969 } + }, + { + { 97.754158, -19.121099, 135.498337 }, + { 97.535713, -22.321255, 122.489861 }, + { 97.244453, -25.190746, 109.739624 }, + { 96.771004, -27.161884, 97.842773 }, + { 96.306892, -27.426241, 88.082397 }, + { 96.729301, -27.640274, 80.065331 }, + { 97.079948, -26.845785, 72.071732 }, + { 97.232704, -24.250675, 64.178589 }, + { 96.918472, -21.464380, 55.986748 }, + { 97.003487, -21.014576, 45.544643 }, + { 97.221298, -17.663111, 40.049976 }, + { 97.778404, -15.158984, 35.137287 }, + { 98.271477, -14.100187, 28.432560 }, + { 98.205032, -12.116192, 20.114220 }, + { 97.820526, -9.019086, 11.347619 }, + { 98.557121, -7.258503, 5.630774 }, + { 98.961845, -5.071193, -1.297562 } + } + }, + { + { + { 36.688290, 99.915314, 60.605904 }, + { 38.405041, 99.911804, 49.498276 }, + { 40.363945, 99.855736, 38.787949 }, + { 42.764114, 99.725571, 28.728138 }, + { 45.689537, 99.550819, 19.408138 }, + { 48.871300, 99.439514, 10.621888 }, + { 51.865654, 99.505074, 2.159902 }, + { 54.364132, 99.864731, -6.117496 }, + { 56.048161, 100.705719, -14.576375 }, + { 56.720039, 102.143372, -23.587648 }, + { 56.422596, 104.246841, -33.281822 }, + { 55.320717, 106.925644, -43.568970 }, + { 53.693401, 109.904060, -54.147541 }, + { 51.835804, 112.902466, -64.692070 }, + { 49.956139, 115.770485, -75.018158 }, + { 48.137817, 118.498611, -85.120956 }, + { 46.366421, 121.156288, -95.110138 } + }, + { + { 43.779247, 91.340202, 74.210709 }, + { 43.673420, 92.019585, 59.207348 }, + { 43.937229, 92.692245, 44.937794 }, + { 45.046070, 93.264503, 32.330265 }, + { 47.319908, 93.627388, 21.986374 }, + { 50.382042, 93.869087, 13.388393 }, + { 53.528847, 94.123428, 5.417353 }, + { 56.083031, 94.514053, -2.833717 }, + { 57.621758, 95.333252, -11.789394 }, + { 58.098366, 96.945038, -21.432245 }, + { 57.543644, 99.270332, -31.570538 }, + { 56.436348, 101.824768, -41.675404 }, + { 55.183681, 104.323273, -51.434105 }, + { 53.971806, 106.713570, -60.813293 }, + { 52.846706, 109.035828, -69.912788 }, + { 51.791458, 111.333199, -78.856758 }, + { 50.767872, 113.626686, -87.745316 } + }, + { + { 50.908531, 82.797966, 87.985077 }, + { 49.565205, 83.881775, 69.939949 }, + { 48.189384, 85.106689, 52.194153 }, + { 48.087772, 86.287483, 37.085712 }, + { 49.485500, 87.284149, 25.380095 }, + { 52.013073, 87.995834, 16.660139 }, + { 55.176651, 88.503082, 9.084156 }, + { 57.446068, 89.110985, 0.427373 }, + { 58.721935, 89.865822, -9.217370 }, + { 59.210979, 91.729500, -19.340094 }, + { 58.522358, 94.323631, -29.856934 }, + { 57.556519, 96.644112, -39.650307 }, + { 56.767887, 98.597023, -48.518520 }, + { 56.214439, 100.393791, -56.751400 }, + { 55.806301, 102.221214, -64.699448 }, + { 55.453465, 104.139832, -72.581078 }, + { 55.110390, 106.114662, -80.469620 } + }, + { + { 57.589550, 74.492783, 101.255981 }, + { 56.117180, 75.491013, 81.924316 }, + { 53.349907, 76.851662, 61.231365 }, + { 52.713985, 78.266144, 44.614178 }, + { 53.235329, 79.882942, 31.544313 }, + { 54.439636, 81.240555, 21.642069 }, + { 57.164951, 82.024643, 13.781807 }, + { 58.520176, 83.377686, 3.933977 }, + { 59.476067, 84.617279, -6.766380 }, + { 59.583015, 86.940918, -17.613361 }, + { 59.191063, 89.316048, -28.034195 }, + { 58.769943, 91.108383, -37.163471 }, + { 58.608559, 92.483315, -45.065620 }, + { 58.701042, 93.787582, -52.266064 }, + { 58.903904, 95.247162, -59.262573 }, + { 59.110504, 96.894020, -66.305420 }, + { 59.297115, 98.639069, -73.418228 } + }, + { + { 63.078342, 66.706207, 112.779800 }, + { 60.384766, 67.576866, 91.493263 }, + { 58.992680, 68.441406, 71.632027 }, + { 59.382164, 69.534187, 55.617046 }, + { 60.196075, 71.135162, 42.607582 }, + { 59.681320, 72.818253, 30.340641 }, + { 59.398361, 74.189804, 19.087774 }, + { 60.622852, 76.283493, 8.810989 }, + { 60.298103, 79.122032, -3.313244 }, + { 59.528725, 81.883011, -15.538560 }, + { 59.886616, 83.652527, -25.491989 }, + { 60.309978, 84.839958, -33.736359 }, + { 60.864922, 85.782570, -40.755859 }, + { 61.517384, 86.808174, -47.191830 }, + { 62.149132, 88.083214, -53.562660 }, + { 62.709053, 89.589195, -60.086075 }, + { 63.222687, 91.206520, -66.727097 } + }, + { + { 68.666924, 59.281513, 123.489960 }, + { 66.332207, 60.022392, 102.351601 }, + { 65.184837, 60.601086, 82.644226 }, + { 65.956032, 61.286366, 66.825439 }, + { 66.684204, 62.426003, 53.508125 }, + { 65.059586, 63.967663, 39.629475 }, + { 64.360023, 65.546425, 26.806763 }, + { 63.495804, 68.109818, 14.464160 }, + { 62.720928, 71.632545, 1.323473 }, + { 61.840694, 74.758194, -11.109055 }, + { 61.766720, 76.552025, -21.086550 }, + { 62.568394, 77.574295, -28.875895 }, + { 63.658833, 78.440384, -35.424267 }, + { 64.645805, 79.470703, -41.532303 }, + { 65.463821, 80.747421, -47.675133 }, + { 66.162994, 82.226448, -54.013344 }, + { 66.811958, 83.800270, -60.478565 } + }, + { + { 73.467705, 51.774593, 132.458008 }, + { 72.516724, 52.408562, 112.369865 }, + { 71.521828, 53.191143, 92.542213 }, + { 70.190758, 54.234955, 74.409828 }, + { 70.007393, 54.752945, 60.417217 }, + { 69.775673, 55.917053, 47.547375 }, + { 68.694466, 57.637142, 33.997166 }, + { 67.044823, 59.366432, 21.230635 }, + { 67.245377, 62.029091, 9.274958 }, + { 67.201637, 65.059464, -2.324881 }, + { 65.052094, 67.781143, -14.294370 }, + { 65.916313, 69.279709, -22.414417 }, + { 67.079613, 70.556053, -29.160650 }, + { 67.970322, 71.860336, -35.476749 }, + { 68.718773, 73.267464, -41.760941 }, + { 69.398834, 74.789436, -48.165668 }, + { 70.053658, 76.375740, -54.655243 } + }, + { + { 77.132301, 44.598946, 139.086624 }, + { 76.853912, 45.092968, 118.976257 }, + { 75.480499, 46.204479, 97.992218 }, + { 70.671471, 48.439346, 76.953476 }, + { 73.807594, 48.262123, 67.259491 }, + { 75.214035, 48.568665, 56.600399 }, + { 74.149460, 49.499374, 43.198547 }, + { 73.892120, 50.624458, 31.581890 }, + { 71.902626, 52.690929, 18.329330 }, + { 71.634789, 55.115467, 7.289275 }, + { 69.327019, 58.092880, -5.728639 }, + { 70.220474, 60.268463, -14.872312 }, + { 70.817139, 62.386520, -22.515419 }, + { 71.288437, 64.059502, -29.359201 }, + { 71.833519, 65.628433, -35.978294 }, + { 72.416199, 67.225563, -42.551498 }, + { 73.008064, 68.870064, -49.131748 } + }, + { + { 79.847588, 38.259377, 143.358810 }, + { 78.675636, 39.115768, 122.014534 }, + { 78.285782, 39.613575, 102.438904 }, + { 77.610466, 40.599167, 87.020706 }, + { 79.230957, 41.093330, 76.768333 }, + { 79.872154, 41.768742, 64.776924 }, + { 78.855896, 41.985077, 51.659176 }, + { 77.875938, 42.750824, 39.361664 }, + { 76.188278, 44.349606, 26.879990 }, + { 75.744507, 46.390327, 15.267989 }, + { 74.133705, 48.830772, 2.610764 }, + { 73.399124, 51.462814, -8.353153 }, + { 74.219017, 54.206993, -16.299948 }, + { 74.481888, 56.082008, -23.514704 }, + { 74.835014, 57.759884, -30.395935 }, + { 75.290047, 59.463341, -37.092003 }, + { 75.781487, 61.225849, -43.724255 } + }, + { + { 82.540932, 32.145336, 146.616745 }, + { 81.160934, 32.701077, 125.856720 }, + { 80.915329, 32.986950, 107.851204 }, + { 82.071327, 33.265720, 94.034996 }, + { 82.114517, 34.128273, 81.235649 }, + { 82.610802, 34.869003, 69.692238 }, + { 81.552299, 34.780773, 57.579247 }, + { 80.776566, 35.406578, 45.409256 }, + { 81.208229, 36.808861, 35.568851 }, + { 80.858154, 38.698914, 24.193680 }, + { 79.212036, 40.564491, 11.561258 }, + { 76.433746, 42.564102, -1.546785 }, + { 77.079826, 45.284351, -10.380394 }, + { 77.524696, 47.790615, -17.940842 }, + { 77.784073, 49.605064, -24.928919 }, + { 78.110992, 51.474594, -31.661455 }, + { 78.485031, 53.406399, -38.277046 } + }, + { + { 85.579605, 25.915577, 149.405197 }, + { 84.502884, 25.673029, 130.443344 }, + { 83.922005, 25.553934, 112.009270 }, + { 85.087440, 26.088091, 98.370575 }, + { 84.392708, 27.073923, 84.548195 }, + { 84.534073, 27.715172, 73.356117 }, + { 84.740562, 27.529100, 63.042175 }, + { 85.658554, 28.811762, 53.033127 }, + { 84.997276, 30.267530, 41.551247 }, + { 84.037521, 31.598318, 30.291777 }, + { 82.992477, 32.355350, 19.536308 }, + { 80.922890, 33.892757, 6.901993 }, + { 80.570099, 36.596882, -3.545864 }, + { 80.597519, 39.096649, -11.872830 }, + { 80.780083, 41.332504, -19.365181 }, + { 80.953491, 43.338497, -26.124706 }, + { 81.203690, 45.378841, -32.716080 } + }, + { + { 88.465195, 19.519770, 150.399551 }, + { 86.569389, 19.001919, 130.961792 }, + { 83.953636, 18.527910, 110.981621 }, + { 85.022385, 19.240419, 98.328857 }, + { 86.359444, 20.441628, 87.655235 }, + { 87.312798, 20.880756, 77.538841 }, + { 87.432838, 20.523823, 66.835182 }, + { 86.647644, 22.319809, 54.383690 }, + { 85.358269, 23.932369, 41.375557 }, + { 87.228477, 24.443521, 35.292377 }, + { 86.056076, 25.524426, 25.180025 }, + { 84.860245, 26.035936, 14.089020 }, + { 83.964821, 27.953773, 3.766033 }, + { 83.875084, 30.954487, -5.325181 }, + { 84.268219, 33.519184, -13.207021 }, + { 83.987190, 35.242516, -20.302776 }, + { 84.012169, 37.122662, -27.037399 } + }, + { + { 90.733536, 12.739808, 149.365204 }, + { 89.276268, 12.692517, 132.605316 }, + { 87.690865, 12.350531, 115.608131 }, + { 87.805557, 12.269123, 102.339783 }, + { 89.387344, 13.826418, 91.372055 }, + { 90.073753, 14.257586, 80.514442 }, + { 89.941376, 14.724685, 68.967323 }, + { 87.762947, 15.964356, 54.369991 }, + { 86.875786, 16.744717, 43.404163 }, + { 88.116272, 16.763790, 37.362484 }, + { 88.068756, 18.747913, 28.435472 }, + { 88.154732, 19.437887, 19.585011 }, + { 88.329346, 20.975426, 11.339172 }, + { 87.849121, 23.473446, 1.726239 }, + { 87.699196, 25.796570, -7.093344 }, + { 87.341454, 27.269760, -14.314291 }, + { 86.993561, 28.737358, -21.309038 } + }, + { + { 92.648087, 5.393196, 146.684952 }, + { 91.978790, 5.866826, 133.847000 }, + { 91.706558, 6.736704, 121.808022 }, + { 91.583336, 7.255363, 108.462563 }, + { 91.029152, 7.572214, 94.360901 }, + { 90.439072, 7.441715, 81.745697 }, + { 90.763855, 7.714839, 71.000038 }, + { 90.548767, 8.915814, 59.444931 }, + { 91.023796, 9.753941, 51.417252 }, + { 91.912331, 11.113091, 43.809669 }, + { 91.534637, 12.528190, 34.081871 }, + { 91.730698, 12.812917, 25.725368 }, + { 92.235023, 13.728673, 18.473150 }, + { 91.765160, 15.850098, 8.626418 }, + { 89.797882, 17.212919, -2.419464 }, + { 90.085976, 18.939486, -9.735577 }, + { 89.971733, 20.481281, -15.937159 } + }, + { + { 94.612671, -2.260512, 143.136475 }, + { 94.238136, -2.270287, 131.318588 }, + { 93.974480, -1.713973, 120.117554 }, + { 94.043449, -0.733555, 109.541527 }, + { 93.940140, 0.600155, 98.175224 }, + { 93.556999, 1.835488, 86.748871 }, + { 93.675896, 1.881620, 76.544907 }, + { 93.860329, 2.027597, 66.453163 }, + { 94.063179, 3.140814, 57.159241 }, + { 94.404381, 4.626008, 48.503357 }, + { 94.347481, 5.114989, 38.977192 }, + { 94.024429, 5.019315, 30.051096 }, + { 94.128319, 5.685556, 22.776838 }, + { 94.199173, 7.942520, 13.770531 }, + { 93.404022, 9.956228, 3.435900 }, + { 92.707062, 10.547346, -4.860276 }, + { 93.293091, 13.190936, -10.817748 } + }, + { + { 96.656845, -10.085104, 139.008530 }, + { 96.395325, -11.312651, 126.754189 }, + { 96.259712, -12.164832, 115.083595 }, + { 96.495872, -12.044371, 105.544731 }, + { 96.387520, -9.912796, 96.883194 }, + { 96.041229, -7.325545, 87.554565 }, + { 95.980072, -5.743129, 78.563446 }, + { 96.058090, -4.485270, 69.116470 }, + { 95.773254, -2.844869, 58.724693 }, + { 96.294159, -2.193801, 51.756031 }, + { 96.389763, -2.227589, 42.437462 }, + { 96.285301, -2.479594, 34.167542 }, + { 96.804405, -1.100444, 27.364597 }, + { 96.880737, 0.534175, 19.293606 }, + { 97.171600, 3.474716, 10.245110 }, + { 96.829399, 5.264803, 1.750960 }, + { 96.805046, 6.827938, -5.494954 } + }, + { + { 98.760368, -18.062004, 134.550674 }, + { 98.586166, -20.571695, 121.918839 }, + { 98.471275, -22.482967, 110.191833 }, + { 98.466064, -22.922596, 100.534302 }, + { 98.475922, -21.571339, 92.957542 }, + { 98.746399, -20.424332, 85.907196 }, + { 98.433105, -17.796642, 76.693054 }, + { 97.726746, -13.039515, 66.771317 }, + { 98.114990, -10.751813, 60.025890 }, + { 98.678322, -12.132895, 53.246109 }, + { 99.244965, -12.623101, 46.439640 }, + { 99.103394, -10.886220, 36.740852 }, + { 99.237404, -7.523942, 28.774591 }, + { 99.813148, -6.187550, 23.309555 }, + { 99.399155, -4.009853, 14.682968 }, + { 99.979889, -2.168140, 8.025488 }, + { 100.000000, 0.000000, 0.000000 } + } + } + } +}; + diff --git a/spectro/dispcal.c b/spectro/dispcal.c index 0a0bc16..97337cd 100644..100755 --- a/spectro/dispcal.c +++ b/spectro/dispcal.c @@ -1632,7 +1632,7 @@ int main(int argc, char *argv[]) { double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */ int out_tvenc = 0; /* 1 to use RGB Video Level encoding */ - int blackbg = 0; /* NZ if whole screen should be filled with black */ + int fullscreen = 0; /* NZ if whole screen should be filled with black */ int verb = 0; int debug = 0; int fake = 0; /* Use the fake device for testing */ @@ -1978,7 +1978,8 @@ int main(int argc, char *argv[]) { /* Number of verify passes */ } else if (argv[fa][1] == 'e') { - verify = 1; + if (verify == 0) + verify = 1; nver = 1; if (na != NULL && na[0] >= '0' && na[0] <= '9') { nver = atoi(na); @@ -1987,6 +1988,8 @@ int main(int argc, char *argv[]) { } else if (argv[fa][1] == 'z') { verify = 2; + if (nver == 0) + nver = 1; mfa = 0; #if defined(UNIX_X11) @@ -2170,9 +2173,9 @@ int main(int argc, char *argv[]) { ho = 2.0 * ho - 1.0; vo = 2.0 * vo - 1.0; - /* Black background */ + /* Full screen black background */ } else if (argv[fa][1] == 'F') { - blackbg = 1; + fullscreen = 1; /* Extra flags */ } else if (argv[fa][1] == 'Y') { @@ -2296,7 +2299,7 @@ int main(int argc, char *argv[]) { #ifdef NT madvrdisp, #endif - out_tvenc, blackbg, override, + out_tvenc, fullscreen, override, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, g_log)) != 0) { error("docalibration failed with return value %d\n",rv); @@ -2325,6 +2328,7 @@ int main(int argc, char *argv[]) { if (verify == 2) warning("Verify flag ignored because we're doing a report only"); verify = 0; + nver = 0; } /* Normally calibrate against native response */ @@ -2334,11 +2338,11 @@ int main(int argc, char *argv[]) { /* Get ready to do some readings */ if ((dr = new_disprd(&errc, ipath, fc, dtype, -1, 0, tele, nadaptive, nocal, noplace, highres, refrate, native, &noramdac, &nocm, NULL, 0, - disp, out_tvenc, blackbg, override, webdisp, ccid, + disp, out_tvenc, fullscreen, override, webdisp, ccid, #ifdef NT madvrdisp, #endif - ccallout, mcallout, + ccallout, mcallout, 0, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, ccs != NULL ? ccs->dtech : cmx != NULL ? cmx->dtech : disptech_unknown, cmx != NULL ? cmx->cc_cbid : 0, @@ -4202,7 +4206,7 @@ int main(int argc, char *argv[]) { x.twh[1] *= x.wh[1]; x.twh[2] *= x.wh[1]; if (verb) - printf("Initial native brightness target = %f cd/m^2\n", x.twh[1]); + printf("\nInitial native brightness target = %f cd/m^2\n", x.twh[1]); } /* Now make sure the target white will fit in gamut. */ @@ -4423,6 +4427,12 @@ int main(int argc, char *argv[]) { } /* - - - - - - - - - - - - - - - - - - - - - */ + /* Make sure nver has a sane value */ + if (verify == 0) + nver = 0; /* 0 verify count if no verify */ + else if (nver == 0) + nver = 1; /* min 1 count if verify */ + /* Start with a scaled down number of test points and refine threshold, */ /* and double/halve these on each iteration. */ if (verb && verify != 2) @@ -4525,28 +4535,28 @@ int main(int argc, char *argv[]) { dr->reset_targ_w(dr); /* Reset white drift target at start of main cal. */ /* Now we go into the main verify & refine loop */ - for (it = verify == 2 ? mxits : 0; - it < mxits || verify != 0; - rsteps *= 2, errthr /= (it < mxits) ? pow(2.0,THRESH_SCALE_POW) : 1.0, it++) { + for (it = (verify == 2) ? mxits : 0; + it < (mxits + nver); + rsteps *= 2, errthr /= (it < mxits) ? pow(2.0,THRESH_SCALE_POW) : 1.0, it++) { int totmeas = 0; /* Total number of measurements in this pass */ col set[3]; /* Variable to read one to three values from the display */ - /* Verify pass */ + /* Verify pass ? */ if (it >= mxits) rsteps = VER_RES; /* Fixed verification resolution */ else thrfail = 0; /* Not verify pass */ - /* re-init asgrey if the number of test points has changed */ - reinit_csamp(&asgrey, &x, verify, (verify == 2 || it >= mxits) ? 1 : 0, rsteps, verb); + reinit_csamp(&asgrey, &x, verify, it >= mxits ? 1 : 0, rsteps, verb); if (verb) { if (it >= mxits) - printf("Doing verify pass with %d sample points\n",rsteps); + printf("\nDoing verify pass %d/%d with %d sample points\n", + it - mxits+1, nver, rsteps); else - printf("Doing iteration %d with %d sample points and repeat threshold of %f DE\n", - it+1,rsteps, errthr); + printf("\nDoing iteration %d/%d with %d sample points and repeat threshold of %f DE\n", + it+1,mxits, rsteps, errthr); } /* Read and adjust each step */ @@ -5093,17 +5103,12 @@ int main(int argc, char *argv[]) { } } - /* Verify loop exit */ - if (nver > 0 && it >= (mxits + nver -1)) { - break; - } - /* Convert our test points into calibration curves. */ /* The call to reinit_csamp() will then convert the */ /* curves back to current test point values. */ /* This applies some level of cohesion between the test points, */ /* as well as forcing monotomicity */ - if (it < mxits) { + if (it < mxits) { /* If not verify pass */ mcvco *sdv[3]; /* Scattered data for mcv */ for (j = 0; j < 3; j++) { @@ -5177,10 +5182,6 @@ int main(int argc, char *argv[]) { } #endif } - - if (verify != 0) /* Do only a single pass */ - break; - } /* Next refine/verify loop */ free_alloc_csamp(&asgrey); /* We're done with test points */ diff --git a/spectro/dispread.c b/spectro/dispread.c index 6af203b..8a78fcc 100644..100755 --- a/spectro/dispread.c +++ b/spectro/dispread.c @@ -209,6 +209,8 @@ void usage(int flag, char *diag, ...) { fprintf(stderr," -Y p Don't wait for the instrument to be placed on the display\n"); fprintf(stderr," -C \"command\" Invoke shell \"command\" each time a color is set\n"); fprintf(stderr," -M \"command\" Invoke shell \"command\" each time a color is measured\n"); +// fprintf(stderr," -x [lx] Take manually entered values, either L*a*b* (-xl) or XYZ (-xx).\n"); + fprintf(stderr," -x x Take manually entered XYZ values\n"); 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," outfile Base name for input[ti1]/output[ti3] file\n"); @@ -225,7 +227,7 @@ int main(int argc, char *argv[]) { double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */ int out_tvenc = 0; /* 1 to use RGB Video Level encoding */ int qbits = 0; /* Quantization bits, 0 = not set */ - int blackbg = 0; /* NZ if whole screen should be filled with black */ + int fullscreen = 0; /* NZ if whole screen should be filled with black */ int verb = 0; int debug = 0; int fake = 0; /* Use the fake device for testing */ @@ -259,6 +261,8 @@ int main(int argc, char *argv[]) { #endif char *ccallout = NULL; /* Change color Shell callout */ char *mcallout = NULL; /* Measure color Shell callout */ + int xtern = 0; /* Use external (user supplied) values rather than */ + /* instument read 1 = Lab, 2 = XYZ */ char inname[MAXNAMEL+1] = "\000"; /* Input cgats file base name */ char outname[MAXNAMEL+1] = "\000"; /* Output cgats file base name */ char calname[MAXNAMEL+1] = "\000"; /* Calibration file name (if any) */ @@ -463,9 +467,9 @@ int main(int argc, char *argv[]) { ho = 2.0 * ho - 1.0; vo = 2.0 * vo - 1.0; - /* Black background */ + /* Full screen black background */ } else if (argv[fa][1] == 'F') { - blackbg = 1; + fullscreen = 1; /* Video encoded output */ } else if (argv[fa][1] == 'E') { @@ -551,6 +555,18 @@ int main(int argc, char *argv[]) { if (na == NULL) usage(0,"Parameter expected after -M"); mcallout = na; + /* Request external values */ + } else if (argv[fa][1] == 'x') { + fa = nfa; + if (na == NULL) usage(0, "Parameter expected after -x"); + + if (na[0] == 'x' || na[0] == 'X') + xtern = 2; +// else if (na[0] == 'l' || na[0] == 'L') +// xtern = 1; + else + usage(0, "Unexpected parameter -x %c",na[0]); + /* Serial port flow control */ } else if (argv[fa][1] == 'W') { fa = nfa; @@ -683,7 +699,7 @@ int main(int argc, char *argv[]) { #ifdef NT madvrdisp, #endif - out_tvenc, blackbg, override, + out_tvenc, fullscreen, override, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, g_log)) != 0) { error("docalibration failed with return value %d\n",rv); @@ -764,15 +780,15 @@ int main(int argc, char *argv[]) { if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0) error ("Input file '%s' doesn't contain field RGB_R",inname); if (icg->t[0].ftype[ri] != r_t) - error ("Input file '%s' field RGB_R is wrong type",inname); + error ("Input file '%s' field RGB_R is wrong type - expect float",inname); if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0) error ("Input file '%s' doesn't contain field RGB_G",inname); if (icg->t[0].ftype[gi] != r_t) - error ("Input file '%s' field RGB_G is wrong type",inname); + error ("Input file '%s' field RGB_G is wrong type - expect float",inname); if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0) error ("Input file '%s' doesn't contain field RGB_B",inname); if (icg->t[0].ftype[bi] != r_t) - error ("Input file '%s' field RGB_B is wrong type",inname); + error ("Input file '%s' field RGB_B is wrong type - expect float",inname); ocg->add_field(ocg, 0, "RGB_R", r_t); ocg->add_field(ocg, 0, "RGB_G", r_t); ocg->add_field(ocg, 0, "RGB_B", r_t); @@ -872,19 +888,19 @@ int main(int argc, char *argv[]) { if ((ii = ccg->find_field(ccg, 0, "RGB_I")) < 0) error ("Calibration file '%s' doesn't contain field RGB_I",calname); if (ccg->t[0].ftype[ii] != r_t) - error ("Field RGB_R in file '%s' is wrong type",calname); + error ("Field RGB_R in file '%s' is wrong type - expect float",calname); if ((ri = ccg->find_field(ccg, 0, "RGB_R")) < 0) error ("Calibration file '%s' doesn't contain field RGB_R",calname); if (ccg->t[0].ftype[ri] != r_t) - error ("Field RGB_R in file '%s' is wrong type",calname); + error ("Field RGB_R in file '%s' is wrong type - expect float",calname); if ((gi = ccg->find_field(ccg, 0, "RGB_G")) < 0) error ("Calibration file '%s' doesn't contain field RGB_G",calname); if (ccg->t[0].ftype[gi] != r_t) - error ("Field RGB_G in file '%s' is wrong type",calname); + error ("Field RGB_G in file '%s' is wrong type - expect float",calname); if ((bi = ccg->find_field(ccg, 0, "RGB_B")) < 0) error ("Calibration file '%s' doesn't contain field RGB_B",calname); if (ccg->t[0].ftype[bi] != r_t) - error ("Field RGB_B in file '%s' is wrong type",calname); + error ("Field RGB_B in file '%s' is wrong type - expect float",calname); for (i = 0; i < ncal; i++) { cal[0][i] = *((double *)ccg->t[0].fdata[i][ri]); cal[1][i] = *((double *)ccg->t[0].fdata[i][gi]); @@ -897,11 +913,11 @@ int main(int argc, char *argv[]) { if ((dr = new_disprd(&errc, ipath, fc, dtype, -1, 0, tele, nadaptive, noautocal, noplace, highres, refrate, native, &noramdac, &nocm, cal, ncal, disp, - out_tvenc, blackbg, override, webdisp, ccid, + out_tvenc, fullscreen, override, webdisp, ccid, #ifdef NT madvrdisp, #endif - ccallout, mcallout, + ccallout, mcallout, xtern, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, ccs != NULL ? ccs->dtech : cmx != NULL ? cmx->dtech : disptech_unknown, cmx != NULL ? cmx->cc_cbid : 0, diff --git a/spectro/dispsup.c b/spectro/dispsup.c index 5751fed..57a598e 100644..100755 --- a/spectro/dispsup.c +++ b/spectro/dispsup.c @@ -96,7 +96,7 @@ inst_code setup_display_calibrate( // dispwin *dw; /* Display window to display test patches on, NULL if none. */ a1logd(p->log,1,"setup_display_calibrate called with calc = 0x%x\n",calc); - switch (calc) { + switch (calc & inst_calc_cond_mask) { case inst_calc_none: /* Use this as a cleanup flag */ if (dwi->dw == NULL && dwi->_dw != NULL) { dwi->_dw->del(dwi->_dw); @@ -112,31 +112,31 @@ inst_code setup_display_calibrate( if (dwi->dw == NULL) { if (dwi->webdisp != 0) { if ((dwi->_dw = new_webwin(dwi->webdisp, dwi->hpatsize, dwi->vpatsize, - dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, dwi->blackbg, - p->log->verb, p->log->debug)) == NULL) { + dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, + dwi->fullscreen, p->log->verb, p->log->debug)) == NULL) { a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error); return inst_other_error; } } else if (dwi->ccid != NULL) { if ((dwi->_dw = new_ccwin(dwi->ccid, dwi->hpatsize, dwi->vpatsize, - dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, dwi->blackbg, - p->log->verb, p->log->debug)) == NULL) { + dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, + dwi->fullscreen, 0, p->log->verb, p->log->debug)) == NULL) { a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error); return inst_other_error; } #ifdef NT } else if (dwi->madvrdisp != 0) { if ((dwi->_dw = new_madvrwin(dwi->hpatsize, dwi->vpatsize, - dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, dwi->blackbg, - p->log->verb, p->log->debug)) == NULL) { + dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, + dwi->fullscreen, p->log->verb, p->log->debug)) == NULL) { a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error); return inst_other_error; } #endif /* NT */ } else { if ((dwi->_dw = new_dispwin(dwi->disp, dwi->hpatsize, dwi->vpatsize, - dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, dwi->blackbg, - dwi->override, p->log->debug)) == NULL) { + dwi->ho, dwi->vo, 0, 0, NULL, NULL, dwi->out_tvenc, + dwi->fullscreen, dwi->override, p->log->debug)) == NULL) { a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error); return inst_other_error; } @@ -157,22 +157,22 @@ inst_code setup_display_calibrate( dwi->dw->set_settling_delay(dwi->dw, tinfo->rise_time, tinfo->fall_time, -1.0); } - if (calc == inst_calc_emis_white) { + if ((calc & inst_calc_cond_mask) == inst_calc_emis_white) { p->cal_gy_level = 1.0; dwi->_dw->set_color(dwi->_dw, 1.0, 1.0, 1.0); - } else if (calc == inst_calc_emis_80pc) { + } else if ((calc & inst_calc_cond_mask) == inst_calc_emis_80pc) { p->cal_gy_level = 0.8; dwi->_dw->set_color(dwi->_dw, 0.8, 0.8, 0.8); } else { - if (calc == inst_calc_emis_grey) { + if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey) { p->cal_gy_level = 0.6; p->cal_gy_count = 0; - } else if (calc == inst_calc_emis_grey_darker) { + } else if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey_darker) { p->cal_gy_level *= 0.7; p->cal_gy_count++; - } else if (calc == inst_calc_emis_grey_ligher) { + } else if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey_ligher) { p->cal_gy_level *= 1.4; if (p->cal_gy_level > 1.0) p->cal_gy_level = 1.0; @@ -216,7 +216,7 @@ ccast_id *ccid, /* non-NULL for ChromeCast */ int madvrdisp, /* NZ for MadVR display */ #endif int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* Override_redirect on X11 */ double hpatsize, /* Size of dispwin */ double vpatsize, @@ -243,7 +243,7 @@ a1log *log /* Verb, debug & error log */ #endif dwi.disp = disp; dwi.out_tvenc = out_tvenc; - dwi.blackbg = blackbg; + dwi.fullscreen = fullscreen; dwi.override = override; dwi.hpatsize = hpatsize; dwi.vpatsize = vpatsize; @@ -318,7 +318,7 @@ a1log *log /* Verb, debug & error log */ if (IMODETST(cap, inst_mode_spectral) && sdtype >= 0) dtype = sdtype; - /* Set the display type */ + /* Set the display type or calibration mode */ if (dtype != 0) { /* Given selection character */ if (cap2 & inst2_disptype) { int ix; @@ -1843,6 +1843,216 @@ static int disprd_fake_read_co(disprd *p, return 0; } +/* Use without a direct connect spectrometer by manual user input */ +/* Return nz on fail/abort - see duspsup.h */ +/* Use disprd_err() to interpret it */ +static int disprd_fake_read_manual(disprd *p, + col *cols, /* Array of patch colors to be tested */ + int npat, /* Number of patches to be tested */ + int spat, /* Start patch index for "verb", 0 if not used */ + int tpat, /* Total patch index for "verb", 0 if not used */ + int acr, /* If nz, do automatic final carriage return */ + int tc, /* If nz, termination key */ + instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */ +) { + int patch, i, j; + int ttpat = tpat; + + if (ttpat < npat) + ttpat = npat; + + /* Continue until the user is done or quits */ + for (patch = 0;;) { + char buf[200], *bp = NULL, *ep = NULL; + char ch = 0; + int allread; + double rgb[3]; + int rv; + char *cmd; + FILE *fp; + + /* Check if all the patches have been read */ + for (allread = i = 0; i < npat; i++) { + if (cols[i].XYZ_v == 0) { + break; + } + } + if (i >= npat) + allread = 1; + + if (spat != 0 && tpat != 0) + a1logv(p->log, 1, "%cpatch %d of %d",cr_char,spat+patch,tpat); + + rgb[0] = cols[patch].r; + rgb[1] = cols[patch].g; + rgb[2] = cols[patch].b; + + /* If we have a test window, display the patch color */ + if (p->dw) { + inst_code rv; + p->dw->enable_update_delay(p->dw, 0); + if ((rv = p->dw->set_color(p->dw, rgb[0], rgb[1], rgb[2])) != 0) { + a1logd(p->log,1,"set_color() returned %d\n",rv); + return 3; + } + p->dw->enable_update_delay(p->dw, 1); + } + + /* If we have a RAMDAC, apply it to the requested color */ + if (p->cal[0][0] >= 0.0) { + double inputEnt_1 = (double)(p->ncal-1); + + for (j = 0; j < 3; j++) { + unsigned int ix; + double val, w; + + val = rgb[j] * inputEnt_1; + if (val < 0.0) { + val = 0.0; + } else if (val > inputEnt_1) { + val = inputEnt_1; + } + ix = (unsigned int)floor(val); /* Coordinate */ + if (ix > (p->ncal-2)) + ix = (p->ncal-2); + w = val - (double)ix; /* weight */ + val = p->cal[j][ix]; + rgb[j] = val + w * (p->cal[j][ix+1] - val); + } + } + + printf("\nReady to read patch %d of %d RGB %.1f %.1f %.1f%s\n", + spat+patch,tpat, rgb[0] * 255.0, rgb[1] * 255.0, rgb[2] * 255.0, + allread ? " (All patches read!)" : + cols[patch].XYZ_v ? " (Already read)" : ""); + + printf("Enter %s value (separated by spaces), or\n", + p->xtern == 1 ? "L*a*b*" : "XYZ"); + printf(" 'f' to move forward\n"); + printf(" 'b' to move back\n"); + printf(" 'd' when done, 'q' to abort : "); + fflush(stdout); + + /* Read in the next line from stdin. */ + if (fgets(buf, 200, stdin) == NULL) { + printf("Error - unrecognised input\n"); + continue; + } + /* Skip whitespace */ + for (bp = buf; *bp != '\000' && isspace(*bp); bp++) + ; + + ch = *bp; /* First character */ + if (ch == '\000') { + printf("Error - unrecognised input\n"); + continue; + } + + /* If it looks like a number */ + if (isdigit(ch) || ch == '-' || ch == '+' || ch == '.') { + + /* For each input number */ + for (i = 0; *bp != '\000' && i < 3; i++) { + char *tp, *nbp; + + /* Find the start of the number */ + while(*bp != '\000' && !isdigit(*bp) + && *bp != '-' && *bp != '+' && *bp != '.') + bp++; + if (!isdigit(*bp) && *bp != '-' && *bp != '+' && *bp != '.') + break; + + /* Find the end of the number */ + for (tp = bp+1; isdigit(*tp) || *tp == 'e' || *tp == 'E' + || *tp == '-' || *tp == '+' || *tp == '.'; tp++) + ; + if (*tp != '\000') + nbp = tp+1; + else + nbp = tp; + *tp = '\000'; + + /* Read the number */ + cols[patch].XYZ[i] = atof(bp); + + bp = nbp; + } + if (i < 3) { /* Didn't find 3 numbers */ + printf("Error - unrecognised input\n"); + continue; + } + if (p->xtern == 1) { + icmLab2XYZ(&icmD50, cols[patch].XYZ, cols[patch].XYZ); + cols[patch].XYZ[0] *= 100.0; + cols[patch].XYZ[1] *= 100.0; + cols[patch].XYZ[2] *= 100.0; + } + + if (clamp) + icmClamp3(cols[patch].XYZ, cols[patch].XYZ); + cols[patch].XYZ_v = 1; + cols[patch].mtype = inst_mrt_emission; + printf(" Got XYZ value %f %f %f\n",cols[patch].XYZ[0], cols[patch].XYZ[1], cols[patch].XYZ[2]); + /* Advance to next patch. */ + patch++; + if (patch >= npat) + patch = 0; + continue; + + /* Assume it's a command */ + } else if (ch == 'f' || ch == 'F') { + patch++; + if (patch >= npat) + patch = 0; + continue; + + } else if (ch == 'b' || ch == 'B') { + patch--; + if (patch < 0) + patch = npat-1; + continue; + + } else if (ch == 'd' || ch == 'D') { + for (allread = i = 0; i < npat; i++) { + if (cols[i].XYZ_v == 0) + break; + } + if (i >= npat) + allread = 1; + + if (allread) + break; + + /* Not all patches have been read */ + empty_con_chars(); + printf("\nDone ? - At least one unread patch (%d), Are you sure [y/n]: ", spat+i); + fflush(stdout); + if ((ch = next_con_char()) == 0x1b) { + printf("\n"); + return 1; + } + printf("\n"); + if (ch == 'y' || ch == 'Y') + break; + continue; + + } else if (ch == 'q' || ch == 'Q' || ch == 0x1b) { + empty_con_chars(); + printf("\nAbort ? - Are you sure ? [y/n]:"); fflush(stdout); + if ((ch = next_con_char()) == 'y' || ch == 'Y') { + printf("\n"); + return 1; + } + printf("\n"); + + } else { + printf("Error - unrecognised input '%c'\n",ch); + continue; + } + } + return 0; +} + /* Return a string describing the error code */ char *disprd_err(int en) { switch(en) { @@ -2008,7 +2218,7 @@ static int config_inst_displ(disprd *p) { if (IMODETST(cap, inst_mode_spectral) && p->sdtype >= 0) dtype = p->sdtype; - /* Set the display type */ + /* Set the display type or calibration mode */ if (dtype != 0) { if (cap2 & inst2_disptype) { int ix; @@ -2150,7 +2360,7 @@ double cal[3][MAX_CAL_ENT], /* Calibration (cal == NULL or cal[0][0] < 0.0 if no int ncal, /* Number of cal[] entries */ disppath *disp, /* Display to calibrate. NULL if fake and no dispwin */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* Override_redirect on X11 */ int webdisp, /* If nz, port number for web color display */ ccast_id *ccid, /* non-NULL for ChromeCast */ @@ -2160,6 +2370,8 @@ int madvrdisp, /* NZ for MadVR display */ char *ccallout, /* Shell callout on set color */ char *mcallout, /* Shell callout on measure color (forced fake) */ //char *scallout, /* Shell callout on results of measure color */ +int xtern, /* Use external (user supplied) values rather than instument read */ + /* 1 = Lab, 2 = XYZ */ double hpatsize, /* Size of dispwin */ double vpatsize, double ho, /* Horizontal offset */ @@ -2220,10 +2432,11 @@ a1log *log /* Verb, debug & error log */ p->noinitplace = noinitplace; p->highres = highres; p->refrate = refrate; - if (mcallout != NULL) + if (mcallout != NULL || xtern != 0) ipath = &icomFakeDevice; /* Force fake device */ p->mcallout = mcallout; // p->scallout = scallout; + p->xtern = xtern; p->ipath = ipath; p->br = baud_19200; p->fc = fc; @@ -2260,7 +2473,7 @@ a1log *log /* Verb, debug & error log */ p->fake_lu = NULL; /* See if there is a profile we should use as the fake device */ - if (p->mcallout == NULL && p->fake_name != NULL + if (p->mcallout == NULL && p->xtern == 0 && p->fake_name != NULL && (p->fake_fp = new_icmFileStd_name(p->fake_name,"r")) != NULL) { if ((p->fake_icc = new_icc()) != NULL) { if (p->fake_icc->read(p->fake_icc,p->fake_fp,0) == 0) { @@ -2282,6 +2495,9 @@ a1log *log /* Verb, debug & error log */ } else if (p->mcallout != NULL) { a1logv(p->log, 1, "Using shell callout '%s' rather than real device\n",p->mcallout); p->read = disprd_fake_read_co; + } else if (p->xtern != 0) { + a1logv(p->log, 1, "Using manual input rather than real device\n"); + p->read = disprd_fake_read_manual; } else p->read = disprd_fake_read; @@ -2357,7 +2573,7 @@ a1log *log /* Verb, debug & error log */ } } else if (ccid != NULL) { if ((p->dw = new_ccwin(ccid, hpatsize, vpatsize, ho, vo, 0, native, noramdac, nocm, - uout_tvenc, 0, p->log->verb, p->log->debug)) == NULL) { + uout_tvenc, 0, 0, p->log->verb, p->log->debug)) == NULL) { a1logd(log,1,"new_disprd failed because new_ccwin('%s') failed\n",ccid->name); p->del(p); if (errc != NULL) *errc = 3; @@ -2386,7 +2602,7 @@ a1log *log /* Verb, debug & error log */ uout_tvenc = 0; } - /* Open display window for positioning (no blackbg) */ + /* Open display window for positioning (no fullscreen) */ if ((p->dw = new_dispwin(disp, hpatsize, vpatsize, ho, vo, 0, native, noramdac, nocm, uout_tvenc, 0, override, p->log->debug)) == NULL) { a1logd(log,1,"new_disprd failed because new_dispwin failed\n"); @@ -2506,10 +2722,10 @@ a1log *log /* Verb, debug & error log */ printf("\n"); } - /* All except web disp can have a black backround when running tests */ - if (webdisp == 0 && blackbg) { + /* All except web disp can have a full screen black backround when running tests */ + if (webdisp == 0 && fullscreen) { - if (p->dw->set_bg(p->dw, blackbg)) { /* Have to re-create window */ + if (p->dw->set_fc(p->dw, fullscreen)) { /* Have to re-create window */ /* Close the positioning window */ if (p->dw != NULL) { @@ -2520,7 +2736,7 @@ a1log *log /* Verb, debug & error log */ /* Open display window again for measurement */ if ((p->dw = new_dispwin(disp, hpatsize, vpatsize, ho, vo, 0, native, noramdac, nocm, - uout_tvenc, blackbg, override, p->log->debug)) == NULL) { + uout_tvenc, fullscreen, override, p->log->debug)) == NULL) { a1logd(log,1,"new_disprd failed new_dispwin failed\n"); p->del(p); if (errc != NULL) *errc = 3; diff --git a/spectro/dispsup.h b/spectro/dispsup.h index e8c3f76..bca3070 100644..100755 --- a/spectro/dispsup.h +++ b/spectro/dispsup.h @@ -26,7 +26,7 @@ struct _disp_win_info { #endif disppath *disp; /* display to calibrate. */ int out_tvenc; /* 1 = use RGB Video Level encoding */ - int blackbg; /* NZ if whole screen should be filled with black */ + int fullscreen; /* NZ if whole screen should be filled with black */ int override; /* Override_redirect on X11 */ double hpatsize; /* Size of dispwin */ double vpatsize; /* Size of dispwin */ @@ -62,7 +62,7 @@ ccast_id *ccid, /* non-NULL for ChromeCast */ int madvrdisp, /* NZ for MadVR display */ #endif int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* Override_redirect on X11 */ double hpatsize, /* Size of dispwin */ double vpatsize, @@ -113,6 +113,8 @@ struct _disprd { icmLuBase *fake_lu; char *mcallout; /* fake instrument shell callout */ // char *scallout; /* measurement XYZ value callout */ + int xtern; /* Use external (user supplied) values rather than instument read */ + /* 1 = Lab, 2 = XYZ */ icompath *ipath; /* Instrument path to open, &icomFakeDevice == fake */ baud_rate br; flow_control fc; @@ -249,7 +251,7 @@ double cal[3][MAX_CAL_ENT], /* Calibration set (cal = NULL or cal[0][0] < 0.0 if int ncal, /* number of entries use in cal */ disppath *screen, /* Screen to calibrate. */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* Override_redirect on X11 */ int webdisp, /* If nz, port number for web display */ ccast_id *ccid, /* non-NULL for ChromeCast */ @@ -259,6 +261,8 @@ int madvrdisp, /* NZ for MadVR display */ char *ccallout, /* Shell callout on set color */ char *mcallout, /* Shell callout on measure color (forced fake) */ //char *scallout, /* Shell callout on results of measure color */ +int xtern, /* Use external (user supplied) values rather than instument read */ + /* 1 = Lab, 2 = XYZ */ double hpatsize, /* Size of dispwin */ double vpatsize, double ho, /* Horizontal offset */ diff --git a/spectro/disptechs.c b/spectro/disptechs.c index 05b9045..d44519c 100644..100755 --- a/spectro/disptechs.c +++ b/spectro/disptechs.c @@ -33,7 +33,8 @@ #include "conv.h" #include "disptechs.h" -/* Other selection characters used: +/* Other selection characters used, + that shouldn't be used in the disptech_info_array[] entries : "n" Non-refresh (Generic) "r" Refresh (Generic) @@ -53,6 +54,11 @@ "z" Eizo CG LCD */ +/* We deliberately duplicate the selection characters, */ +/* because it's not usual to offer the whole list, just */ +/* a sub-set, which may not clash. */ +/* disptechs_set_sel() should be used to present */ +/* unique selectors. */ static disptech_info disptech_info_array[] = { { disptech_none, /* Not applicable entry. Must be first */ @@ -323,9 +329,9 @@ static disptech_info disptech_info_array[] = { }; -static unknown_ix = -1; +static int unknown_ix = -1; -static find_unknown() { +static void find_unknown() { int i; for (i = 0; disptech_info_array[i].dtech != disptech_end; i++) { @@ -372,57 +378,86 @@ disptech_info *disptech_get_strid(char *strid) { if already used, remove it. if no selector remain, - allocate a free one. + allocate a free one from the fallback list. mark all used selectors We treat the first selector as more important - than any aliases that come after it, so we need - to do two passes to resolve what gets used. + than any aliases that come after it, and the + aliases as more important than the fallback list, + so we need to do three passes through all the selections. */ -/* Set the selection characters */ -/* return NZ if we have run out */ -/* If flag & 3 == 1, deal with all selectors & remove any already used */ -/* If flag & 3 == 2, deal with just primary selectors & remove any already used */ -/* If flag & 3 == 3, deal with just secondary selectors & remove any already used */ -/* If flag & 4, allocate selectors to those that don't have any */ -int disptechs_set_sel(int flag, char *sel, char *usels, int *k, char *asels) { +/* Set the selection characters. */ +/* Return NZ if we have not set all selectors */ +/* If a selector is set, its index will be set in usels[], */ +/* and any remaining selection characters deleted. */ +/* If flag == 0, set from just first suggested selector */ +/* If flag == 1, set from just suggested selector */ +/* If flag == 2, set from suggested and fallback selectors */ +/* If flag == 3, set from suggested and fallback selectors, and set unset to nul */ +int disptechs_set_sel( + int flag, /* See above */ + int ix, /* Index of entry being set */ + char *sel, /* Pointer to string list of suggested selectors, */ + /* return a single unique selector in string. */ + char *usels, /* char[256] initially -1, to track used selector entry index */ + int *k, /* Index of next available selector in asels */ + char *asels /* String list of fallback selectors to choose from, in order. */ +) { char *d, *s, i; - /* First remove any used chars from selector */ - if (flag & 3) { - for (i = 0, d = s = sel; *s != '\000'; s++, i++) { - if (((flag & 3) == 3 && i == 0) /* Ignore and keep primary selector */ - || ((flag & 3) == 2 && i == 1)) { /* Ignore and keep secondary selectors */ - *d++ = *s; - continue; - } - if (usels[*s] == 0) { /* If selector is not currently used */ - *d++ = *s; - usels[*s] = 1; - } +//a1logd(g_log, 1,"disptechs_set_sel: flag %d, ix %d, sel '%s', k %d\n",flag, ix,sel,*k); + + /* See if this has already been allocated */ + if (usels[*sel] == ix) { +//a1logd(g_log, 1," set OK\n"); + return 0; /* Nothing to do */ + } + + /* Set from the suggested selectors */ + for (i = 0, s = sel; *s != '\000'; s++, i++) { + if (flag == 0 && i > 0) { +//a1logd(g_log, 1," run out of primaries\n"); + break; /* Looked at primary */ + } + if (usels[*s] == ((char)-1)) { /* If this selector is not currently used */ +//a1logd(g_log, 1," set to '%c' at %d\n", *s, i); + sel[0] = *s; /* Use it */ + sel[1] = '\000'; + usels[*s] = ix; + return 0; } - *d = '\000'; +//a1logd(g_log, 1," sel '%c' at %d is used by ix %d\n", *s, i, usels[*s]); } - /* Add a selector if we need one */ - if ((flag & 4) && sel[0] == '\000') { + if (flag <= 2) { +//a1logd(g_log, 1," returning unset\n"); + return 1; + } - /* Locate the next unused selector */ - for (;;) { - if (asels[*k] == '\000') /* Run out of selectors */ - return 1; - if (usels[*k] == 0) - break; - (*k)++; - } + /* Get the next unused char in fallback list */ + for (;asels[*k] != '\000'; (*k)++) { + if (usels[asels[*k]] == ((char)-1)) /* Unused */ + break; + } + if (asels[*k] != '\000') { +//a1logd(g_log, 1," set int to fallback '%c' at %d\n", asels[*k], *k); sel[0] = asels[*k]; sel[1] = '\000'; - usels[sel[0]] = 1; + usels[sel[0]] = ix; (*k)++; + return 0; + } + + /* Set any unset to nul */ + if (flag >= 3) { +//a1logd(g_log, 1," clearing\n"); + sel[0] = '\000'; } - return 0; +//a1logd(g_log, 1," failed\n"); + /* If we got here, we failed */ + return 1; } /* Return the display tech list with unique lsel lectors */ @@ -434,26 +469,23 @@ disptech_info *disptech_get_list() { static char *asels = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (i = 0; i < 256; i++) - usels[i] = 0; + usels[i] = ((char)-1); k = 0; /* Next selector index */ /* Add entries from the static list and their primary selectors */ for (i = 0; list[i].dtech != disptech_end; i++) { +//a1logd(1,"tech[%d] '%s' sels = '%s'\n",i,list[i].desc,list[i].sel); strcpy(list[i].lsel, list[i].sel); - - if (disptechs_set_sel(2, list[i].lsel, usels, &k, asels)) { - a1loge(g_log, 1, "disptech_get_list run out of selectors\n"); - break; - } + disptechs_set_sel(0, i, list[i].lsel, usels, &k, asels); } - /* Create needed selectors */ + /* Set selectors from secondary */ for (i = 0; list[i].dtech != disptech_end; i++) - disptechs_set_sel(4, list[i].lsel, usels, &k, asels); + disptechs_set_sel(1, i, list[i].lsel, usels, &k, asels); - /* Verify or delete any secondary selectors from the list */ + /* Set remainder from fallback */ for (i = 0; list[i].dtech != disptech_end; i++) - disptechs_set_sel(3, list[i].lsel, usels, &k, asels); + disptechs_set_sel(3, i, list[i].lsel, usels, &k, asels); return list; } diff --git a/spectro/disptechs.h b/spectro/disptechs.h index 8c0a416..68245cf 100644..100755 --- a/spectro/disptechs.h +++ b/spectro/disptechs.h @@ -136,7 +136,8 @@ disptech_info *disptech_select(disptech_info *list, char c); /* - - - - - - - - - - - */ /* utility function, used by disptech_get_list & inst_creat_disptype_list() */ -int disptechs_set_sel(int flag, char *sel, char *usels, int *k, char *asels); +/* See disptechs.c for parameter description. */ +int disptechs_set_sel(int flag, int ix, char *sel, char *usels, int *k, char *asels); /* - - - - - - - - - - */ /* Display settling time model */ diff --git a/spectro/dispwin.c b/spectro/dispwin.c index d5b0797..69536f3 100644..100755 --- a/spectro/dispwin.c +++ b/spectro/dispwin.c @@ -148,6 +148,7 @@ CFUUIDRef CGDisplayCreateUUIDFromDisplayID (uint32_t displayID); # define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx #endif + /* ----------------------------------------------- */ /* Dealing with locating displays */ @@ -287,7 +288,6 @@ static unsigned short *char2wchar(char *s) { #endif /* NT */ - #if defined(UNIX_X11) /* Hack to notice if the error handler has been triggered */ /* when a function doesn't return a value. */ @@ -3916,6 +3916,7 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ return 0; } + /* ----------------------------------------------- */ /* Set a patch delay and instrument reaction time values. */ @@ -3927,9 +3928,9 @@ void dispwin_set_update_delay(dispwin *p, int patch_delay, int inst_reaction) { p->inst_reaction = inst_reaction; } -/* Set/unset the blackground color flag */ +/* Set/unset the full screen black flag */ /* Return nz on error */ -static int dispwin_set_bg(dispwin *p, int blackbg) { +static int dispwin_set_fc(dispwin *p, int fullscreen) { return 1; /* Need to re-create window */ } @@ -3955,6 +3956,7 @@ int dispwin_compute_delay(dispwin *p, double *orgb) { int update_delay = 0, disp_settle = 0; if (p->do_update_del == 0) { + if (p->ddebug) fprintf(stderr,"dispwin: update delay disabled\n"); return 0; } @@ -3979,6 +3981,7 @@ int dispwin_compute_delay(dispwin *p, double *orgb) { return update_delay; } + /* ----------------------------------------------- */ /* Set the shell set color callout */ void dispwin_set_callout( @@ -4337,6 +4340,7 @@ int win_message_thread(void *pp) { #endif /* NT */ + /* Set the defauly update delay values */ void dispwin_set_default_delays(dispwin *p) { char *cp; @@ -4373,6 +4377,7 @@ void dispwin_set_default_delays(dispwin *p) { p->do_update_del = 1; /* Default this to on */ } + /* Create a RAMDAC access and display test window, default grey */ dispwin *new_dispwin( disppath *disp, /* Display to calibrate. */ @@ -4386,7 +4391,7 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* NZ if override_redirect is to be used on X11 */ int ddebug /* >0 to print debug statements to stderr */ ) { @@ -4415,7 +4420,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->nowin = nowin; p->native = native; p->out_tvenc = out_tvenc; - p->blackbg = blackbg; + p->fullscreen = fullscreen; p->ddebug = ddebug; p->get_ramdac = dispwin_get_ramdac; p->set_ramdac = dispwin_set_ramdac; @@ -4423,7 +4428,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->uninstall_profile = dispwin_uninstall_profile; p->get_profile = dispwin_get_profile; p->set_color = dispwin_set_color; - p->set_bg = dispwin_set_bg; + p->set_fc = dispwin_set_fc; p->set_update_delay = dispwin_set_update_delay; p->set_settling_delay = dispwin_set_settling_delay; p->enable_update_delay = dispwin_enable_update_delay; @@ -4482,7 +4487,7 @@ int ddebug /* >0 to print debug statements to stderr */ if (he > disp_vrz) he = disp_vrz; - if (p->blackbg) { /* Window fills the screen, test area is within it */ + if (p->fullscreen) { /* Window fills the screen, test area is within it */ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5); p->ty = (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5); p->tw = wi; @@ -4688,7 +4693,7 @@ int ddebug /* >0 to print debug statements to stderr */ /* (Because Cocoa origin is botton left, we flip voff) */ /* (Cocoa doesn't use disp->sx/sy either - each screen origin is at 0,0) */ - if (p->blackbg) { /* Window fills the screen, test area is within it */ + if (p->fullscreen) { /* Window fills the screen, test area is within it */ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5); p->ty = (int)((-voff * 0.5 + 0.5) * (disp->sh - he) + 0.5); p->tw = wi; @@ -4837,7 +4842,7 @@ int ddebug /* >0 to print debug statements to stderr */ if (he > disp_vrz) he = disp_vrz; - if (p->blackbg) { /* Window fills the screen, test area is within it */ + if (p->fullscreen) { /* Window fills the screen, test area is within it */ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5); p->ty = (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5); p->tw = wi; @@ -5357,7 +5362,8 @@ int x11_daemon_mode(disppath *disp, int verb, int ddebug) { return -1; } -#endif +#endif /* UNIX_X11 */ + /* ================================================================ */ #ifdef STANDALONE_TEST @@ -5477,7 +5483,7 @@ main(int argc, char *argv[]) { double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */ int out_tvenc = 0; /* 1 to use RGB Video Level encoding */ - int blackbg = 0; /* NZ if whole screen should be filled with black */ + int fullscreen = 0; /* NZ if whole screen should be filled with black */ int nowin = 0; /* Don't create test window */ int ramd = 0; /* Just test ramdac */ int fade = 0; /* Test greyramp fade */ @@ -5612,25 +5618,25 @@ main(int argc, char *argv[]) { /* Test patch offset and size */ else if (argv[fa][1] == 'P') { fa = nfa; - if (na == NULL) usage(0,"-p parameters are missing"); + if (na == NULL) usage(0,"-P parameters are missing"); if (sscanf(na, " %lf,%lf,%lf,%lf ", &ho, &vo, &hpatscale, &vpatscale) == 4) { ; } else if (sscanf(na, " %lf,%lf,%lf ", &ho, &vo, &hpatscale) == 3) { vpatscale = hpatscale; } else { - usage(0,"-p parameters '%s' is badly formatted",na); + usage(0,"-P parameters '%s' is badly formatted",na); } if (ho < 0.0 || ho > 1.0 || vo < 0.0 || vo > 1.0 || hpatscale <= 0.0 || hpatscale > 50.0 || vpatscale <= 0.0 || vpatscale > 50.0) - usage(0,"-p parameters '%s' is out of range",na); + usage(0,"-P parameters '%s' is out of range",na); ho = 2.0 * ho - 1.0; vo = 2.0 * vo - 1.0; /* Black background */ } else if (argv[fa][1] == 'F') { - blackbg = 1; + fullscreen = 1; /* Video mode encoding */ } else if (argv[fa][1] == 'E') { @@ -5769,7 +5775,7 @@ main(int argc, char *argv[]) { if (webdisp != 0) { if ((dw = new_webwin(webdisp, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, native, - &noramdac, &nocm, out_tvenc, blackbg, verb, ddebug)) == NULL) { + &noramdac, &nocm, out_tvenc, fullscreen, verb, ddebug)) == NULL) { printf("Error - new_webwin failed!\n"); return -1; } @@ -5793,7 +5799,7 @@ main(int argc, char *argv[]) { if ((dw = new_ccwin(ids[ccdisp-1], 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, native, &noramdac, &nocm, out_tvenc, - blackbg, verb, ddebug)) == NULL) { + fullscreen, 0, verb, ddebug)) == NULL) { printf("Error - new_ccwin failed!\n"); free_ccids(ids); return -1; @@ -5808,7 +5814,7 @@ main(int argc, char *argv[]) { } if ((dw = new_madvrwin(100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, native, - &noramdac, &nocm, out_tvenc, blackbg, verb, ddebug)) == NULL) { + &noramdac, &nocm, out_tvenc, fullscreen, verb, ddebug)) == NULL) { printf("Error - new_madvrwin failed! (Is it running and up to date?)\n"); return -1; } @@ -5816,7 +5822,7 @@ main(int argc, char *argv[]) { } else { if (verb) printf("About to open dispwin object on the display\n"); if ((dw = new_dispwin(disp, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, native, - &noramdac, &nocm, out_tvenc, blackbg, 1, ddebug)) == NULL) { + &noramdac, &nocm, out_tvenc, fullscreen, 1, ddebug)) == NULL) { printf("Error - new_dispwin failed!\n"); return -1; } @@ -6175,6 +6181,7 @@ main(int argc, char *argv[]) { printf("Verify: '%s' is NOT loaded (discrepancy %.1f%%)\n", calname, berr * 100); } + /* If no other command selected, do a Window or VideoLUT test */ if (sname[0] == '\000' && clear == 0 && installprofile == 0 && loadfile == 0 && verify == 0 && loadprofile == 0) { diff --git a/spectro/dispwin.h b/spectro/dispwin.h index 43e23d2..b5e14ce 100644..100755 --- a/spectro/dispwin.h +++ b/spectro/dispwin.h @@ -176,10 +176,18 @@ struct _ramdac { /* - - - - - - - - - - - - - - - - - - - - - - - */ /* Dispwin object */ /* This is used by all the different test patch window types, */ -/* dispwin, webwin, madvrwin and ccwin. +/* dispwin, webwin, madvrwin and ccwin. */ /* !!!! Make changes in dispwin.c, webwin.c, madvrwin.c & ccwin.c !!!! */ /* !!!! if this structure gets changed. !!!! */ +/* Full screen background handling */ +typedef enum { + dw_bg_black = 0, /* Black background */ + dw_bg_grey = 1, /* Grey background */ + dw_bg_cvideo = 2, /* Constant Average Video background */ + dw_bg_clight = 3 /* Constant Average Light background */ +} dw_bg_type; + struct _dispwin { /* private: */ @@ -218,7 +226,9 @@ struct _dispwin { ramdac *or; /* Original ramdac contents, NULL if not accessible, restored on exit */ ramdac *r; /* Ramdac in use for native mode or general use */ double width, height; /* Orginial size in mm or % */ - int blackbg; /* NZ if black full screen background */ + int fullscreen; /* NZ if full screen background (default black) */ + dw_bg_type bge; /* Full screen background color (ccwin only) */ + double area; /* Patch area for bge calc 0..1 */ char *callout; /* if not NULL - set color Shell callout routine */ @@ -329,13 +339,20 @@ struct _dispwin { /* Return nz on error */ int (*set_color)(struct _dispwin *p, double r, double g, double b); - /* Set/unset the blackground color flag. */ + /* Set/unset the fullscreen black flag. */ /* Will only change on next set_col() */ /* Return nz on error */ - int (*set_bg)(struct _dispwin *p, int blackbg); + int (*set_fc)(struct _dispwin *p, int fullscreen); + /* Change the patch display parameters. */ /* Optional - may be NULL */ - /* set patch info */ + int (*set_patch_win)(struct _dispwin *p, + double hoff, double voff, /* Offset from c. in fraction of screen, -1.0 .. 1.0 */ + double area, /* Patch area 0..1 */ + dw_bg_type bge /* Background */ + ); + + /* set patch user info */ /* Return nz on error */ int (*set_pinfo)(struct _dispwin *p, int pno, int tno); @@ -356,6 +373,7 @@ struct _dispwin { /* Set a shell set color callout command line */ void (*set_callout)(struct _dispwin *p, char *callout); + /* Destroy ourselves */ void (*del)(struct _dispwin *p); @@ -374,7 +392,7 @@ dispwin *new_dispwin( int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ - int blackbg, /* NZ if whole screen should be filled with black */ + int fullscreen, /* NZ if whole screen should be filled with black */ int override, /* NZ if override_redirect is to be used on X11 */ int ddebug /* >0 to print debug statements to stderr */ ); diff --git a/spectro/dtp20.c b/spectro/dtp20.c index a460bb8..a504803 100644..100755 --- a/spectro/dtp20.c +++ b/spectro/dtp20.c @@ -1128,7 +1128,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (*calt & inst_calt_ref_white) { int i; - if (*calc != inst_calc_man_ref_white) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) { char *cp; if ((ev = dtp20_command(p, "04SN\r", buf, MAX_MES_SIZE, 4.5)) != inst_ok) return ev; @@ -1725,7 +1725,7 @@ extern dtp20 *new_dtp20(icoms *icom, instType itype) { p->del = dtp20_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; p->cap = inst_mode_none; /* Unknown until set */ p->mode = inst_mode_none; /* Not in a known mode yet */ diff --git a/spectro/dtp20.h b/spectro/dtp20.h index c575c67..c575c67 100644..100755 --- a/spectro/dtp20.h +++ b/spectro/dtp20.h diff --git a/spectro/dtp22.c b/spectro/dtp22.c index a80f887..d332ffc 100644..100755 --- a/spectro/dtp22.c +++ b/spectro/dtp22.c @@ -684,7 +684,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (*calt & inst_calt_ref_white) { /* White calibration */ sprintf(id, "Serial no. %d",p->plaqueno); - if (*calc != inst_calc_man_ref_whitek) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_whitek) { *calc = inst_calc_man_ref_whitek; ev = inst_cal_setup; goto do_exit; @@ -744,7 +744,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ } if (*calt & inst_calt_ref_dark) { /* Black calibration */ - if (*calc != inst_calc_man_ref_dark) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_dark) { *calc = inst_calc_man_ref_dark; ev = inst_cal_setup; goto do_exit; @@ -1079,7 +1079,7 @@ extern dtp22 *new_dtp22(icoms *icom, instType itype) { p->del = dtp22_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; p->mode = inst_mode_none; p->need_cal = 1; /* Do a white calibration each time we open the device */ diff --git a/spectro/dtp22.h b/spectro/dtp22.h index 95dce16..95dce16 100644..100755 --- a/spectro/dtp22.h +++ b/spectro/dtp22.h diff --git a/spectro/dtp41.c b/spectro/dtp41.c index a2f7e83..5c3361c 100644..100755 --- a/spectro/dtp41.c +++ b/spectro/dtp41.c @@ -923,8 +923,9 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) { if (*calt & inst_calt_trans_white) { - if (*calc != inst_calc_uop_trans_white) - *calc = inst_calc_uop_trans_white; /* Ask user to do calibration */ + if ((*calc & inst_calc_cond_mask) != inst_calc_uop_trans_white) + /* Ask user to do calibration */ + *calc = inst_calc_uop_trans_white; return inst_cal_setup; } @@ -934,8 +935,9 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ } else { if (*calt & inst_calt_ref_white) { - if (*calc != inst_calc_uop_ref_white) { - *calc = inst_calc_uop_ref_white; /* Ask user to do calibration */ + if ((*calc & inst_calc_cond_mask) != inst_calc_uop_ref_white) { + /* Ask user to do calibration */ + *calc = inst_calc_uop_ref_white; return inst_cal_setup; } @@ -1283,7 +1285,7 @@ extern dtp41 *new_dtp41(icoms *icom, instType itype) { p->del = dtp41_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; p->cap = inst_mode_none; /* Unknown until set */ p->mode = inst_mode_none; /* Not in a known mode yet */ p->nstaticr = 5; /* Number of static readings */ diff --git a/spectro/dtp41.h b/spectro/dtp41.h index 529f94c..529f94c 100644..100755 --- a/spectro/dtp41.h +++ b/spectro/dtp41.h diff --git a/spectro/dtp51.c b/spectro/dtp51.c index 062ad7f..cfd1265 100644..100755 --- a/spectro/dtp51.c +++ b/spectro/dtp51.c @@ -635,8 +635,9 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (*calt & inst_calt_ref_white) { - if (*calc != inst_calc_uop_ref_white) { - *calc = inst_calc_uop_ref_white; /* Ask user to do calibration */ + if ((*calc & inst_calc_cond_mask) != inst_calc_uop_ref_white) { + /* Ask user to do calibration */ + *calc = inst_calc_uop_ref_white; return inst_cal_setup; } p->need_cal = 0; @@ -892,7 +893,7 @@ extern dtp51 *new_dtp51(icoms *icom, instType itype) { p->del = dtp51_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; return p; } diff --git a/spectro/dtp51.h b/spectro/dtp51.h index 329c5d6..329c5d6 100644..100755 --- a/spectro/dtp51.h +++ b/spectro/dtp51.h diff --git a/spectro/dtp92.c b/spectro/dtp92.c index 9524326..1ed9bc1 100644..100755 --- a/spectro/dtp92.c +++ b/spectro/dtp92.c @@ -819,7 +819,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (*calt & inst_calt_emis_offset) { /* Dark offset calibration */ - if (*calc != inst_calc_man_em_dark) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) { *calc = inst_calc_man_em_dark; return inst_cal_setup; } @@ -833,9 +833,9 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (*calt & inst_calt_emis_ratio) { /* Cell ratio calibration */ - if (*calc != inst_calc_emis_grey - && *calc != inst_calc_emis_grey_darker - && *calc != inst_calc_emis_grey_ligher) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_grey + && (*calc & inst_calc_cond_mask) != inst_calc_emis_grey_darker + && (*calc & inst_calc_cond_mask) != inst_calc_emis_grey_ligher) { *calc = inst_calc_emis_grey; return inst_cal_setup; } @@ -1405,7 +1405,7 @@ extern dtp92 *new_dtp92(icoms *icom, instType itype) { p->del = dtp92_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */ set_base_disptype_list(p); diff --git a/spectro/dtp92.h b/spectro/dtp92.h index 317fb7a..317fb7a 100644..100755 --- a/spectro/dtp92.h +++ b/spectro/dtp92.h diff --git a/spectro/ex1.c b/spectro/ex1.c index 06f5597..93d0a31 100644..100755 --- a/spectro/ex1.c +++ b/spectro/ex1.c @@ -58,155 +58,102 @@ #include "insttypes.h" #include "conv.h" #include "icoms.h" +#include "inst.h" +#include "rspec.h" #include "ex1.h" +#define ENABLE_NONVCAL /* [Def] Enable saving calibration state between program runs in a file */ + +#undef DEBUG +#undef PLOT_DEBUG /* Use plot to show readings & processing */ +#undef TEST_DARK_INTERP /* Test adaptive dark interpolation */ + +#define EX1_MAX_MEAS_TIME 1.0 /* Maximum measurement time to use */ + +/* ----------------------------------------------------------------- */ +/* High level EX1 commands, implemented at the bottom of the file */ + +#define EX1_EP 0x1 /* End point to use. Can use 1 and/or 2 */ +#define MIN_CYCLE_TIME 0.009 /* Minimum time per measurement cycle */ + +#define SENSE_AIM (0.85 * ((1 << 14)-1)) /* Sensor level aim point */ +#define SENSE_SAT (0.95 * ((1 << 14)-1)) /* Saturation level */ + +#define DCALTOUT (1 * 60 * 60) /* [1 Hour ??] Dark Calibration timeout in seconds */ + +static int icoms2ex1_err(int se); static inst_code ex1_interp_code(inst *pp, int ec); +static char *ex1_interp_native_error(ex1 *p, int ec); -#define MAX_MES_SIZE 500 /* Maximum normal message reply size */ -#define MAX_RD_SIZE 8000 /* Maximum reading message reply size */ +static void ex1_flush(ex1 *p); +static int ex1_get_hw_rev(ex1 *p, int *hwrev); +static int ex1_get_fw_rev(ex1 *p, int *fwrev); +static int ex1_get_slit_width(ex1 *p, int *swidth); +static int ex1_get_fiber_width(ex1 *p, int *fibw); +static int ex1_get_grating(ex1 *p, char **grating); +static int ex1_get_filter(ex1 *p, char **filter); +static int ex1_get_coating(ex1 *p, char **coating); +static int ex1_get_alias(ex1 *p, char **alias); +static int ex1_get_serno(ex1 *p, char **serno); +static int ex1_get_wl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs); +static int ex1_get_nl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs); +static int ex1_get_ir_coefs(ex1 *p, unsigned int *nocoefs, double **coefs, double *area); +static int ex1_get_sl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs); -/* Interpret an icoms error into a EX1 error */ -static int icoms2ex1_err(int se) { - if (se != ICOM_OK) { - if (se & ICOM_TO) - return EX1_TIMEOUT; - return EX1_COMS_FAIL; - } - return EX1_OK; -} +#define EX1_TRIGMODE_IMED 0x0 /* Immediate software trigger mode. */ +#define EX1_TRIGMODE_TRIG 0x1 /* Trigger on ext trigger signal after possible delay. */ +#define EX1_TRIGMODE_STROBE 0x2 /* Trigger afer possible delay on internal cont. strobe. */ -/* Debug - dump a command packet at debug level deb1 */ -static void dump_command(ex1 *p, ORD8 *buf, int len, int debl) { - if (debl < p->log->debug) - return; +static int ex1_set_trig_mode(ex1 *p, int trigmode); - if (len < 64) { - a1logd(p->log, 4, "Command packet too short (%d bytes)\n",len); - return; - } +#define EX1_INTTIME_MIN 10.0e-6 +#define EX1_INTTIME_MAX 10.0 - if (buf[0] != 0xC1 || buf[1] != 0xC0) { - a1logd(p->log, 4, "Command missing start bytes (0x%02x, 0x%02x)\n",buf[0],buf[1]); - } +static int ex1_set_inttime(ex1 *p, double *qinttime, double inttime); - // ~~~~999 - // etc. -} +#define EX1_DELTIME_MIN 5.0e-6 +#define EX1_DELTIME_MAX 335.5e-3 -/* Do a full command/response exchange with the ex1 */ -/* (This level is not multi-thread safe) */ -/* Return the ex1 error code. */ -static int -ex1_fcommand( -ex1 *p, -char *in, /* In string */ -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 */ -int nd /* nz to disable debug messages */ -) { - int se; - int bread = 0; - char *cp, *tc = "", *dp; +static int ex1_set_trig_delay(ex1 *p, double *qtrigdel, double trigdel); - // ~~~99 - return EX1_NOT_IMP; - - if (ctype == 0) - tc = "\r\006\025"; /* Return, Ack or Nak */ - else if (ctype == 1) - tc = "\007\025"; /* Bell or Nak */ - else if (ctype == 2) - tc = "\r\025"; /* Return or Nak */ - - se = p->icom->write_read(p->icom, in, 0, out, bsize, &bread, tc, ntc, to); - - /* 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) - se = ICOM_OK; - - if (se != 0) { - if (!nd) a1logd(p->log, 1, "ex1_fcommand: serial i/o failure on write_read '%s' 0x%x\n",icoms_fix(in),se); - return icoms2ex1_err(se); - } - - /* 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 */ - char buf[100]; - - if ((se = p->icom->write_read(p->icom, "*stat:err?\r", 0, buf, 100, NULL, "\r", 1, 1.0)) != 0) { - if (!nd) a1logd(p->log, 1, "ex1_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in)); - return icoms2ex1_err(se);; - } - if (sscanf(buf, "Error Code: %d ",&se) != 1) { - if (!nd) a1logd(p->log, 1, "ex1_fcommand: failed to parse error code '%s'\n",icoms_fix(buf)); - return EX1_DATA_PARSE_ERROR; - } - - if (!nd) a1logd(p->log, 1, "Got ex1 error code %d\n",se); - break; - } - if (*cp == '\005') /* Got an Enquire */ - continue; /* remove it */ - *dp = *cp; - dp++; - } - out[bsize-1] = '\000'; +#define EX1_STRBPER_MIN 50.0e-6 +#define EX1_STRBPER_MAX 5.0 - if (!nd) a1logd(p->log, 4, "ex1_fcommand: command '%s' returned '%s' bytes %d, err 0x%x\n", - icoms_fix(in), icoms_fix(out),strlen(out), se); - return se; -} +static int ex1_set_strobe_period(ex1 *p, double *qstbper, double stbper); -/* Do a normal command/response echange with the ex1. */ -/* (This level is not multi-thread safe) */ -/* Return the inst code */ -static inst_code -ex1_command( -struct _ex1 *p, -char *in, /* In string */ -char *out, /* Out string buffer */ -int bsize, /* Out buffer size */ -double to) { /* Timout in seconds */ - int rv = ex1_fcommand(p, in, out, bsize, to, 1, 0, 0); - return ex1_interp_code((inst *)p, rv); -} +#define EX1_STRB_DISABLE 0x0 /* Continuous strobe disabled */ +#define EX1_STRB_ENABLE 0x1 /* Continuous strobe enabled */ -/* Read another line of response */ -/* (This level is not multi-thread safe) */ -/* Return the inst code */ -static int -ex1_readresp( -struct _ex1 *p, -char *out, /* Out string buffer */ -int bsize, /* Out buffer size */ -double to /* Timeout in seconds */ -) { - int rv, se; - char *cp, *tc = "\r\006\025"; /* Return, Ack or Nak */ +static int ex1_set_strobe_enable(ex1 *p, int enable); - // ~~~999 - return inst_unsupported; +static int ex1_set_single_strobe_enable(ex1 *p, int enable); - if ((se = p->icom->read(p->icom, out, bsize, NULL, tc, 1, to)) != 0) { - a1logd(p->log, 1, "ex1_readresp: serial i/o failure\n"); - return icoms2ex1_err(se); - } - return inst_ok; -} +#define EX1_AVERAGE_MIN 1 +#define EX1_AVERAGE_MAX 5000 + +static int ex1_set_average(ex1 *p, int noavg); + +#define EX1_BIN_OFF 0x0 /* Full res, 1024 bins */ +#define EX1_BIN_2 0x1 /* 1/2 res, 512 bins */ +#define EX1_BIN_4 0x2 /* 1/4 res, 256 bins */ +#define EX1_BIN_8 0x3 /* 1/8 res, 128 bins */ + +static int ex1_set_binning(ex1 *p, int bf); + +#define EX1_BOXCAR_MIN 0 +#define EX1_BOXCAR_MAX 15 + +static int ex1_set_boxcar(ex1 *p, int nobox); + +static int ex1_measure(ex1 *p, double *raw); + +/* ----------------------------------------------------------------- */ /* Establish communications with a ex1 */ /* Return EX1_COMS_FAIL on failure to establish communications */ static inst_code ex1_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { ex1 *p = (ex1 *) pp; - char buf[MAX_MES_SIZE]; - baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_nc }; instType itype = pp->itype; int se; @@ -214,23 +161,30 @@ ex1_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { a1logd(p->log, 2, "ex1_init_coms: called\n"); - amutex_lock(p->lock); - if (p->icom->port_type(p->icom) != icomt_usb) { - amutex_unlock(p->lock); a1logd(p->log, 1, "ex1_init_coms: wrong communications type for device!\n"); return inst_coms_fail; } - // ~~~99 check it is responding. + /* Set config, interface, write end point, read end point, read quanta */ + if ((se = p->icom->set_usb_port(p->icom, 1, EX1_EP, EX1_EP | 0x80, icomuf_none, 0, NULL)) != ICOM_OK) { + a1logd(p->log, 1, "ex1_init_coms: set_usbe_port failed ICOM err 0x%x\n",se); + return ex1_interp_code((inst *)p, icoms2ex1_err(se)); + } - // ~~~99 check the model type + /* Should we reset it ? */ - a1logd(p->log, 2, "ex1_init_coms: init coms has suceeded\n"); + /* Make sure no message is waiting */ + ex1_flush(p); + + /* Check it is responding */ + if ((se = ex1_get_hw_rev(p, &p->hwrev)) != EX1_OK) { + return ex1_interp_code((inst *)p, se); + } p->gotcoms = 1; - amutex_unlock(p->lock); + a1logd(p->log, 2, "ex1_init_coms: init coms has suceeded\n"); return inst_ok; } @@ -240,218 +194,288 @@ ex1_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { static inst_code ex1_init_inst(inst *pp) { ex1 *p = (ex1 *)pp; - char mes[100]; - char buf[MAX_MES_SIZE]; inst_code ev = inst_ok; + rspec_inf *sconf = &p->sconf; + unsigned int count, i; a1logd(p->log, 2, "ex1_init_inst: called\n"); if (p->gotcoms == 0) return inst_internal_error; /* Must establish coms before calling init */ - - amutex_lock(p->lock); - /* Restore the instrument to it's default settings */ - if ((ev = ex1_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 = ex1_command(p, "*para:calibn 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + p->lo_secs = 2000000000; /* A very long time */ + p->max_meastime = EX1_MAX_MEAS_TIME; + + /* Get information about the instrument */ + if ((ev = ex1_get_alias(p, &p->alias)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_hw_rev(p, &p->hwrev)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_fw_rev(p, &p->fwrev)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_serno(p, &p->serno)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_slit_width(p, &p->slitw)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_fiber_width(p, &p->fiberw)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_grating(p, &p->grating)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_filter(p, &p->filter)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + if ((ev = ex1_get_coating(p, &p->coating)) != EX1_OK) + return ex1_interp_code((inst *)p, ev); + + /* Set the instrument to sane defaults: */ + + /* Set trigger mode to software immediate */ + if ((ev = ex1_set_trig_mode(p, EX1_TRIGMODE_IMED)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - /* Set auto exposure/integration time */ - /* Set calibration type to auto on ambient cap */ - if ((ev = ex1_command(p, "*para:expo 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok - || (ev = ex1_command(p, "*para:adapt 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Set integration time to minimum */ + if ((ev = ex1_set_inttime(p, &p->inttime, EX1_INTTIME_MIN)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - p->measto = 20.0; /* default */ - - if (p->model == 1211) - p->measto = 5.0; /* Same overall time as i1d3 ?? */ - else if (p->model == 1201) - p->measto = 15.0; + /* Set trigger delay time to minumum */ + if ((ev = ex1_set_trig_delay(p, NULL, EX1_DELTIME_MIN)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); + } - /* Set maximum integration time to speed up display measurement */ - sprintf(mes, "*conf:maxtin %d\r", (int)(p->measto * 1000.0+0.5)); - if ((ev = ex1_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Disable continuous strobe */ + if ((ev = ex1_set_strobe_enable(p, EX1_STRB_DISABLE)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - /* Set the measurement function to be Radiometric spectrum */ - if ((ev = ex1_command(p, "*conf:func 6\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Disable single strobe */ + if ((ev = ex1_set_single_strobe_enable(p, EX1_STRB_DISABLE)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - /* Set the measurement format to ASCII */ - if ((ev = ex1_command(p, "*conf:form 4\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Set averages to 1 */ + if ((ev = ex1_set_average(p, EX1_AVERAGE_MIN)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - if ((ev = ex1_command(p, "*para:wavbeg?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Turn off binning */ + if ((ev = ex1_set_binning(p, EX1_BIN_OFF)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - if (sscanf(buf, "Predefined start wave: %lf ",&p->wl_short) != 1) { - amutex_unlock(p->lock); - a1loge(p->log, 1, "ex1_init_inst: failed to parse start wave\n"); - return ev; + + /* Turn off boxcar filtering */ + if ((ev = ex1_set_boxcar(p, EX1_BOXCAR_MIN)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - a1logd(p->log, 1, " Short wl range %f\n",p->wl_short); - if ((ev = ex1_command(p, "*para:wavend?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Setup calibration information and measurement config. */ + clear_rspec_inf(sconf); + sconf->log = p->log; + sconf->nsen = 1024; + sconf->nshgrps = 0; + sconf->nilltkgrps = 0; + sconf->lightrange.off = 0; /* All of sensor value go to raw */ + sconf->lightrange.num = sconf->nsen; + sconf->nraw = sconf->lightrange.num; + + if ((ev = ex1_get_wl_coefs(p, &sconf->nwlcal, &sconf->wlcal)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - if (sscanf(buf, "Predefined end wave: %lf ",&p->wl_long) != 1) { - amutex_unlock(p->lock); - a1loge(p->log, 1, "ex1_init_inst: failed to parse end wave\n"); - return ev; + if ((ev = ex1_get_nl_coefs(p, &sconf->nlin, &sconf->lin)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); } - if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */ - p->wl_long = 830.0; - - a1logd(p->log, 1, " Long wl range %f\n",p->wl_long); + sconf->lindiv = 1; /* Divide type polynomial correction */ - p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5); + /* If we every figure out what the format is, convert it */ + /* into 2D matrix form and store into sconf. */ + if ((ev = ex1_get_sl_coefs(p, &p->nstraylight, &p->straylight)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); + } - /* 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 = ex1_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + /* Get raw calibration values */ + if ((ev = ex1_get_ir_coefs(p, &count, &sconf->ecal, &p->emis_area)) != EX1_OK) { + return ex1_interp_code((inst *)p, ev); + } + if (count != sconf->nraw) { + a1logd(p->log, 1, " Calibration array is unexpected length (is %d, should be %d)\n", + count, sconf->nraw); + return inst_wrong_setup; } +#ifdef PLOT_DEBUG + printf("emission cal:\n"); + plot_ecal(sconf); +#endif + + /* Hmm. not 100% sure this is correct, but it gives the right */ + /* sort of numbers.. */ + for (i = 0; i < sconf->nraw; i++) + sconf->ecal[i] /= p->emis_area; + + sconf->ecaltype = rspec_raw; + +#ifdef PLOT_DEBUG + printf("adjusted emission cal:\n"); + plot_ecal(sconf); +#endif + + /* Figure out the calibrated range */ + rspec_comp_raw_range_from_ecal(sconf); + +//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_triangle; +// sconf->ktype = rspec_cubicspline; + sconf->wl_space = 2.0; + sconf->wl_short = rspec_raw2nm(sconf, sconf->rawrange.off); + sconf->wl_short = sconf->wl_space * ceil(sconf->wl_short/sconf->wl_space); + if (sconf->wl_short < 350.0) + sconf->wl_short = 350.0; + sconf->wl_long = rspec_raw2nm(sconf, sconf->rawrange.off + sconf->rawrange.num-1); + sconf->wl_long = sconf->wl_space * floor(sconf->wl_long/sconf->wl_space); + if (sconf->wl_long > 800.0) + sconf->wl_long = 800.0; + + sconf->nwav = (int)floor(sconf->wl_long - sconf->wl_short)/sconf->wl_space + 1; + + a1logd(p->log, 1, " %d Wavelengths %f - %f spacing %f\n",sconf->nwav, + sconf->wl_short,sconf->wl_long,sconf->wl_space); + + /* The EX1 is Vis range 350-800 nm */ + /* so the raw spacing is about 0.45 nm */ + /* The EX1 has a 100um slit, so FWHM will be 6nm */ + /* so aim for calibrated wavlength spacing of 2nm */ + + rspec_make_resample_filters(sconf); +#ifdef PLOT_DEBUG + plot_resample_filters(sconf); +#endif + + p->idark_int_time[0] = EX1_INTTIME_MIN; + p->idark_int_time[1] = 2.0; + +#ifdef ENABLE_NONVCAL + /* Restore idarl calibration from the local system */ + ex1_restore_calibration(p); + /* Touch it so that we know when the instrument was last opened */ + ex1_touch_calibration(p); +#endif + +#ifdef NEVER /* Test linearity iversion */ + { + double v1, v2, v3; - /* Set to average just 1 reading */ - if ((ev = ex1_command(p, "*conf:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; + for (v1 = 0.0; v1 < SENSE_SAT; v1 += 1638.0) { + v2 = linearize_val_rspec(sconf, v1); + v3 = inv_linearize_val_rspec(sconf, v2); + + printf("Sens in %f -> lin %f -> non-lin %f (%f)\n",v1,v2,v3,fabs(v1 - v3)); + } } +#endif /* NEVER */ - if (p->log->verb) { - int val; - char *sp; + p->conv = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, icxNoClamp); - if ((ev = ex1_command(p, "*idn?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - if ((sp = strrchr(buf, '\r')) != NULL) - *sp = '\000'; - a1logv(p->log, 1, " Identificaton: %s\n",buf); - - if ((ev = ex1_command(p, "*vers?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - - if ((sp = strrchr(buf, '\r')) != NULL) - *sp = '\000'; - a1logv(p->log, 1, " Firmware: %s\n",buf); - - if ((ev = ex1_command(p, "*para:spnum?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - if (sscanf(buf, "spectrometer number: %d ",&val) == 1) { - a1logv(p->log, 1, " Spectrometer number: %d\n",val); - } - - if ((ev = ex1_command(p, "*para:serno?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - if (sscanf(buf, "serial number: %d ",&val) == 1) { - a1logv(p->log, 1, " Serial number: %d\n",val); - } + if (p->conv == NULL) + return EX1_INT_CIECONVFAIL; + + if (p->log->verb) { + a1logv(p->log, 1, " Model: %s\n",p->alias != NULL ? p->alias : "Unknown"); + a1logv(p->log, 1, " HW rev: %d\n",p->hwrev); + a1logv(p->log, 1, " FW rev: %d\n",p->fwrev); + a1logv(p->log, 1, " Serial number: %s\n",p->serno); + if (p->slitw != 0) + a1logv(p->log, 1, " Slit width: %d microns\n",p->slitw); + else + a1logv(p->log, 1, " Slit width: Unknown\n"); + if (p->fiberw != 0) + a1logv(p->log, 1, " Fiber width: %d microns\n",p->fiberw); + else + a1logv(p->log, 1, " Fiber width: Unknown\n"); + a1logv(p->log, 1, " Grating: %s\n",p->grating != NULL ? p->grating : "Unknown"); + a1logv(p->log, 1, " Filter: %s\n",p->filter != NULL ? p->filter : "Unknown"); + a1logv(p->log, 1, " Coating: %s\n",p->coating != NULL ? p->coating : "Unknown"); } p->inited = 1; a1logd(p->log, 2, "ex1_init_inst: instrument inited OK\n"); - amutex_unlock(p->lock); return inst_ok; } -static inst_code ex1_imp_measure_set_refresh(ex1 *p); -static inst_code ex1_imp_set_refresh(ex1 *p); - -/* Get the ambient diffuser position */ -/* (This is not multithread safe) */ -static inst_code -ex1_get_diffpos( - ex1 *p, /* Object */ - int *pos, /* 0 = display, 1 = ambient */ - int nd /* nz = no debug message */ -) { - char buf[MAX_RD_SIZE]; +/* Do a raw measurement. */ +/* Will delete existing *praw */ +/* return EX1 error */ +static int ex1_do_meas(ex1 *p, rspec **praw, double *inttime, double duration) { + rspec *sens, *raw; + int notoav; int ec; - /* See if we're in emissive or ambient mode */ - if ((ec = ex1_fcommand(p, "*contr:mhead?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) { - return ex1_interp_code((inst *)p, ec); + notoav = (int)ceil(duration/(MIN_CYCLE_TIME + *inttime)); + if (notoav <= 0) + notoav = 1; + if (notoav > EX1_AVERAGE_MAX) + notoav = EX1_AVERAGE_MAX; + + /* Set integration time */ + if ((ec = ex1_set_inttime(p, &p->inttime, *inttime)) != EX1_OK) { + return ec; } - if (sscanf(buf, "mhead: %d ",pos) != 1) { - a1logd(p->log, 2, "ex1_init_coms: unrecognised measuring head string '%s'\n",icoms_fix(buf)); - return inst_protocol_error; + *inttime = p->inttime; /* Quantized integration time */ + + /* Set no. of averages */ + if ((ec = ex1_set_average(p, notoav)) != EX1_OK) { + return ec; } - return inst_ok; -} -/* Get the target laser state */ -/* (This is not multithread safe) */ -static inst_code -ex1_get_target_laser( - ex1 *p, /* Object */ - int *laser, /* 0 = off, 1 = on */ - int nd /* nz = no debug message */ -) { - char buf[MAX_RD_SIZE]; - int ec; - int lstate; + sens = new_rspec(&p->sconf, rspec_sensor, 1); - if ((ec = ex1_fcommand(p, "*contr:laser?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) { - return ex1_interp_code((inst *)p, ec); - } - if (sscanf(buf, "laser: %d ",&lstate) != 1) { - a1loge(p->log, 2, "ex1_get_target_laser: failed to parse laser state\n"); - return inst_protocol_error; + if ((ec = ex1_measure(p, sens->samp[0])) != EX1_OK) { + del_rspec(sens); + return ec; } - *laser = lstate; - return inst_ok; + + sens->mtype = inst_mrt_emission; + sens->inttime = p->inttime; + + /* + Any other processing from sens to raw, */ + /* i.e. shielded cell tracking, illuminant temp value etc. ? */ + + raw = extract_raw_from_sensor_rspec(sens); + del_rspec(sens); + + if (*praw != NULL) + del_rspec(*praw); + *praw = raw; + + return EX1_OK; } /* Read a single sample */ -/* Return the dtp error code */ +/* Return the EX1 error code */ static inst_code ex1_read_sample( inst *pp, char *name, /* Strip name (7 chars) */ ipatch *val, /* Pointer to instrument patch value */ -instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ +instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */ +) { ex1 *p = (ex1 *)pp; - char buf[MAX_RD_SIZE]; - int ec; int user_trig = 0; int pos = -1; inst_code rv = inst_protocol_error; + rspec_inf *sconf = &p->sconf; + rspec *raw = NULL, *wav = NULL; + int ec, i; if (!p->gotcoms) return inst_no_coms; if (!p->inited) return inst_no_init; - amutex_lock(p->lock); if (p->trig == inst_opt_trig_user) { - amutex_unlock(p->lock); if (p->uicallback == NULL) { a1logd(p->log, 1, "ex1: inst_opt_trig_user but no uicallback function set!\n"); @@ -473,307 +497,199 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ /* Notify of trigger */ if (p->uicallback) p->uicallback(p->uic_cntx, inst_triggered); - amutex_lock(p->lock); /* Progromatic Trigger */ } else { /* Check for abort */ if (p->uicallback != NULL && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) { - amutex_unlock(p->lock); return rv; /* Abort */ } } - - /* See if we're in emissive or ambient mode */ - if ((rv = ex1_get_diffpos(p, &pos, 0) ) != inst_ok) { - amutex_unlock(p->lock); - return rv; - } - - /* Attempt a refresh display frame rate calibration if needed */ - if (p->refrmode != 0 && p->rrset == 0) { - a1logd(p->log, 1, "ex1: need refresh rate calibration before measure\n"); - if ((rv = ex1_imp_measure_set_refresh(p)) != inst_ok) { - amutex_unlock(p->lock); - return rv; + { + double inttime, tinttime; + int six; + double max = 1e6; + double blk; + + a1logd(p->log,5,"Starting auto integration time:\n"); + + /* Find an integration time small enough to avoid overload */ + for (inttime = 0.01; max > SENSE_SAT && inttime >= EX1_INTTIME_MIN; inttime *= 0.1) { + a1logd(p->log,5,"Trying inttime %f\n",inttime); + if ((ec = ex1_do_meas(p, &raw, &inttime, 0.05)) != EX1_OK) { + return ex1_interp_code((inst *)p, ec); + } + max = largest_val_rspec(NULL, &six, raw); + a1logd(p->log,5,"Max %.0f at six %d, Sat level %.0f\n",max,six,SENSE_SAT); + if (max <= SENSE_SAT) + break; + } + if (max >= SENSE_SAT) { + a1logd(p->log,1,"Saturated\n"); + return ex1_interp_code((inst *)p, EX1_RD_SENSORSATURATED); } - } - - /* Trigger a measurement */ - if ((ec = ex1_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0)) != EX1_OK) { - amutex_unlock(p->lock); - return ex1_interp_code((inst *)p, ec); - } + blk = ex1_interp_idark_val(sconf, 0, six, inttime); + a1logd(p->log,5,"Black at max = %f\n",blk); + + /* Find an integration time large enough to measure something significant */ + for (; max < (2.0 * blk) + && inttime <= p->max_meastime + && inttime <= EX1_INTTIME_MAX;) { + tinttime = inttime * 10.0; + if (tinttime > p->max_meastime + || tinttime > EX1_INTTIME_MAX) + break; + inttime = tinttime; + a1logd(p->log,5,"Trying intttime %f\n",inttime); + if ((ec = ex1_do_meas(p, &raw, &inttime, 0.05)) != EX1_OK) { + return ex1_interp_code((inst *)p, ec); + } + max = largest_val_rspec(NULL, &six, raw); + blk = ex1_interp_idark_val(sconf, 0, six, inttime); + a1logd(p->log,5,"Max %.0f, black %.0f\n",max,blk); + if (max >= (2.0 * blk)) + break; + } + /* If we haven't already tried the maximum time, calculate optimal inttime */ + if (inttime <= p->max_meastime + && max >= (2.0 * blk)) { + double llev, blk2; - if (ec == EX1_OK) { + /* Compute the light level for our measurement */ + llev = linearize_val_rspec(sconf, max - blk)/inttime; + a1logd(p->log,5,"Light level = %f\n",llev); - if (sscanf(buf, " X: %lf Y: %lf Z: %lf ", - &val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) != 3) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "ex1_read_sample: failed to parse '%s'\n",buf); - return inst_protocol_error; - } - - amutex_unlock(p->lock); - return ex1_interp_code((inst *)p, ec); - } + /* Calculate an initial target integration time to use to estimat black */ + tinttime = (SENSE_AIM - blk)/(max - blk) * inttime; + a1logd(p->log,5,"Initial optimal inttime %f\n",tinttime); - /* This may not change anything since instrument may clamp */ - if (clamp) - icmClamp3(val->XYZ, val->XYZ); - val->loc[0] = '\000'; - if (p->mode & inst_mode_ambient) { - val->mtype = inst_mrt_ambient; - } else - val->mtype = inst_mrt_emission; - val->XYZ_v = 1; /* These are absolute XYZ readings */ - val->sp.spec_n = 0; - val->duration = 0.0; - rv = inst_ok; - - - /* spectrum data is returned only if requested */ - if (p->mode & inst_mode_spectral) { - int tries, maxtries = 5; - int 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 */ - - /* Because the ex1 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;;) { - - /* Fetch the spectral readings */ - ec = ex1_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 2.0, 2+p->nbands+1, 0, 0); - tries++; - if (ec != EX1_OK) { - if (tries > maxtries) { - amutex_unlock(p->lock); - a1logd(p->log, 1, "ex1_fcommand: failed with 0x%x\n",ec); - return ex1_interp_code((inst *)p, ec); - } - continue; /* Retry the fetch */ + /* Itterate */ + for (i = 0; i < 5; i++) { + blk2 = ex1_interp_idark_val(sconf, 0, six, tinttime); + tinttime = linearize_val_rspec(sconf, SENSE_AIM - blk2)/llev; } + a1logd(p->log,5,"Optimal inttime %f\n",tinttime); + + if (tinttime < p->max_meastime) { + if (tinttime < EX1_INTTIME_MIN) + tinttime = EX1_INTTIME_MIN; + if (tinttime > EX1_INTTIME_MAX) + tinttime = EX1_INTTIME_MAX; - val->sp.spec_n = p->nbands; - val->sp.spec_wl_short = p->wl_short; - val->sp.spec_wl_long = p->wl_long; + /* Do the real measurement */ + if (inttime <= 1.0) { + inttime = tinttime; - /* Spectral data is in W/nm/m^2 */ - val->sp.norm = 1.0; - cp = buf; - for (i = -2; i < val->sp.spec_n; i++) { - if ((ncp = strchr(cp, '\r')) == NULL) { - a1logd(p->log, 1, "ex1_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; + a1logd(p->log,5,"Doing real measurement with inttime %f\n",inttime); + if ((ec = ex1_do_meas(p, &raw, &inttime, 1.0)) != EX1_OK) { + return ex1_interp_code((inst *)p, ec); } - continue; /* 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 */ - if (p->mode & inst_mode_ambient) - val->mtype = inst_mrt_ambient; + max = largest_val_rspec(NULL, &six, raw); + a1logd(p->log,5,"Got max %.0f, aimed for %.0f\n",max,SENSE_AIM); } - cp = ncp+1; } - /* We've parsed correctly, so don't retry */ - break; } - a1logd(p->log, 1, "ex1_read_sample: got total %d samples/%d expected in %d tries\n",i,val->sp.spec_n, tries); - } - amutex_unlock(p->lock); - - if (user_trig) - return inst_user_trig; - return rv; -} - -/* Set the instrument to match the current refresh settings */ -/* (Not thread safe) */ -static inst_code -ex1_imp_set_refresh(ex1 *p) { - char buf[MAX_MES_SIZE]; - inst_code rv; - - if (p->model == 1201) - return inst_unsupported; - - /* Set synchronised read if we should do so */ - if (p->refrmode != 0 && p->refrvalid) { - char mes[100]; - if ((rv = ex1_command(p, "*conf:cycmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; + if (max >= SENSE_SAT) { + /* Hmm. Should retry in case light level changed during measurement ? */ + return ex1_interp_code((inst *)p, EX1_RD_SENSORSATURATED); } - sprintf(mes,"*conf:cyctim %f\r",p->refperiod * 1e6); - if ((rv = ex1_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; - } - a1logd(p->log,5,"ex1_imp_set_refresh set refresh rate to %f Hz\n",1.0/p->refperiod); - } else { - if ((rv = ex1_command(p, "*conf:cycmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; - } - a1logd(p->log,5,"ex1_imp_set_refresh set non-refresh mode\n"); } - return inst_ok; -} -/* Implementation of read refresh rate */ -/* (Not thread safe) */ -/* Return 0.0 if none detectable */ -static inst_code -ex1_imp_measure_refresh( -ex1 *p, -double *ref_rate -) { - char buf[MAX_MES_SIZE], *cp; - double refperiod = 0.0; - int ec; - inst_code rv; - if (ref_rate != NULL) - *ref_rate = 0.0; - if (p->model == 1201) - return inst_unsupported; +#ifdef PLOT_DEBUG + printf("Raw:\n"); + plot_rspec1(raw); +#endif - /* Make sure the target laser is off */ - if ((rv = ex1_command(p, "*contr:laser 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) { - return rv; - } + subtract_idark_rspec(raw); - if ((ec = ex1_fcommand(p, "*contr:cyctim 200 4000\r", buf, MAX_MES_SIZE, 5.0, 1, 2, 0)) != EX1_OK) { - return ex1_interp_code((inst *)p, ec); +#ifdef PLOT_DEBUG + { + rspec *nl = new_rspec_clone(raw); + linearize_rspec(raw); + printf("non-lin and linearized:\n"); + plot_rspec2(nl, raw); + del_rspec(nl); } +#else + linearize_rspec(raw); +#endif - if ((cp = strchr(buf, 'c')) == NULL) - cp = buf; - if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) { - a1logd(p->log, 1, "ex1_read_refrate rate: failed to parse string '%s'\n",icoms_fix(buf)); - *ref_rate = 0.0; - return inst_misread; - } + emis_calibrate_rspec(raw); - if (refperiod == 0.0) - *ref_rate = 0.0; - else - *ref_rate = 1000.0/refperiod; +#ifdef PLOT_DEBUG + printf("Calibrated raw:\n"); + plot_rspec1(raw); +#endif - return inst_ok; -} + wav = convert_wav_from_raw_rspec(raw); + del_rspec(raw); -/* Read an emissive refresh rate */ -static inst_code -ex1_read_refrate( -inst *pp, -double *ref_rate -) { - ex1 *p = (ex1 *)pp; - char buf[MAX_MES_SIZE]; - double refrate; - inst_code rv; + inttime_calibrate_rspec(wav); - if (!p->gotcoms) - return inst_no_coms; - if (!p->inited) - return inst_no_init; +#ifdef PLOT_DEBUG + printf("Wav:\n"); + plot_rspec1(wav); +#endif - if (ref_rate != NULL) - *ref_rate = 0.0; + val->mtype = wav->mtype; - amutex_lock(p->lock); - if ((rv = ex1_imp_measure_refresh(p, &refrate)) != inst_ok) { - amutex_unlock(p->lock); - return rv; - } - amutex_unlock(p->lock); + /* Copy spectral in */ + val->sp.spec_n = sconf->nwav; + val->sp.spec_wl_short = sconf->wl_short; + val->sp.spec_wl_long = sconf->wl_long; + val->sp.norm = 1.0; /* Spectral data is in W/nm/m^2 */ - if (refrate == 0.0) - return inst_misread; - - if (ref_rate != NULL) - *ref_rate = refrate; - - return inst_ok; -} - -/* Measure and then set refperiod, refrate if possible */ -/* (Not thread safe) */ -static inst_code -ex1_imp_measure_set_refresh( - ex1 *p /* Object */ -) { - inst_code rv; - double refrate = 0.0; - int mul; - double pval; - - if ((rv = ex1_imp_measure_refresh(p, &refrate)) != inst_ok) { - return rv; + for (i = 0; i < val->sp.spec_n; i++) { + val->sp.spec[i] = 1000.0 * wav->samp[0][i]; } - if (refrate != 0.0) { - p->refrate = refrate; - p->refrvalid = 1; - p->refperiod = 1.0/refrate; - } else { - p->refrate = 0.0; - p->refrvalid = 0; - p->refperiod = 0.0; - } - p->rrset = 1; + del_rspec(wav); - if ((rv = ex1_imp_set_refresh(p)) != inst_ok) { - return rv; - } + /* Set the XYZ */ + p->conv->convert(p->conv, val->XYZ, &val->sp); + if (clamp) + icmClamp3(val->XYZ, val->XYZ); + val->XYZ_v = 1; - return inst_ok; -} -/* Measure and then set refperiod, refrate if possible */ -static inst_code -ex1_measure_set_refresh( - ex1 *p /* Object */ -) { - int rv; - amutex_lock(p->lock); - rv = ex1_imp_measure_set_refresh(p); - amutex_unlock(p->lock); + if (user_trig) + return inst_user_trig; return rv; } /* Return needed and available inst_cal_type's */ static inst_code ex1_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) { ex1 *p = (ex1 *)pp; + time_t curtime = time(NULL); inst_cal_type n_cals = inst_calt_none; inst_cal_type a_cals = inst_calt_none; + int idark_valid = p->idark_valid; - if (p->refrmode != 0) { - if (p->rrset == 0) - n_cals |= inst_calt_ref_freq; - a_cals |= inst_calt_ref_freq; + if ((curtime - p->iddate) > DCALTOUT) { + a1logd(p->log,2,"Invalidating adaptive dark cal as %d secs from last cal\n",curtime - p->iddate); + idark_valid = 0; } + if (!idark_valid + || (p->want_dcalib && !p->noinitcalib)) + n_cals |= inst_calt_em_dark; + a_cals |= inst_calt_em_dark; + if (pn_cals != NULL) *pn_cals = n_cals; if (pa_cals != NULL) *pa_cals = a_cals; + a1logd(p->log,3,"ex1: returning n_cals 0x%x, a_cals 0x%x\n",n_cals, a_cals); + return inst_ok; } @@ -785,16 +701,16 @@ inst_cal_cond *calc, /* Current condition/desired condition */ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ ) { ex1 *p = (ex1 *)pp; - inst_code ev; + rspec_inf *sconf = &p->sconf; inst_cal_type needed, available; + inst_code ev; + int ec; if (!p->gotcoms) return inst_no_coms; if (!p->inited) return inst_no_init; - id[0] = '\000'; - if ((ev = ex1_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok) return ev; @@ -820,103 +736,197 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ return inst_unsupported; } - if ((*calt & inst_calt_ref_freq) && p->refrmode != 0) { - inst_code ev = inst_ok; - + /* Adaptive black calibration: */ + if (*calt & inst_calt_em_dark) { + time_t cdate = time(NULL); + int i, j, k; + rspec *raw; - if (*calc != inst_calc_emis_80pc) { - *calc = inst_calc_emis_80pc; + if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) { + *calc = inst_calc_man_em_dark; return inst_cal_setup; } - /* Do refresh display rate calibration */ - if ((ev = ex1_measure_set_refresh(p)) != inst_ok) - return ev; + a1logd(p->log,2,"\nDoing emis adapative black calibration\n"); - *calt &= ~inst_calt_ref_freq; - } - return inst_ok; -} + /* Bracket the dark level and interpolate. */ -/* Return the last calibrated refresh rate in Hz. Returns: */ -static inst_code ex1_get_refr_rate(inst *pp, -double *ref_rate -) { - ex1 *p = (ex1 *)pp; - if (p->refrvalid) { - *ref_rate = p->refrate; - return inst_ok; - } else if (p->rrset) { - *ref_rate = 0.0; - return inst_misread; - } - return inst_needs_cal; -} + if ((ec = ex1_do_meas(p, &sconf->idark[0], &p->idark_int_time[0], 1.0)) != EX1_OK) { + return ex1_interp_code((inst *)p, ec); + } -/* Set the calibrated refresh rate in Hz. */ -/* Set refresh rate to 0.0 to mark it as invalid */ -/* Rates outside the range 5.0 to 150.0 Hz will return an error */ -static inst_code ex1_set_refr_rate(inst *pp, -double ref_rate -) { - ex1 *p = (ex1 *)pp; - inst_code rv; + if ((ec = ex1_do_meas(p, &sconf->idark[1], &p->idark_int_time[1], 1.0)) != EX1_OK) { + return ex1_interp_code((inst *)p, ec); + } - a1logd(p->log,5,"ex1_set_refr_rate %f Hz\n",ref_rate); + p->idark_valid = 1; + p->want_dcalib = 0; + p->iddate = cdate; + *calt &= ~inst_calt_em_dark; + +#ifdef PLOT_DEBUG /* Use plot to show readings & processing */ + printf("idark calib:\n"); + plot_rspec2(sconf->idark[0], sconf->idark[1]); +#endif + + /* Test accuracy of dark level interpolation */ +#ifdef TEST_DARK_INTERP + { + double tinttime; + rspec *ref, *interp; + + for (tinttime = EX1_INTTIME_MIN; ; tinttime *= 2.0) { + if (tinttime >= EX1_INTTIME_MAX) + tinttime = EX1_INTTIME_MAX; + + if ((ec = ex1_do_meas(p, &ref, &tinttime, 1.0)) != EX1_OK) + return ex1_interp_code((inst *)p, ec); - if (ref_rate != 0.0 && (ref_rate < 5.0 || ref_rate > 150.0)) - return inst_bad_parameter; + interp = ex1_interp_idark(sconf, tinttime); - p->refrate = ref_rate; - if (ref_rate == 0.0) - p->refrvalid = 0; - else { - p->refperiod = 1.0/ref_rate; - p->refrvalid = 1; - } - p->rrset = 1; + fprintf(stderr,"Low gain ref vs. interp dark offset for inttime %f:\n",tinttime); + plot_rspec2(ref, interp); - /* Set the instrument to given refresh rate */ - amutex_lock(p->lock); - if ((rv = ex1_imp_set_refresh(p)) != inst_ok) { - amutex_unlock(p->lock); - return rv; + del_rspec(interp); + del_rspec(ref); + + if ((tinttime * 1.1) > EX1_INTTIME_MAX) + break; + } + } +#endif /* NEVER */ + +#ifdef ENABLE_NONVCAL + /* Save the idark calibration to a file */ + ex1_save_calibration(p); +#endif } - amutex_unlock(p->lock); return inst_ok; } - /* Error codes interpretation */ static char * ex1_interp_error(inst *pp, int ec) { -// ex1 *p = (ex1 *)pp; + char *rv; + ex1 *p = (ex1 *)pp; + ec &= inst_imask; + + /* See if it's an native error code */ + if ((rv = ex1_interp_native_error(p, ec)) != NULL) + return rv; + switch (ec) { - case EX1_INTERNAL_ERROR: - return "Internal software error"; case EX1_TIMEOUT: return "Communications timeout"; case EX1_COMS_FAIL: return "Communications failure"; case EX1_UNKNOWN_MODEL: - return "Not a JETI ex1"; + return "Not an EX1"; + case EX1_SHORT_WRITE: + return "Short USB write"; + case EX1_SHORT_READ: + return "Short USB read"; + case EX1_LONG_READ: + return "Long USB read"; + case EX1_DATA_CHSUM_ERROR: + return "Data checksum error"; case EX1_DATA_PARSE_ERROR: return "Data from ex1 didn't parse as expected"; + case EX1_RD_SENSORSATURATED: + return "Sensor is saturated"; - case EX1_OK: - return "No device error"; + /* Internal software errors */ + case EX1_INTERNAL_ERROR: + return "Internal software error"; case EX1_NOT_IMP: return "Not implemented"; + case EX1_MEMORY: + return "Memory allocation failed"; + case EX1_INT_THREADFAILED: + return "Thread failed"; + case EX1_INTTIME_RANGE: + return "Integration time is out of range"; + case EX1_DELTIME_RANGE: + return "Trigger delat time is out of range"; + case EX1_STROBE_RANGE: + return "Multi strobe period time is out of range"; + case EX1_AVERAGE_RANGE: + return "Number to average is out of range"; + case EX1_BOXCAR_RANGE: + return "Boxcar filtering is out of range"; + case EX1_INT_CAL_SAVE: + return "Saving calibration file failed"; + case EX1_INT_CAL_RESTORE: + return "Restoring calibration file failed"; + case EX1_INT_CAL_TOUCH: + return "Touching calibration file failed"; + case EX1_INT_CIECONVFAIL: + return "Creating spectral to XYZ conversion failed"; + + /* Hardware errors */ + case EX1_NO_WL_CAL: + return "Instrument doesn't contain wavelength calibration"; + case EX1_NO_IR_CAL: + return "Instrument doesn't contain irradiance calibration"; default: return "Unknown error code"; } } +/* EX1 Native error codes interpretation */ +/* Return NULL if not recognised */ +static char * +ex1_interp_native_error(ex1 *p, int ec) { + switch (ec) { + case EX1_OK: + return "No device error"; + case EX1_UNSUP_PROTOCOL: + return "Invalid/unsupported protocol"; + case EX1_MES_UNKN: + return "Unknown message type"; + case EX1_MES_BAD_CHSUM: + return "Bad message checksum"; + case EX1_MES_TOO_LARGE: + return "Message is too large"; + case EX1_MES_PAYLD_LEN: + return "Payload length doesn't match message type"; + case EX1_MES_PAYLD_INV: + return "Payload data is invalid"; + case EX1_DEV_NOT_RDY: + return "Device not ready for message type"; + case EX1_MES_UNK_CHSUM: + return "Unknown checksum type"; + case EX1_DEV_UNX_RST: + return "Unexpected device reset"; + case EX1_TOO_MANY_BUSSES: + return "Too many command sources"; + case EX1_OUT_OF_MEM: + return "Device is out of memory"; + case EX1_NO_INF: + return "Information doesn't exist"; + case EX1_DEV_INT_ERR: + return "Device internal error"; + case EX1_DECRYPT_ERR: + return "Could not decrypt"; + case EX1_FIRM_LAYOUT: + return "Firmware layout is invalid"; + case EX1_PACKET_SIZE: + return "Data packet size is not 64 bytes"; + case EX1_HW_REV_INCPT: + return "HW rev. is incompatible with firmware"; + case EX1_FLASH_MAP: + return "Flash map is incompatible with firmware"; + case EX1_DEFERRED: + return "Operation/Response deffered"; + default: + return NULL; + } +} /* Convert a machine specific error code into an abstract dtp code */ static inst_code @@ -928,21 +938,64 @@ ex1_interp_code(inst *pp, int ec) { case EX1_OK: return inst_ok; -// return inst_internal_error | ec; - -// return inst_coms_fail | ec; + case EX1_INTERNAL_ERROR: + case EX1_MEMORY: + case EX1_INT_THREADFAILED: + case EX1_INTTIME_RANGE: + case EX1_DELTIME_RANGE: + case EX1_STROBE_RANGE: + case EX1_AVERAGE_RANGE: + case EX1_BOXCAR_RANGE: + case EX1_INT_CAL_SAVE: + case EX1_INT_CAL_RESTORE: + case EX1_INT_CAL_TOUCH: + case EX1_INT_CIECONVFAIL: + return inst_internal_error | ec; -// return inst_unknown_model | ec; + case EX1_TIMEOUT: + case EX1_COMS_FAIL: + case EX1_SHORT_WRITE: + case EX1_SHORT_READ: + case EX1_LONG_READ: + return inst_coms_fail | ec; -// return inst_protocol_error | ec; + case EX1_UNKNOWN_MODEL: + return inst_unknown_model | ec; -// return inst_wrong_config | ec; + case EX1_DATA_CHSUM_ERROR: + case EX1_DATA_PARSE_ERROR: + return inst_protocol_error | ec; // return inst_bad_parameter | ec; +// return inst_wrong_config | ec; -// return inst_misread | ec; - -// return inst_hardware_fail | ec; + case EX1_NO_WL_CAL: + case EX1_NO_IR_CAL: + + /* Native instrument error */ + case EX1_UNSUP_PROTOCOL: + case EX1_MES_UNKN: + case EX1_MES_BAD_CHSUM: + case EX1_MES_TOO_LARGE: + case EX1_MES_PAYLD_LEN: + case EX1_MES_PAYLD_INV: + case EX1_DEV_NOT_RDY: + case EX1_MES_UNK_CHSUM: + case EX1_DEV_UNX_RST: + case EX1_TOO_MANY_BUSSES: + case EX1_OUT_OF_MEM: + case EX1_NO_INF: + case EX1_DEV_INT_ERR: + case EX1_DECRYPT_ERR: + case EX1_FIRM_LAYOUT: + case EX1_PACKET_SIZE: + case EX1_HW_REV_INCPT: + case EX1_FLASH_MAP: + case EX1_DEFERRED: + return inst_hardware_fail | ec; + + case EX1_RD_SENSORSATURATED: + return inst_misread | ec; case EX1_NOT_IMP: return inst_unsupported | ec; @@ -955,9 +1008,36 @@ static void ex1_del(inst *pp) { if (pp != NULL) { ex1 *p = (ex1 *)pp; + +#ifdef ENABLE_NONVCAL + ex1_touch_calibration(p); +#endif + if (p->icom != NULL) p->icom->del(p->icom); - amutex_del(p->lock); + if (p->cbuf != NULL) + free(p->cbuf); + if (p->alias != NULL) + free(p->alias); + if (p->serno != NULL) + free(p->serno); + if (p->grating != NULL) + free(p->grating); + if (p->filter != NULL) + free(p->filter); + if (p->coating != NULL) + free(p->coating); + + free_rspec_inf(&p->sconf); + + if (p->straylight != NULL) + free(p->straylight); + if (p->emis_coef != NULL) + free(p->emis_coef); + + if (p->conv != NULL) + p->conv->del(p->conv); + free(p); } } @@ -972,27 +1052,14 @@ inst3_capability *pcap3) { inst2_capability cap2 = 0; cap1 |= inst_mode_emis_tele -// | inst_mode_ambient // ?? is it | inst_mode_colorimeter | inst_mode_spectral - | inst_mode_emis_refresh_ovd - | inst_mode_emis_norefresh_ovd ; - /* can inst2_has_sensmode, but not report it asynchronously */ cap2 |= inst2_prog_trig | inst2_user_trig - | inst2_disptype - | inst2_has_target /* Has a laser target */ ; -// ~~~~9999 - if (p->model != 1201) { - cap2 |= inst2_emis_refr_meas; - cap2 |= inst2_set_refresh_rate; - cap2 |= inst2_get_refresh_rate; - } - if (pcap1 != NULL) *pcap1 = cap1; if (pcap2 != NULL) @@ -1011,38 +1078,15 @@ int *conf_ix ) { ex1 *p = (ex1 *)pp; inst_code ev; - inst_mode mval; - int pos; + inst_mode mval = 0; if (mmodes != NULL) *mmodes = inst_mode_none; if (cconds != NULL) *cconds = inst_calc_unknown; - if (conf_ix == NULL - || *conf_ix < 0 - || *conf_ix > 1) { - /* Return current configuration measrement modes */ - amutex_lock(p->lock); - if ((ev = ex1_get_diffpos(p, &pos, 0)) != inst_ok) { - amutex_unlock(p->lock); - return ev; - } - amutex_unlock(p->lock); - } else { - /* Return given configuration measurement modes */ - pos = *conf_ix; - } - - if (pos == 1) { - mval = inst_mode_emis_ambient; - } else if (pos == 0) { - mval |= inst_mode_emis_tele; - } - /* Add the extra dependent and independent modes */ - mval |= inst_mode_emis_refresh_ovd - | inst_mode_emis_norefresh_ovd + mval |= inst_mode_emis_tele | inst_mode_colorimeter | inst_mode_spectral; @@ -1051,7 +1095,7 @@ int *conf_ix /* Return configuration index returned */ if (conf_ix != NULL) - *conf_ix = pos; + *conf_ix = 0; /* There is only one */ return inst_ok; } @@ -1072,8 +1116,7 @@ static inst_code ex1_check_mode(inst *pp, inst_mode m) { return inst_unsupported; /* Only tele emission mode supported */ - if (!IMODETST(m, inst_mode_emis_tele) - && !IMODETST(m, inst_mode_emis_ambient)) { + if (!IMODETST(m, inst_mode_emis_tele)) { return inst_unsupported; } @@ -1091,144 +1134,18 @@ static inst_code ex1_set_mode(inst *pp, inst_mode m) { p->mode = m; - - if (p->model != 1201) { /* Can't set refresh mode on 1201 */ - - /* Effective refresh mode may change */ - refrmode = p->refrmode; - if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */ - refrmode = 0; - } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) { - refrmode = 1; - } - - if (p->refrmode != refrmode) { - p->rrset = 0; /* This is a hint we may have swapped displays */ - p->refrvalid = 0; - } - p->refrmode = refrmode; - } - - return inst_ok; -} - -static inst_disptypesel ex1_disptypesel[3] = { - { - inst_dtflags_default, - 1, - "nl", - "Non-Refresh display", - 0, - disptech_lcd, - 0 - }, - { - inst_dtflags_none, /* flags */ - 2, /* cbid */ - "rc", /* sel */ - "Refresh display", /* desc */ - 1, /* refr */ - disptech_crt, /* disptype */ - 1 /* ix */ - }, - { - inst_dtflags_end, - 0, - "", - "", - 0, - disptech_none, - 0 - } -}; - -/* Get mode and option details */ -static inst_code ex1_get_disptypesel( -inst *pp, -int *pnsels, /* Return number of display types */ -inst_disptypesel **psels, /* Return the array of display types */ -int allconfig, /* nz to return list for all configs, not just current. */ -int recreate /* nz to re-check for new ccmx & ccss files */ -) { - ex1 *p = (ex1 *)pp; - inst_code rv = inst_ok; - - if ((!allconfig && (p->mode & inst_mode_ambient)) /* If set to Ambient */ - || p->model == 1201) { /* Or 1201, return empty list */ - - if (pnsels != NULL) - *pnsels = 0; - - if (psels != NULL) - *psels = NULL; - - return inst_ok; - } - - - if (pnsels != NULL) - *pnsels = 2; - - if (psels != NULL) - *psels = ex1_disptypesel; - - return inst_ok; -} - -/* Given a display type entry, setup for that type */ -static inst_code set_disp_type(ex1 *p, inst_disptypesel *dentry) { - inst_code rv; - int refrmode; - - refrmode = dentry->refr; - - a1logd(p->log,5,"ex1 set_disp_type refmode %d\n",refrmode); - - if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */ - refrmode = 0; - } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) { - refrmode = 1; - } - - if (p->refrmode != refrmode) - p->rrset = 0; /* This is a hint we may have swapped displays */ - p->refrmode = refrmode; - - amutex_lock(p->lock); - if ((rv = ex1_imp_set_refresh(p)) != inst_ok) { - amutex_unlock(p->lock); - return rv; - } - amutex_unlock(p->lock); - return inst_ok; } -/* Set the display type - refresh or not */ -static inst_code ex1_set_disptype(inst *pp, int ix) { - ex1 *p = (ex1 *)pp; - inst_code ev; - inst_disptypesel *dentry; +/* Set the noinitcalib mode */ +static void ex1_set_noinitcalib(ex1 *p, int v, int losecs) { - if (!p->gotcoms) - return inst_no_coms; - if (!p->inited) - return inst_no_init; - - if (p->model == 1201) /* No display type to select on 1201 */ - return inst_unsupported; - - if (ix < 0 || ix >= 2) - return inst_unsupported; - - a1logd(p->log,5,"ex1 ex1_set_disptype ix %d\n",ix); - dentry = &ex1_disptypesel[ix]; - - if ((ev = set_disp_type(p, dentry)) != inst_ok) { - return ev; + /* Ignore disabling init calib if more than losecs since instrument was open */ + if (v && losecs != 0 && p->lo_secs >= losecs) { + a1logd(p->log,3,"initcalib disable ignored because %d >= %d secs\n",p->lo_secs,losecs); + return; } - - return inst_ok; + p->noinitcalib = v; } /* @@ -1241,13 +1158,27 @@ static inst_code ex1_get_set_opt(inst *pp, inst_opt_type m, ...) { ex1 *p = (ex1 *)pp; - char buf[MAX_MES_SIZE]; inst_code ev = inst_ok; a1logd(p->log, 5, "ex1_get_set_opt: opt type 0x%x\n",m); + if (m == inst_opt_initcalib) { /* default */ + ex1_set_noinitcalib(p, 0, 0); + return inst_ok; + + } else if (m == inst_opt_noinitcalib) { + va_list args; + int losecs = 0; + + va_start(args, m); + losecs = va_arg(args, int); + va_end(args); + + ex1_set_noinitcalib(p, 1, losecs); + return inst_ok; + /* Record the trigger mode */ - if (m == inst_opt_trig_prog + } else if (m == inst_opt_trig_prog || m == inst_opt_trig_user) { p->trig = m; return inst_ok; @@ -1269,6 +1200,14 @@ extern ex1 *new_ex1(icoms *icom, instType itype) { return NULL; } + /* Allocate a default communication buffer */ + if ((p->cbuf = calloc(1, 64)) == NULL) { + a1loge(icom->log, 1, "new_ex1: malloc failed!\n"); + free(p); + return NULL; + } + p->cbufsz = 64; + p->log = new_a1log_d(icom->log); p->init_coms = ex1_init_coms; @@ -1277,23 +1216,1438 @@ extern ex1 *new_ex1(icoms *icom, instType itype) { p->meas_config = ex1_meas_config; p->check_mode = ex1_check_mode; p->set_mode = ex1_set_mode; - p->get_disptypesel = ex1_get_disptypesel; - p->set_disptype = ex1_set_disptype; p->get_set_opt = ex1_get_set_opt; p->read_sample = ex1_read_sample; - p->read_refrate = ex1_read_refrate; p->get_n_a_cals = ex1_get_n_a_cals; p->calibrate = ex1_calibrate; - p->get_refr_rate = ex1_get_refr_rate; - p->set_refr_rate = ex1_set_refr_rate; p->interp_error = ex1_interp_error; p->del = ex1_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; - amutex_init(p->lock); + p->want_dcalib = 1; /* Always do an initial dark calibration */ return p; } +/* =============================================================================== */ +/* Calibration info save/restore */ + +int ex1_save_calibration(ex1 *p) { + int ev = EX1_OK; + int i; + char fname[100]; /* Name */ + calf x; + int argyllversion = ARGYLL_VERSION; + int ss; + + snprintf(fname, 99, ".ex1_%s.cal", p->serno); + + if (calf_open(&x, p->log, fname, 1)) { + x.ef = 2; + goto done; + } + + ss = sizeof(ex1); + + /* Some file identification */ + calf_wints(&x, &argyllversion, 1); + calf_wints(&x, &ss, 1); + calf_wstrz(&x, p->serno); + + /* Save the black calibration if it's valid */ + calf_wints(&x, &p->idark_valid, 1); + calf_wtime_ts(&x, &p->iddate, 1); + calf_wrspec(&x, p->sconf.idark[0]); + calf_wrspec(&x, p->sconf.idark[1]); + + a1logd(p->log,3,"nbytes = %d, Checkum = 0x%x\n",x.nbytes,x.chsum); + calf_wints(&x, (int *)(&x.chsum), 1); + + if (calf_done(&x)) + x.ef = 3; + + done:; + if (x.ef != 0) { + a1logd(p->log,2,"Writing calibration file failed with %d\n",x.ef); + ev = EX1_INT_CAL_SAVE; + } else { + a1logd(p->log,2,"Writing calibration file succeeded\n"); + } + + return ev; +} + +/* Restore the all modes calibration from the local system */ +int ex1_restore_calibration(ex1 *p) { + int ev = EX1_OK; + int i, j; + char fname[100]; /* Name */ + calf x; + int argyllversion; + int ss, nbytes, chsum1, chsum2; + char *serno = NULL; + + snprintf(fname, 99, ".ex1_%s.cal", p->serno); + + if (calf_open(&x, p->log, fname, 0)) { + x.ef = 2; + goto done; + } + + /* Last modified time */ + p->lo_secs = x.lo_secs; + + /* Do a dumy read to check the checksum, then a real read */ + for (x.rd = 0; x.rd < 2; x.rd++) { + calf_rewind(&x); + + /* Check the file identification */ + calf_rints2(&x, &argyllversion, 1); + calf_rints2(&x, &ss, 1); + calf_rstrz2(&x, &serno); + + if (x.ef != 0 + || argyllversion != ARGYLL_VERSION + || ss != (sizeof(ex1)) + || strcmp(serno, p->serno) != 0) { + a1logd(p->log,2,"Identification didn't verify\n"); + if (x.ef == 0) + x.ef = 4; + goto done; + } + + /* Read the black calibration if it's valid */ + calf_rints(&x, &p->idark_valid, 1); + calf_rtime_ts(&x, &p->iddate, 1); + calf_rrspec(&x, &p->sconf.idark[0], &p->sconf); + calf_rrspec(&x, &p->sconf.idark[1], &p->sconf); + + /* Check the checksum */ + chsum1 = x.chsum; + nbytes = x.nbytes; + calf_rints2(&x, &chsum2, 1); + + if (x.ef != 0 + || chsum1 != chsum2) { + a1logd(p->log,2,"Checksum didn't verify, bytes %d, got 0x%x, expected 0x%x\n",nbytes,chsum1, chsum2); + if (x.ef == 0) + x.ef = 5; + goto done; + } + } + + a1logd(p->log,5,"ex1_restore_calibration done\n"); + done:; + + free(serno); + if (calf_done(&x)) + x.ef = 3; + + if (x.ef != 0) { + a1logd(p->log,2,"Reading calibration file failed with %d\n",x.ef); + ev = EX1_INT_CAL_RESTORE; + } + + return ev; +} + +int ex1_touch_calibration(ex1 *p) { + int ev = EX1_OK; + char fname[100]; /* Name */ + int rv; + + snprintf(fname, 99, ".ex1_%s.cal", p->serno); + + if (calf_touch(p->log, fname)) { + a1logd(p->log,2,"Touching calibration file time failed with\n"); + return EX1_INT_CAL_TOUCH; + } + + return EX1_OK; +} + +/* =============================================================================== */ +/* EX1 lower level communications */ + +/* Interpret an icoms error into a EX1 error */ +static int icoms2ex1_err(int se) { + if (se != ICOM_OK) { + if (se & ICOM_TO) + return EX1_TIMEOUT; + return EX1_COMS_FAIL; + } + return EX1_OK; +} + +/* Message format definitions */ + +#define EX1_FLAG_RESP 0x0001 /* Response to an earlier request */ +#define EX1_FLAG_ACK 0x0002 /* Acknowldgement response */ +#define EX1_FLAG_RQACK 0x0004 /* Request for acknowldgement */ +#define EX1_FLAG_NACK 0x0008 /* Negative acknowldgement response */ +#define EX1_FLAG_EXPTN 0x0010 /* Exception occured */ +#define EX1_FLAG_PVDEP 0x0020 /* Protocol version is deprecated */ + +#define EX1_CHSUM_NONE 0x0 /* No checksum */ +#define EX1_CHSUM_MD5 0x1 /* MD5 checksum */ + +#define EX1_TLC_MASK 0xFFF00000 /* Top-level category message type mask */ +#define EX1_TLC_GENERAL 0x00000000 /* General device characteristics */ +#define EX1_TLC_SPECTRO 0x00100000 /* Spectrometer feature */ +#define EX1_TLC_GPIO 0x00200000 /* GPIO feature */ +#define EX1_TLC_STROBE 0x00300000 /* Strobe feature */ +#define EX1_TLC_TEMP 0x00400000 /* Temperature feature */ + +static char *cmdtstring(unsigned int cmd); + +/* Debug - dump a command packet at debug level deb1 */ +static void dump_command(ex1 *p, ORD8 *buf, int len, int deblev) { + unsigned int pver = 0; /* Protocol version */ + unsigned int flags = 0; + unsigned int merrno = 0; + char *es; + unsigned int mestype = 0; + unsigned int tlc = 0; /* Top level message category */ + unsigned int regarding = 0; + unsigned int chstype = EX1_CHSUM_NONE; + unsigned int imdatlen = 0; + unsigned int bremain = 0; + unsigned int pll = 0; /* Explicit payload length */ + int fo; /* Footer offset */ + + if (deblev < p->log->debug) + return; + + if (len < 44) { + a1logd(p->log, 0, " Command packet too short (%d bytes)\n",len); + return; + } + + /* First comes the header */ + if (buf[0] != 0xC1 || buf[1] != 0xC0) { + a1logd(p->log, 0, " Start bytes wrong (0x%02x, 0x%02x)\n",buf[0],buf[1]); + } + + pver = read_ORD16_le(buf + 2); + if (pver < 0x1000) { + a1logd(p->log, 0, " Unknown protocol version (0x%x)\n",pver); + return; + } + a1logd(p->log, 0, " Protocol version: 0x%x\n",pver); + + flags = read_ORD16_le(buf + 4); + a1logd(p->log, 0, " Flags: 0x%x\n",flags); + + if (flags & EX1_FLAG_RESP) + a1logd(p->log, 0, " Response to an earlier request\n"); + if (flags & EX1_FLAG_ACK) + a1logd(p->log, 0, " Acknowldgement response\n"); + if (flags & EX1_FLAG_RQACK) + a1logd(p->log, 0, " Request for acknowldgement\n"); + if (flags & EX1_FLAG_NACK) + a1logd(p->log, 0, " Negative acknowldgement response\n"); + if (flags & EX1_FLAG_EXPTN) + a1logd(p->log, 0, " Exception occured\n"); + if (flags & EX1_FLAG_PVDEP) + a1logd(p->log, 0, " Protocol version is deprecated request\n"); + + merrno = read_ORD16_le(buf + 6); + a1logd(p->log, 0, " Error no.: 0x%x\n",merrno); + if ((es = ex1_interp_native_error(p, merrno)) != NULL) + a1logd(p->log, 0, " '%s'\n",es); + + mestype = read_ORD32_le(buf + 8); + a1logd(p->log, 0, " Mes. Type: 0x%x = %s\n",mestype, cmdtstring(mestype)); + tlc = mestype & EX1_TLC_MASK; + switch(tlc) { + case EX1_TLC_GENERAL: + a1logd(p->log, 0, " General device characteristics\n"); + break; + case EX1_TLC_SPECTRO: + a1logd(p->log, 0, " Spectrometer feature\n"); + break; + case EX1_TLC_GPIO: + a1logd(p->log, 0, " GPIO feature\n"); + break; + case EX1_TLC_STROBE: + a1logd(p->log, 0, " Strobe feature\n"); + break; + case EX1_TLC_TEMP: + a1logd(p->log, 0, " Temperature feature\n"); + break; + } + + regarding = read_ORD32_le(buf + 12); + a1logd(p->log, 0, " Regarding: 0x%x\n",regarding); + + chstype = read_ORD8(buf + 22); + a1logd(p->log, 0, " checksum: 0x%x\n",chstype); + if (chstype == EX1_CHSUM_NONE) + a1logd(p->log, 0, " none\n"); + else if (chstype == EX1_CHSUM_MD5) + a1logd(p->log, 0, " MD5\n"); + + imdatlen = read_ORD8(buf + 23); + a1logd(p->log, 0, " immediate data %d bytes%s\n",imdatlen, imdatlen > 16 ? " (illegal)" : " "); + + if (imdatlen > 0) + a1logd(p->log, 0, " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31], + buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]); + + bremain = read_ORD32_le(buf + 40); + a1logd(p->log, 0, " bytes remaining %d\n",bremain); + + if (bremain < 20) { + a1logd(p->log, 0, " - too small for chsum & footer\n"); + return; + } + + if ((44 + bremain) > len) { + a1logd(p->log, 0, " - too large for for message size (%d available)\n",len - 44); + return; + } + + /* Now comes the payload */ + pll = bremain - 20; /* Payload length */ + + if (pll > 0) { + adump_bytes(p->log, " ", buf + 44, 0, pll); + } + + /* Then the checksum */ + if (chstype == EX1_CHSUM_NONE) { + a1logd(p->log, 0, " checksum not used\n"); + } else if (chstype == EX1_CHSUM_MD5) { + icmMD5 *md5; + + if ((md5 = new_icmMD5()) == NULL) { + a1logd(p->log, 0, " new_icmMD5 failed\n"); + } else { + ORD8 chsum[16]; + int i; + + md5->add(md5, buf, 44 + pll); + md5->get(md5, chsum); + for (i = 0; i < 16; i++) { + if (chsum[i] != buf[44+pll+i]) + break; + } + if (i < 16) + a1logd(p->log, 0, " MD5 checksum error\n"); + else + a1logd(p->log, 0, " MD5 checksum OK\n"); + md5->del(md5); + } + } else { + a1logd(p->log, 0, " checksum not checked (unknown type)\n"); + } + + /* Finally the footer */ + fo = 44 + pll + 16; + if (buf[fo] != 0xC5 || buf[fo + 1] != 0xC4 || buf[fo + 2] != 0xC3 || buf[fo + 3] != 0xC2) { + a1logd(p->log, 0, " Footer error (0x%02x 0x%02x 0x%02x 0x%02x)\n", + buf[fo],buf[fo+1],buf[fo+2],buf[fo+3]); + } +} + +/* Do a full command/response exchange with the ex1 */ +/* (This level is not multi-thread safe) */ +/* Return the ex1 error code. */ +static int +ex1_command( +ex1 *p, +unsigned int cmd, /* 32 bit command or query code */ +ORD8 *in, /* Input data */ +int ilen, /* data length */ +ORD8 *out, /* Output payload - if NULL, assume it's a command */ +int olen, /* Expected returned data length */ +int *prlen, /* Actual data returned. If NULL, expect exactly olen */ +double to, /* Timeout in seconds */ +int nd /* nz to disable debug messages */ +) { + int se, rv; + ORD8 *buf; + int bsize = 64; /* Size needed */ + int rwbytes = 0; + int stime; + + int slen = 64; /* Send length */ + int toff; /* Tail offset */ + + int rlen = 64; /* Receive length */ + unsigned int pver = 0; /* Protocol version */ + unsigned int flags = 0; + unsigned int merrno = 0; + unsigned int mestype = 0; + unsigned int tlc = 0; /* Top level message category */ + unsigned int regarding = 0; + unsigned int chstype = EX1_CHSUM_MD5; + unsigned int imdatlen = 0; + unsigned int bremain = 0; + unsigned int pll = 0; /* Explicit payload length */ + unsigned int ardlen = 0; /* Actual read data length (payload) */ + int fo; /* Footer offset */ + + if (in == NULL) + ilen = 0; + + if (out == NULL) + olen = 0; + + a1logd(p->log,6,"ex1_command: 0x%x '%s' ilen %d olen %d\n", cmd, cmdtstring(cmd), ilen, olen); + + if (p->log->debug >= 7 && ilen > 0) { + adump_bytes(p->log, " ", in, 0, ilen); + } + + stime = msec_time(); + + if (ilen > 16) { /* Too big for immediate data */ + slen += ilen; + } + + if (out != NULL && olen > 16) { /* Too big for immediate data */ + rlen += olen; + } + + /* Make sure out buffer is big enough to send or revieve */ + bsize = slen > rlen ? slen : rlen; + if (bsize > p->cbufsz) { + if ((p->cbuf = realloc(p->cbuf, bsize)) == NULL) { + rv = EX1_MEMORY; + goto done; + } + p->cbufsz = bsize; + } + buf = p->cbuf; + + /* Header */ + buf[0] = 0xC1; + buf[1] = 0xC0; + + /* Protocol version */ + write_ORD16_le(buf + 2, 0x1100); + + /* If it's a command, request an acknowledge */ + flags = 0; + if (out == NULL) { + flags |= EX1_FLAG_RQACK; + } + write_ORD16_le(buf + 4, flags); + + /* Error number */ + write_ORD16_le(buf + 6, 0); + + /* Command */ + write_ORD32_le(buf + 8, cmd); + + /* Regarding identifier (not used) */ + write_ORD32_le(buf + 12, 0); + + /* Checksum type 0 = none */ + write_ORD8(buf + 22, chstype); + + /* Reserved bytes */ + memset(buf + 16, 0, 6); + + /* Immediate data */ + if (ilen <= 16) { + write_ORD8(buf + 23, ilen); + if (ilen > 0) + memcpy(buf + 24, in, ilen); + if (ilen < 16) + memset(buf + 24 + ilen, 0, 16 - ilen); + + /* Bytes remaining = checksum + footer = 20 */ + write_ORD32_le(buf + 40, 20); + toff = 44; + pll = 0; + + /* or Payload */ + } else { + write_ORD8(buf + 23, 0); + write_ORD32_le(buf + 40, ilen + 20); + if (ilen > 0) + memcpy(buf + 44, in, ilen); + toff = 44 + ilen; + pll = ilen; + } + + /* Checksum bytes */ + + if (chstype == EX1_CHSUM_MD5) { + icmMD5 *md5; + + if ((md5 = new_icmMD5()) == NULL) { + a1logd(p->log, 1, "new_icmMD5 failed\n"); + merrno = EX1_INTERNAL_ERROR; + } else { + ORD8 chsum[16]; + int i; + + md5->add(md5, buf, toff); + md5->get(md5, chsum); + for (i = 0; i < 16; i++) + buf[44+pll+i] = chsum[i]; + md5->del(md5); + } + } else { + memset(buf + toff, 0, 16); + } + + /* Finally the footer */ + buf[toff + 16 + 0] = 0xC5; + buf[toff + 16 + 1] = 0xC4; + buf[toff + 16 + 2] = 0xC3; + buf[toff + 16 + 3] = 0xC2; + + if (p->log->debug >= 8) { + a1logd(p->log,1,"\nex1_command: SENDING:\n"); + dump_command(p, buf, slen, p->log->debug); + } + + /* Send the command */ + se = p->icom->usb_write(p->icom, NULL, EX1_EP, buf, slen, &rwbytes, 1.0); + + if ((rv = icoms2ex1_err(se)) != EX1_OK) { + a1logd(p->log,1,"ex1_command: send failed with ICOM err 0x%x\n",se); + goto done; + } + + if (rwbytes != slen) { + a1logd(p->log,1,"ex1_command: send %d/%d bytes - short\n",rwbytes, slen); + rv = EX1_SHORT_WRITE; + goto done; + } + + /* - - - - - - - - - - - - - - */ + + /* Get the expected reply to a query, or an acknowledgement to a command */ + se = p->icom->usb_read(p->icom, NULL, EX1_EP | 0x80, buf, 64, &rwbytes, to); + + if ((rv = icoms2ex1_err(se)) != EX1_OK) { + a1logd(p->log,1,"ex1_command: read failed with ICOM err 0x%x\n",se); + goto done; + } + + if (p->log->debug >= 8) { + a1logd(p->log,1,"\nex1_command: RECIEVING:\n"); + dump_command(p, buf, rwbytes, p->log->debug); + } + + if (rwbytes != 64) { + a1logd(p->log,1,"ex1_command: read %d/%d bytes - short\n",rwbytes, 64); + rv = EX1_SHORT_READ; + goto done; + } + + /* Parse and check the reply: */ + + /* First comes the header */ + if (buf[0] != 0xC1 || buf[1] != 0xC0) { + a1logd(p->log, 1, "ex1_command: start bytes wrong (0x%02x, 0x%02x)\n",buf[0],buf[1]); + rv = EX1_DATA_PARSE_ERROR; + goto done; + } + + pver = read_ORD16_le(buf + 2); + if (pver < 0x1000) { + a1logd(p->log, 1, "Unknown protocol version (0x%x)\n",pver); + rv = EX1_DATA_PARSE_ERROR; + goto done; + } + + flags = read_ORD16_le(buf + 4); + merrno = read_ORD16_le(buf + 6); + mestype = read_ORD32_le(buf + 8); + regarding = read_ORD32_le(buf + 12); + chstype = read_ORD8(buf + 22); + imdatlen = read_ORD8(buf + 23); + bremain = read_ORD32_le(buf + 40); + + /* If there has been an error, return it */ + if (merrno != EX1_OK) { + rv = merrno; + goto done; + } + + if (bremain < 20) { + a1logd(p->log, 1, "Bytes remaining %d is too small for chsum & footer\n",bremain); + rv = EX1_DATA_PARSE_ERROR; + goto done; + } + + /* Explicit playload length */ + pll = bremain - 20; /* Payload length */ + + if (pll > 0 && imdatlen > 0) { + a1logd(p->log, 1, "Got both immediate payoad %d bytes and explicit %d bytes\n",imdatlen,pll); + rv = EX1_DATA_PARSE_ERROR; + goto done; + } + + /* Payload is immediate */ + if (imdatlen > 0) { + if (imdatlen > olen) { + a1logd(p->log, 1, "Got %d bytes payload when expecting %d\n",imdatlen, olen); + rv = EX1_LONG_READ; + goto done; + } + memcpy(out, buf + 24, imdatlen); + if (prlen != NULL) + *prlen = imdatlen; + ardlen = imdatlen; + } + + /* If there is an explicit payload, read the remaining bytes */ + else if (pll > 0) { + /* Make sure buffer is big enough for read */ + bsize = pll + 64; + if (bsize > p->cbufsz) { + if ((p->cbuf = realloc(p->cbuf, bsize)) == NULL) { + rv = EX1_MEMORY; + goto done; + } + p->cbufsz = bsize; + } + buf = p->cbuf; + + se = p->icom->usb_read(p->icom, NULL, EX1_EP | 0x80, buf + 64, pll, &rwbytes, to); + +// adump_bytes(p->log, " ", buf + 44, 0, pll); + + if (rwbytes != pll) { + a1logd(p->log,1,"ex1_command: read %d/%d bytes - short\n",rwbytes, pll); + rv = EX1_SHORT_READ; + goto done; + } + + if (rwbytes > olen) { + a1logd(p->log, 1, "Got %d bytes payload when expecting %d\n",rwbytes, olen); + rv = EX1_LONG_READ; + goto done; + } + memcpy(out, buf + 44, pll); + if (prlen != NULL) + *prlen = pll; + ardlen = pll; + } + + /* Then the checksum */ + if (chstype == EX1_CHSUM_MD5) { + icmMD5 *md5; + + if ((md5 = new_icmMD5()) == NULL) { + a1logd(p->log, 1, "new_icmMD5 failed\n"); + rv = EX1_INTERNAL_ERROR; + goto done; + } else { + ORD8 chsum[16]; + int i; + + md5->add(md5, buf, 44 + pll); + md5->get(md5, chsum); + for (i = 0; i < 16; i++) { + if (chsum[i] != buf[44+pll+i]) + break; + } + if (i < 16) { + a1logd(p->log, 1, "MD5 checksum failed\n"); + md5->del(md5); + rv = EX1_DATA_CHSUM_ERROR; + goto done; + } + md5->del(md5); + } + } + + /* If we were expecting an exact ammount */ + if (prlen == NULL && ardlen != olen) { + a1logd(p->log, 1, "Got %d bytes payload when expecting %d\n",ardlen, olen); + rv = EX1_SHORT_READ; + goto done; + } + + /* Finally the footer */ + fo = 44 + pll + 16; + if (buf[fo] != 0xC5 || buf[fo + 1] != 0xC4 || buf[fo + 2] != 0xC3 || buf[fo + 3] != 0xC2) { + a1logd(p->log, 1, "Footer error (0x%02x 0x%02x 0x%02x 0x%02x)\n", + buf[fo],buf[fo+1],buf[fo+2],buf[fo+3]); + rv = EX1_DATA_PARSE_ERROR; + goto done; + } + + if (p->log->debug >= 7 && out != NULL && olen > 0) { + adump_bytes(p->log, " ", out, 0, olen); + } + + done:; + a1logd(p->log,6,"ex1_command: returning 0x%x (%d msec)\n", rv, msec_time()-stime); + + return rv; +} + +#define EX1_CMD_GET_HW_REV 0x00000080 + +/* Flush the pipe in case we have an unexpected reply waiting for us. */ +/* Note that the instrument will return a measurement initiated from */ +/* a previous session if it finishes in this session, i.e. closing */ +/* the instrument doesn't abort what it is doing ! */ +/* (This helps on MSWin, but stuffs up Linux) */ +static void +ex1_flush( +ex1 *p +) { +#ifdef NEVER + char buf[8096]; + int debugl = p->log->debug; + p->log->debug = 0; + p->icom->usb_resetep(p->icom, EX1_EP); + p->icom->usb_read(p->icom, NULL, EX1_EP | 0x80, buf, 8096, NULL, 0.1); + ex1_command(p, EX1_CMD_GET_HW_REV, NULL, 0, buf, 1, NULL, 0.1, 0); + p->icom->usb_resetep(p->icom, EX1_EP); + p->log->debug = debugl; +#endif +} + +/* ------------------------------------------------------------------- */ +/* Implement specific commands */ + +/* Unimplemented commands/queries */ +#define EX1_CMD_RESETDEFAULTS 0x00000001 + +#define EX1_CMD_GET_NO_USER_STR 0x00000300 +#define EX1_CMD_GET_USER_STR_SZ 0x00000301 +#define EX1_CMD_GET_USER_STR 0x00000302 + +/* - - - - - - */ + +//#define EX1_CMD_GET_HW_REV 0x00000080 + +/* Return Hardware revision number */ +/* Return the ex1 error code. */ +static int ex1_get_hw_rev(ex1 *p, int *hwrev) { + ORD8 buf[1]; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_HW_REV, NULL, 0, buf, 1, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + *hwrev = read_ORD8(buf); + + return EX1_OK; +} + + +#define EX1_CMD_GET_FW_REV 0x00000090 + +/* Return Firmware revision number */ +/* Return the ex1 error code. */ +static int ex1_get_fw_rev(ex1 *p, int *fwrev) { + ORD8 buf[2]; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_FW_REV, NULL, 0, buf, 2, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + *fwrev = read_ORD16_le(buf); + + return EX1_OK; +} + +#define EX1_CMD_GET_SLITW 0x001B0200 + +/* Get slit width in microns */ +/* Return 0 if info. not available */ +/* Return the ex1 error code. */ +static int ex1_get_slit_width(ex1 *p, int *swidth) { + ORD8 buf[2]; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_SLITW, NULL, 0, buf, 2, NULL, 1.0, 0)) != EX1_OK) { + if (ec != EX1_NO_INF) + return ec; + *swidth = 0; + } else { + *swidth = read_ORD16_le(buf); + } + + return EX1_OK; +} + +#define EX1_CMD_GET_FIBW 0x001B0300 + +/* Get fiber diameter in microns */ +/* Return the ex1 error code. */ +static int ex1_get_fiber_width(ex1 *p, int *fibw) { + ORD8 buf[2]; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_FIBW, NULL, 0, buf, 2, NULL, 1.0, 0)) != EX1_OK) { + if (ec != EX1_NO_INF) + return ec; + *fibw = 0; + } else { + *fibw = read_ORD16_le(buf); + } + + return EX1_OK; +} + +#define EX1_CMD_GET_GRATING 0x001B0400 + +/* Return grating string, or NULL if none */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_grating(ex1 *p, char **grating) { + int bread; + int len = 32; /* We assume a max of 32 bytes */ + int ec; + + if ((*grating = malloc(len+1)) == NULL) + return EX1_MEMORY; + if ((ec = ex1_command(p, EX1_CMD_GET_GRATING, NULL, 0, (ORD8 *)*grating, len, &bread, 2.0, 0)) + != EX1_OK) { + if (ec != EX1_NO_INF) + return ec; + free(*grating); + *grating = NULL; + } else { + (*grating)[bread] = '\000'; + } + + return EX1_OK; +} + +#define EX1_CMD_GET_FILTER 0x001B0500 + +/* Return filter string, or NULL if none */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_filter(ex1 *p, char **filter) { + int bread; + int len = 32; /* We assume a max of 32 bytes */ + int ec; + + if ((*filter = malloc(len+1)) == NULL) + return EX1_MEMORY; + if ((ec = ex1_command(p, EX1_CMD_GET_FILTER, NULL, 0, (ORD8 *)*filter, len, &bread, 2.0, 0)) + != EX1_OK) { + if (ec != EX1_NO_INF) + return ec; + free(*filter); + *filter = NULL; + } else { + (*filter)[bread] = '\000'; + } + + return EX1_OK; +} + +#define EX1_CMD_GET_COATING 0x001B0600 + +/* Return coating string, or NULL if none */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_coating(ex1 *p, char **coating) { + int bread; + int len = 32; /* We assume a max of 32 bytes */ + int ec; + + if ((*coating = malloc(len+1)) == NULL) + return EX1_MEMORY; + if ((ec = ex1_command(p, EX1_CMD_GET_COATING, NULL, 0, (ORD8 *)*coating, len, &bread, 2.0, 0)) + != EX1_OK) { + if (ec != EX1_NO_INF) + return ec; + free(*coating); + *coating = NULL; + } else { + (*coating)[bread] = '\000'; + } + + return EX1_OK; +} + + +#define EX1_CMD_GET_ALIAS_LEN 0x00000201 +#define EX1_CMD_GET_ALIAS 0x00000200 + +/* Return device alias string, or NULL if none */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_alias(ex1 *p, char **alias) { + ORD8 buf[3]; + int bread; + int len; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_ALIAS_LEN, NULL, 0, buf, 1, NULL, 2.0, 0)) != EX1_OK) { + return ec; + } + + len = read_ORD8(buf); + if (len == 0) { + *alias = NULL; + return inst_ok; + } + if ((*alias = malloc(len+1)) == NULL) { + return EX1_MEMORY; + } + + if ((ec = ex1_command(p, EX1_CMD_GET_ALIAS, NULL, 0, (ORD8 *)*alias, len, &bread, 2.0, 0)) + != EX1_OK) { + if (ec != EX1_NO_INF) { + return ec; + } + free(*alias); + *alias = NULL; + } else { + (*alias)[bread] = '\000'; + } + + return EX1_OK; +} + +#define EX1_CMD_GET_SERNO_LEN 0x00000101 +#define EX1_CMD_GET_SERNO 0x00000100 + +/* Return device serial string, or NULL if none */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_serno(ex1 *p, char **serno) { + ORD8 buf[3]; + int bread; + int len; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_SERNO_LEN, NULL, 0, buf, 1, NULL, 2.0, 0)) != EX1_OK) { + return ec; + } + + len = read_ORD8(buf); + if (len == 0) { + *serno = NULL; + return inst_ok; + } + if ((*serno = malloc(len+1)) == NULL) { + return EX1_MEMORY; + } + + if ((ec = ex1_command(p, EX1_CMD_GET_SERNO, NULL, 0, (ORD8 *)*serno, len, &bread, 2.0, 0)) + != EX1_OK) { + if (ec != EX1_NO_INF) { + return ec; + } + free(*serno); + *serno = NULL; + } else { + (*serno)[bread] = '\000'; + } + + return EX1_OK; +} + +/* - - - - - - */ + +#define EX1_CMD_GET_WL_COEF_COUNT 0x00180100 +#define EX1_CMD_GET_WL_COEF 0x00180101 + +/* Get wavelength cooeficients. */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_wl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs) { + ORD8 buf[4]; + unsigned int i, no; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_WL_COEF_COUNT, NULL, 0, buf, 1, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + no = read_ORD8(buf); + + /* There should be 4, but 2 is the minimum */ + if (no < 2) { + return EX1_NO_WL_CAL; + } + if ((*coefs = malloc(sizeof(double) * no)) == NULL) { + return EX1_MEMORY; + } + + for (i = 0; i < no; i++) { + write_ORD8(buf, i); + if ((ec = ex1_command(p, EX1_CMD_GET_WL_COEF, buf, 1, buf, 4, NULL, 1.0, 0)) != EX1_OK) { + *nocoefs = 0; + free(*coefs); + return ec; + } + (*coefs)[i] = IEEE754todouble(read_ORD32_le(buf)); + } + *nocoefs = no; + + if (p->log->debug >= 6) { + a1logd(p->log,1,"ex1: no. wavelength calib coefs = %d\n",no); + for (i = 0; i < no; i++) { + a1logd(p->log,1," [%d] = %e\n",i,(*coefs)[i]); + } + } + + return EX1_OK; +} + +#define EX1_CMD_GET_NL_COEF_COUNT 0x00181100 +#define EX1_CMD_GET_NL_COEF 0x00181101 + +/* Get non-linearity coefficient */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_nl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs) { + ORD8 buf[4]; + unsigned int i, no; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_NL_COEF_COUNT, NULL, 0, buf, 1, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + no = read_ORD8(buf); + + if (no == 0) { + *nocoefs = 0; + *coefs = NULL; + return EX1_OK; + } + if ((*coefs = malloc(sizeof(double) * no)) == NULL) { + return EX1_MEMORY; + } + + for (i = 0; i < no; i++) { + write_ORD8(buf, i); + if ((ec = ex1_command(p, EX1_CMD_GET_NL_COEF, buf, 1, buf, 4, NULL, 1.0, 0)) != EX1_OK) { + free(*coefs); + *nocoefs = 0; + *coefs = NULL; + return ec; + } + (*coefs)[i] = IEEE754todouble(read_ORD32_le(buf)); + } + *nocoefs = no; + + if (p->log->debug >= 6) { + a1logd(p->log,1,"ex1: no. linearity calib coefs = %d\n",no); + for (i = 0; i < no; i++) { + a1logd(p->log,1," [%d] = %e\n",i,(*coefs)[i]); + } + } + + return EX1_OK; +} + +#define EX1_CMD_GET_IR_COEF_COUNT 0x00182002 +#define EX1_CMD_GET_IR_COEF 0x00182001 +#define EX1_CMD_GET_IR_AREA 0x00182003 + +/* Get Irradiance calibration coefficients and collection area */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_ir_coefs(ex1 *p, unsigned int *nocoefs, double **coefs, double *area) { + ORD8 buf[4], *tbuf; + unsigned int i, no; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_IR_COEF_COUNT, NULL, 0, buf, 4, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + no = read_ORD32_le(buf); + + if (no == 0) { + *nocoefs = 0; + *coefs = NULL; + return EX1_NO_IR_CAL; + } + if ((tbuf = malloc(4 * no)) == NULL) { + return EX1_MEMORY; + } + + if ((*coefs = malloc(sizeof(double) * no)) == NULL) { + free(tbuf); + return EX1_MEMORY; + } + + if ((ec = ex1_command(p, EX1_CMD_GET_IR_COEF, NULL, 0, tbuf, 4 * no, NULL, 1.0, 0)) != EX1_OK) { + free(*coefs); + *nocoefs = 0; + *coefs = NULL; + *area = 0.0; + return ec; + } + for (i = 0; i < no; i++) { + (*coefs)[i] = IEEE754todouble(read_ORD32_le(tbuf + 4 * i)); + } + *nocoefs = no; + free(tbuf); + + if (p->log->debug >= 6) { + a1logd(p->log,1,"ex1: no. Irradiance calib coefs = %d\n",no); + for (i = 0; (i+3) < no; i += 4) { + a1logd(p->log,1," [%d] = %e, %e %e %e\n",i, + (*coefs)[i], (*coefs)[i+1], (*coefs)[i+2], (*coefs)[i+3]); + } + } + + if ((ec = ex1_command(p, EX1_CMD_GET_IR_AREA, NULL, 0, buf, 4, NULL, 1.0, 0)) != EX1_OK) { + if (ec != EX1_NO_INF) { + return ec; + } + *area = 0.0; + } else { + *area = IEEE754todouble(read_ORD32_le(buf)); + } + + a1logd(p->log,1,"ex1: Irradiance collection area = %f\n",*area); + + return EX1_OK; +} + +#define EX1_CMD_GET_SL_COEF_COUNT 0x00183100 +#define EX1_CMD_GET_SL_COEF 0x00183101 + +/* Get stray light coefficient */ +/* (free after use) */ +/* Return the ex1 error code. */ +static int ex1_get_sl_coefs(ex1 *p, unsigned int *nocoefs, double **coefs) { + ORD8 buf[4]; + unsigned int i, no; + int ec; + + if ((ec = ex1_command(p, EX1_CMD_GET_SL_COEF_COUNT, NULL, 0, buf, 1, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + no = read_ORD8(buf); + + if (no == 0) { + *nocoefs = 0; + *coefs = NULL; + return EX1_OK; + } + if ((*coefs = malloc(sizeof(double) * no)) == NULL) { + return EX1_MEMORY; + } + + for (i = 0; i < no; i++) { + write_ORD8(buf, i); + if ((ec = ex1_command(p, EX1_CMD_GET_SL_COEF, buf, 1, buf, 4, NULL, 1.0, 0)) != EX1_OK) { + free(*coefs); + *nocoefs = 0; + *coefs = NULL; + if (ec != EX1_NO_INF) + return ec; + else + return EX1_OK; + } + (*coefs)[i] = IEEE754todouble(read_ORD32_le(buf)); + } + *nocoefs = no; + + if (p->log->debug >= 6) { + a1logd(p->log,1,"ex1: no. stray light calib coefs = %d\n",no); + for (i = 0; i < no; i++) { + a1logd(p->log,1," [%d] = %e\n",i,(*coefs)[i]); + } + } + + return EX1_OK; +} + + +/* - - - - - - */ + +#define EX1_CMD_SET_TRIGMODE 0x00110110 + +/* Set trigger mode */ +static int ex1_set_trig_mode(ex1 *p, int trigmode) { + ORD8 buf[1]; + int ec; + + write_ORD8(buf, trigmode); + if ((ec = ex1_command(p, EX1_CMD_SET_TRIGMODE, buf, 1, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + return EX1_OK; +} + +#define EX1_CMD_SET_INTTIME 0x00110010 + +/* Set integration time, min 10 usec, max 10 sec */ +/* Return qualtized integration time in qinttime if != NULL */ +static int ex1_set_inttime(ex1 *p, double *qinttime, double inttime) { + ORD8 buf[4]; + unsigned int iinttime; + int ec; + + inttime = floor(inttime * 1e6 + 0.5); /* To int usec */ + if (inttime < (EX1_INTTIME_MIN * 1e6) || inttime > (EX1_INTTIME_MAX * 1e6)) + return EX1_INTTIME_RANGE; + + iinttime = (unsigned int)inttime; + write_ORD32_le(buf, iinttime); + + if ((ec = ex1_command(p, EX1_CMD_SET_INTTIME, buf, 4, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + + if (qinttime != NULL) + *qinttime = inttime/1e6; + + return EX1_OK; +} + +#define EX1_CMD_SET_DELTIME 0x00110510 + +/* Set trigger delay time, min 5 usec, max 355.5 msec */ +/* Return quantized trigger delay time in qtrigdel if != NULL */ +static int ex1_set_trig_delay(ex1 *p, double *qtrigdel, double trigdel) { + ORD8 buf[4]; + unsigned int itrigdel; + int ec; + + trigdel = floor(trigdel * 1e6 + 0.5); /* To int usec */ + if (trigdel < (EX1_DELTIME_MIN * 1e6) || trigdel > (EX1_DELTIME_MAX * 1e6)) + return EX1_DELTIME_RANGE; + + itrigdel = (unsigned int)trigdel; + write_ORD32_le(buf, itrigdel); + + if ((ec = ex1_command(p, EX1_CMD_SET_DELTIME, buf, 4, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + + if (qtrigdel != NULL) + *qtrigdel = trigdel/1e6; + + return EX1_OK; +} + +#define EX1_CMD_SET_STRBPER 0x00310010 + +/* Set continuous strobe period, min 50 usec, max 5 sec */ +/* Return quantized strobe period in qinttime if != NULL */ +static int ex1_set_strobe_period(ex1 *p, double *qstbper, double stbper) { + ORD8 buf[4]; + unsigned int istbper; + int ec; + + stbper = floor(stbper * 1e6 + 0.5); /* To int usec */ + if (stbper < (EX1_STRBPER_MIN * 1e6) || stbper > (EX1_STRBPER_MAX * 1e6)) + return EX1_STROBE_RANGE; + + istbper = (unsigned int)stbper; + write_ORD32_le(buf, istbper); + + if ((ec = ex1_command(p, EX1_CMD_SET_STRBPER, buf, 4, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + + if (qstbper != NULL) + *qstbper = stbper/1e6; + + return EX1_OK; +} + +#define EX1_CMD_SET_STRBEN 0x00310011 + +/* Set continuous strobe enable/disable mode */ +static int ex1_set_strobe_enable(ex1 *p, int enable) { + ORD8 buf[1]; + int ec; + + write_ORD8(buf, enable); + if ((ec = ex1_command(p, EX1_CMD_SET_STRBEN, buf, 1, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + return EX1_OK; +} + +#define EX1_CMD_SET_SING_STRBEN 0x00300012 + +/* Set single strobe enable/disable mode */ +static int ex1_set_single_strobe_enable(ex1 *p, int enable) { + ORD8 buf[1]; + int ec; + + write_ORD8(buf, enable); + if ((ec = ex1_command(p, EX1_CMD_SET_SING_STRBEN, buf, 1, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + return EX1_OK; +} + +#define EX1_CMD_SET_AVERAGE 0x00120010 + +/* Set number of scans to average, range 1 - 5000 */ +static int ex1_set_average(ex1 *p, int noavg) { + ORD8 buf[2]; + int ec; + + if (noavg < EX1_AVERAGE_MIN || noavg > EX1_AVERAGE_MAX) + return EX1_AVERAGE_RANGE; + + write_ORD16_le(buf, noavg); + if ((ec = ex1_command(p, EX1_CMD_SET_AVERAGE, buf, 2, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + p->noaverage = noavg; + return EX1_OK; +} + +#define EX1_CMD_SET_BINNING 0x00110290 + +/* Set binning factor. */ +static int ex1_set_binning(ex1 *p, int bf) { + ORD8 buf[1]; + int ec; + + write_ORD8(buf, bf); + if ((ec = ex1_command(p, EX1_CMD_SET_BINNING, buf, 1, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + return EX1_OK; +} + +#define EX1_CMD_SET_BOXCAR 0x00121010 + +/* Set boxcar filtering width, 0 - 15 */ +static int ex1_set_boxcar(ex1 *p, int nobox) { + ORD8 buf[1]; + int ec; + + if (nobox < EX1_BOXCAR_MIN || nobox > EX1_BOXCAR_MAX) + return EX1_BOXCAR_RANGE; + + write_ORD8(buf, nobox); + if ((ec = ex1_command(p, EX1_CMD_SET_BOXCAR, buf, 1, NULL, 0, NULL, 1.0, 0)) != EX1_OK) { + return ec; + } + return EX1_OK; +} + +/* - - - - - - */ + +#define EX1_CMD_GET_COR_SPEC 0x00101000 + +/* Get corrected spectrum (temp and pattern noise corrected). */ +/* raw must be double[1024] */ +/* Return the ex1 error code. */ +static int ex1_measure(ex1 *p, double *raw) { + ORD8 buf[2048]; + unsigned int i, no = 1024; + int ec; + double to; + int stime; + + to = 1.0 + p->noaverage * (MIN_CYCLE_TIME + p->inttime) * 1.1; + +//printf("~1 ex1_measure: to = %f from %d x %f\n",to,p->noaverage,p->inttime); + + stime = msec_time(); + if ((ec = ex1_command(p, EX1_CMD_GET_COR_SPEC, NULL, 0, buf, no * 2, NULL, to, 0)) != EX1_OK) { + return ec; + } +//printf("Measure took %d msec\n", msec_time()-stime); + + for (i = 0; i < no; i++) + raw[i] = (double)read_ORD16_le(buf + 2 * i); + + if (p->log->debug >= 6) { + a1logd(p->log,1,"ex1: spectrum:\n"); + for (i = 0; (i+3) < no; i += 4) { + a1logd(p->log,1," [%d] = %.0f, %.0f %.0f %.0f\n", + i, raw[i], raw[i+1], raw[i+2], raw[i+3]); + } + } + return EX1_OK; +} + +/* - - - - - - */ + +/* Return command description */ +static char *cmdtstring(unsigned int cmd) { + switch (cmd) { + + case EX1_CMD_RESETDEFAULTS: + return "Reset to defaults"; + case EX1_CMD_GET_NO_USER_STR: + return "Get number of user strings"; + case EX1_CMD_GET_USER_STR_SZ: + return "Get maximum user string size"; + case EX1_CMD_GET_USER_STR: + return "Get user string"; + case EX1_CMD_GET_HW_REV: + return "Get Hardware Revision"; + case EX1_CMD_GET_FW_REV: + return "Get Firmware revision"; + case EX1_CMD_GET_ALIAS_LEN: + return "Get Alias string length"; + case EX1_CMD_GET_ALIAS: + return "Get Alias string"; + case EX1_CMD_GET_SERNO_LEN: + return "Get Serial number length"; + case EX1_CMD_GET_SERNO: + return "Get Serial number"; + case EX1_CMD_GET_SLITW: + return "Get Slit width"; + case EX1_CMD_GET_FIBW: + return "Get Fiber width"; + case EX1_CMD_GET_GRATING: + return "Get Grating string"; + + case EX1_CMD_GET_WL_COEF_COUNT: + return "Get Wavelenght coefficient count"; + case EX1_CMD_GET_WL_COEF: + return "Get Wavelenght coefficient"; + case EX1_CMD_GET_NL_COEF_COUNT: + return "Get Linearity coefficient count"; + case EX1_CMD_GET_NL_COEF: + return "Get Linearity coefficient"; + case EX1_CMD_GET_IR_COEF_COUNT: + return "Get Irradiance coefficient count"; + case EX1_CMD_GET_IR_COEF: + return "Get Irradiance coefficient"; + case EX1_CMD_GET_IR_AREA: + return "Get Irradiance collection area"; + case EX1_CMD_GET_SL_COEF_COUNT: + return "Get Stray light coefficient count"; + case EX1_CMD_GET_SL_COEF: + return "Get Stray light coefficient"; + + case EX1_CMD_SET_TRIGMODE: + return "Set Trigger mode"; + case EX1_CMD_SET_INTTIME: + return "Set Intergration time"; + case EX1_CMD_SET_DELTIME: + return "Set Trigger delay time"; + case EX1_CMD_SET_STRBPER: + return "Set Strobe period"; + case EX1_CMD_SET_STRBEN: + return "Set Strobe enable"; + case EX1_CMD_SET_SING_STRBEN: + return "Set Single Strobe enable"; + case EX1_CMD_SET_AVERAGE: + return "Set Averaging count"; + case EX1_CMD_SET_BINNING: + return "Set Binning multiple"; + case EX1_CMD_SET_BOXCAR: + return "Set Boxcar filtering width"; + + case EX1_CMD_GET_COR_SPEC: + return "Measure corrected spectral values"; + + default: + return "Unknown"; + } +} + + diff --git a/spectro/ex1.h b/spectro/ex1.h index 456ab75..d69b7ca 100644..100755 --- a/spectro/ex1.h +++ b/spectro/ex1.h @@ -37,48 +37,108 @@ #include "inst.h" -/* Fake Error codes */ -#define EX1_INTERNAL_ERROR 0xff01 /* Internal software error */ -#define EX1_TIMEOUT 0xff02 /* Communication timeout */ -#define EX1_COMS_FAIL 0xff03 /* Communication failure */ -#define EX1_UNKNOWN_MODEL 0xff04 /* Not a JETI ex1 */ -#define EX1_DATA_PARSE_ERROR 0xff05 /* Read data parsing error */ +/* Communication errors */ +#define EX1_TIMEOUT 0xFF02 /* Communication timeout */ +#define EX1_COMS_FAIL 0xFF03 /* Communication failure */ +#define EX1_UNKNOWN_MODEL 0xFF04 /* Not an ex1 */ +#define EX1_SHORT_WRITE 0xFF06 /* Write failure */ +#define EX1_SHORT_READ 0xFF07 /* Read failure */ +#define EX1_LONG_READ 0xFF08 /* Read more data than expected */ +#define EX1_DATA_CHSUM_ERROR 0xFF09 /* Checksum failed */ +#define EX1_DATA_PARSE_ERROR 0xFF0A /* Read data parsing error */ +/* Measurement errors */ +#define EX1_RD_SENSORSATURATED 0xFF0B /* Sensor is saturated */ -/* Real instrument error code */ -#define EX1_OK 0 -#define EX1_NOT_IMP 1 /* Internal software errors */ -#define EX1_INT_THREADFAILED 1000 +#define EX1_INTERNAL_ERROR 0xE000 /* Internal software error */ +#define EX1_NOT_IMP 0xE001 /* Function not implemented */ +#define EX1_MEMORY 0xE002 /* Memory allocation fail */ +#define EX1_INT_THREADFAILED 0xE003 +#define EX1_INTTIME_RANGE 0xE004 /* Integration time is out of range */ +#define EX1_DELTIME_RANGE 0xE005 /* Trigger Delaty time time is out of range */ +#define EX1_STROBE_RANGE 0xE006 /* Strobe period time is out of range */ +#define EX1_AVERAGE_RANGE 0xE007 /* Number to average is out of range */ +#define EX1_BOXCAR_RANGE 0xE008 /* Boxcar filtering size out of ange */ +#define EX1_INT_CAL_SAVE 0xE009 /* Saving calibration to file failed */ +#define EX1_INT_CAL_RESTORE 0xE00A /* Restoring calibration to file failed */ +#define EX1_INT_CAL_TOUCH 0xE00B /* Touching calibration to file failed */ +#define EX1_INT_CIECONVFAIL 0xE00C /* Creating spec. to XYZ conversion failed */ + +/* Configuration or operation errors */ +#define EX1_NO_WL_CAL 0xD001 /* There is no wavelegth calibration info */ +#define EX1_NO_IR_CAL 0xD002 /* There is no irradiance calibration info */ + +/* Real instrument error code */ +#define EX1_OK 0 +#define EX1_UNSUP_PROTOCOL 1 +#define EX1_MES_UNKN 2 +#define EX1_MES_BAD_CHSUM 3 +#define EX1_MES_TOO_LARGE 4 +#define EX1_MES_PAYLD_LEN 5 +#define EX1_MES_PAYLD_INV 6 +#define EX1_DEV_NOT_RDY 7 +#define EX1_MES_UNK_CHSUM 8 +#define EX1_DEV_UNX_RST 9 +#define EX1_TOO_MANY_BUSSES 10 +#define EX1_OUT_OF_MEM 11 +#define EX1_NO_INF 12 +#define EX1_DEV_INT_ERR 13 +#define EX1_DECRYPT_ERR 100 +#define EX1_FIRM_LAYOUT 101 +#define EX1_PACKET_SIZE 102 +#define EX1_HW_REV_INCPT 103 +#define EX1_FLASH_MAP 104 +#define EX1_DEFERRED 255 /* EX1 communication object */ struct _ex1 { INST_OBJ_BASE - amutex lock; /* Command lock (not necessary) */ + ORD8 *cbuf; /* USB communication buffer */ + int cbufsz; /* Current cbuf size */ - int model; /* ex1 model number */ + char *alias; /* Alias string (OEM Model ?) */ + int hwrev; /* Hardware rev number */ + int fwrev; /* Hardware rev number */ + char *serno; /* ASCII serial number */ + int slitw; /* Slit width in microns */ + int fiberw; /* Fiber width in microns */ + char *grating; /* Grating description */ + char *filter; /* Filter description */ + char *coating; /* Coating description */ inst_mode mode; /* Currently instrument mode */ - int refrmode; /* nz if in refresh display mode */ - /* (1201 has a refresh mode ?? but can't measure frequency) */ - int rrset; /* Flag, nz if the refresh rate has been determined */ - double refperiod; /* if > 0.0 in refmode, target int time quantization */ - double refrate; /* Measured refresh rate in Hz */ - int refrvalid; /* nz if refrate is valid */ + double max_meastime; /* Maximum integration time to use for measurement */ + double inttime; /* Current integration time */ + int noaverage; /* Current number being averaged */ - inst_opt_type trig; /* Reading trigger mode */ + rspec_inf sconf; /* Measurement & spectral configuration */ + + /* Don't know what to do with stray light - not present in EX1 ? */ + unsigned int nstraylight; /* Number in array */ + double *straylight; /* Array of stray light coefficients. */ + + unsigned int nemis_coef; /* Number in array */ + double *emis_coef; /* Emission calibration coefficients for raw */ + double emis_area; /* Emission collection area */ - double measto; /* Expected measurement timeout value */ - int nbands; /* Number of spectral bands */ - double wl_short; - double wl_long; + /* Adaptive emission black calibration */ + int idark_valid; /* idark calibration factors valid */ + time_t iddate; /* Date/time of last dark idark calibration */ + double idark_int_time[2]; /* Target dark integration times */ /* Other state */ + inst_opt_type trig; /* Reading trigger mode */ + int want_dcalib; /* Want Dark Calibration at start */ + int noinitcalib; /* Disable initial calibration if not essential */ + int lo_secs; /* Seconds since last opened (from calibration file mod time) */ + + xsp2cie *conv; /* spectral to XYZ conversion */ - }; typedef struct _ex1 ex1; +}; typedef struct _ex1 ex1; /* Constructor */ extern ex1 *new_ex1(icoms *icom, instType itype); diff --git a/spectro/fakeread.c b/spectro/fakeread.c index 892f548..3cad93a 100644..100755 --- a/spectro/fakeread.c +++ b/spectro/fakeread.c @@ -729,7 +729,7 @@ int main(int argc, char *argv[]) if ((ii = ti3->find_field(ti3, 0, fname)) < 0) error ("Input file doesn't contain field %s",fname); if (ti3->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",fname); + error ("Field %s is wrong type - expect float",fname); ti3_chix[j] = ii; } @@ -740,7 +740,7 @@ int main(int argc, char *argv[]) if ((ii = ti3->find_field(ti3, 0, ti3_isLab ? labfname[j] : xyzfname[j])) < 0) error ("Input file doesn't contain field %s",ti3_isLab ? labfname[j] : xyzfname[j]); if (ti3->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",ti3_isLab ? labfname[j] : xyzfname[j]); + error ("Field %s is wrong type - expect float",ti3_isLab ? labfname[j] : xyzfname[j]); ti3_pcsix[j] = ii; } @@ -768,6 +768,9 @@ int main(int argc, char *argv[]) if ((ti3_spi[j] = ti3->find_field(ti3, 0, buf)) < 0) error("Input file doesn't contain field %s",buf); + + if (ti3->t[0].ftype[ti3_spi[j]] != r_t) + error("Field %s is wrong type - expect float",buf); } } @@ -1061,7 +1064,7 @@ int main(int argc, char *argv[]) if ((ii = icg->find_field(icg, 0, fname)) < 0) error ("Input file doesn't contain field %s",fname); if (icg->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",fname); + error ("Field %s is wrong type - expect float",fname); ocg->add_field(ocg, 0, fname, r_t); chix[j] = ii; @@ -1075,7 +1078,7 @@ int main(int argc, char *argv[]) if ((ii = icg->find_field(icg, 0, islab ? labfname[j] : xyzfname[j])) < 0) error ("Input file doesn't contain field %s",islab ? labfname[j] : xyzfname[j]); if (icg->t[0].ftype[ii] != r_t) - error ("Field %s is wrong type",islab ? labfname[j] : xyzfname[j]); + error ("Field %s is wrong type - expect float",islab ? labfname[j] : xyzfname[j]); pcsix[j] = ii; } } diff --git a/spectro/hcfr.c b/spectro/hcfr.c index e5e1288..d0a8261 100644..100755 --- 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(__i386__) +#if defined(__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; @@ -946,7 +946,7 @@ extern hcfr *new_hcfr(icoms *icom, instType itype) { p->del = hcfr_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */ p->dtech = disptech_unknown; diff --git a/spectro/hcfr.h b/spectro/hcfr.h index 8910cec..8910cec 100644..100755 --- a/spectro/hcfr.h +++ b/spectro/hcfr.h diff --git a/spectro/hidio.c b/spectro/hidio.c index c930755..c930755 100644..100755 --- a/spectro/hidio.c +++ b/spectro/hidio.c diff --git a/spectro/hidio.h b/spectro/hidio.h index 90a741b..90a741b 100644..100755 --- a/spectro/hidio.h +++ b/spectro/hidio.h diff --git a/spectro/huey.c b/spectro/huey.c index 79d0284..79f8089 100644..100755 --- a/spectro/huey.c +++ b/spectro/huey.c @@ -1744,7 +1744,7 @@ extern huey *new_huey(icoms *icom, instType itype) { p->del = huey_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */ p->dtech = disptech_unknown; diff --git a/spectro/huey.h b/spectro/huey.h index aec96a0..aec96a0 100644..100755 --- a/spectro/huey.h +++ b/spectro/huey.h diff --git a/spectro/i1d3.c b/spectro/i1d3.c index b088728..689f328 100644..100755 --- a/spectro/i1d3.c +++ b/spectro/i1d3.c @@ -750,7 +750,7 @@ i1d3_read_external_eeprom( /* Take a raw measurement using a given integration time. */ -/* The measureent is the count of (both) edges from the L2V */ +/* The measurent is the count of (both) edges from the L2V */ /* over the integration time */ static inst_code i1d3_freq_measure( @@ -790,7 +790,7 @@ i1d3_freq_measure( /* Take a raw measurement that returns the number of clocks */ /* between and initial edge and edgec[] subsequent edges of the L2F. */ /* The edge count must be between 1 and 65535 inclusive. */ -/* Both edges are counted. It's advisable to use and even edgec[], */ +/* Both edges are counted. It's advisable to use an even edgec[], */ /* because the L2F output may not be symetric. */ /* If there are no edges within 10 seconds, return a count of 0 */ static inst_code @@ -894,7 +894,7 @@ i1d3_set_LEDs( timestamp them. Interpolate values up to .05 msec regular samples. Do an auto-correlation on the samples. - Pick the longest peak between 10 andf 40Hz as the best sample period, + Pick the longest peak between 10 and 40Hz as the best sample period, and halve this to use as the quantization value (ie. make it lie between 20 and 80 Hz). @@ -1740,7 +1740,7 @@ i1d3_take_emis_measurement( double mint; /* Blend down from target of 200 to minimum target of 1 edge over 8 sec. */ - /* (Allow margine away from max integration time of 10 secs) */ + /* (Allow margine away from max integration time of 6 secs) */ mint = p->inttime/6.0; bl = (nedgec - mint)/(200.0 - mint); if (bl < 0.0) @@ -1753,8 +1753,8 @@ i1d3_take_emis_measurement( tintt[i] = tedges/(edgec[i] * p->clk_freq/rmeas[i]); - if (tintt[i] > 6.0) /* Maximum possible is 10 seconds */ - tintt[i] = 6.0; + if (tintt[i] > 6.0) /* Maximum possible is 6 seconds */ + tintt[i] = 6.0; /* to ensure it completes within the 20 timeout */ if (p->refperiod > 0.0) { /* If we have a refresh period */ int n; @@ -2945,7 +2945,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ p->mininttime = 2.0 * p->dinttime; - if (*calc != inst_calc_emis_80pc) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_80pc) { *calc = inst_calc_emis_80pc; return inst_cal_setup; } @@ -4009,7 +4009,7 @@ extern i1d3 *new_i1d3(icoms *icom, instType itype) { p->del = i1d3_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; amutex_init(p->lock); icmSetUnity3x3(p->ccmat); diff --git a/spectro/i1d3.h b/spectro/i1d3.h index 47f3858..47f3858 100644..100755 --- a/spectro/i1d3.h +++ b/spectro/i1d3.h diff --git a/spectro/i1disp.c b/spectro/i1disp.c index e9a375e..437e1fa 100644..100755 --- a/spectro/i1disp.c +++ b/spectro/i1disp.c @@ -2040,7 +2040,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (p->dtype == 0) { /* Eye-One Display 1 */ if (*calt & inst_calt_emis_offset) { - if (*calc != inst_calc_man_ref_dark) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_dark) { *calc = inst_calc_man_ref_dark; return inst_cal_setup; } @@ -2055,7 +2055,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ } else { /* Eye-One Display 2 */ if ((*calt & inst_calt_ref_freq) && p->refrmode != 0) { - if (*calc != inst_calc_emis_80pc) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_80pc) { *calc = inst_calc_emis_80pc; return inst_cal_setup; } @@ -2605,6 +2605,8 @@ i1disp_get_set_opt(inst *pp, inst_opt_type m, ...) /* Constructor */ extern i1disp *new_i1disp(icoms *icom, instType itype) { i1disp *p; + + if ((p = (i1disp *)calloc(sizeof(i1disp),1)) == NULL) { a1loge(icom->log, 1, "new_i1disp: malloc failed!\n"); return NULL; @@ -2632,7 +2634,7 @@ extern i1disp *new_i1disp(icoms *icom, instType itype) { p->del = i1disp_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; if (p->itype == instI1Disp2) p->dtype = 1; /* i1Display2 */ diff --git a/spectro/i1disp.h b/spectro/i1disp.h index 45e21db..45e21db 100644..100755 --- a/spectro/i1disp.h +++ b/spectro/i1disp.h diff --git a/spectro/i1pro.c b/spectro/i1pro.c index cc2d7f2..96335cc 100644..100755 --- a/spectro/i1pro.c +++ b/spectro/i1pro.c @@ -726,7 +726,7 @@ i1pro_get_set_opt(inst *pp, inst_opt_type m, ...) i1pro_set_noinitcalib(p, 0, 0); return inst_ok; - } if (m == inst_opt_noinitcalib) { + } else if (m == inst_opt_noinitcalib) { va_list args; int losecs = 0; @@ -839,7 +839,7 @@ extern i1pro *new_i1pro(icoms *icom, instType itype) { p->del = i1pro_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; i1pro_determine_capabilities(p); diff --git a/spectro/i1pro.h b/spectro/i1pro.h index 4366e4f..4366e4f 100644..100755 --- a/spectro/i1pro.h +++ b/spectro/i1pro.h diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c index 9a888f9..0b6fc69 100644..100755 --- a/spectro/i1pro_imp.c +++ b/spectro/i1pro_imp.c @@ -45,6 +45,10 @@ routine based on an emissive scan + the auto-correlation (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. */ /* @@ -1543,8 +1547,8 @@ i1pro_code i1pro_imp_calibrate( /* Wavelength calibration: */ if ((m->capabilities2 & I1PRO_CAP2_WL_LED) && (*calt & (inst_calt_wavelength | inst_calt_ap_flag)) - && (*calc == inst_calc_man_ref_white - || *calc == inst_calc_man_am_dark)) { + && ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white + || (*calc & inst_calc_cond_mask) == inst_calc_man_am_dark)) { double *wlraw; double optscale; double *abswav; @@ -1608,10 +1612,10 @@ i1pro_code i1pro_imp_calibrate( if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */ - || *calc == inst_calc_man_em_dark - || *calc == inst_calc_man_am_dark - || *calc == inst_calc_man_trans_dark) + && ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white /* Any condition conducive to dark calib */ + || (*calc & inst_calc_cond_mask) == inst_calc_man_em_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_am_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_trans_dark) && ( s->reflective || (s->emiss && !s->adaptive && !s->scan) || (s->trans && !s->adaptive))) { @@ -1698,10 +1702,10 @@ i1pro_code i1pro_imp_calibrate( /* Emissive scan black calibration: */ /* Emsissive scan (flash) uses the fastest possible scan rate (??) */ if ((*calt & (inst_calt_em_dark | inst_calt_ap_flag)) - && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */ - || *calc == inst_calc_man_em_dark - || *calc == inst_calc_man_am_dark - || *calc == inst_calc_man_trans_dark) + && ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white /* Any condition conducive to dark calib */ + || (*calc & inst_calc_cond_mask) == inst_calc_man_em_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_am_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_trans_dark) && (s->emiss && !s->adaptive && s->scan)) { int stm; @@ -1749,10 +1753,11 @@ i1pro_code i1pro_imp_calibrate( if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */ - || *calc == inst_calc_man_em_dark - || *calc == inst_calc_man_am_dark - || *calc == inst_calc_man_trans_dark) + /* Any condition conducive to dark calib */ + && ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white + || (*calc & inst_calc_cond_mask) == inst_calc_man_em_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_am_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_trans_dark) && ((s->emiss && s->adaptive && !s->scan) || (s->trans && s->adaptive && !s->scan))) { int i, j, k; @@ -1915,10 +1920,11 @@ i1pro_code i1pro_imp_calibrate( if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */ - || *calc == inst_calc_man_em_dark - || *calc == inst_calc_man_am_dark - || *calc == inst_calc_man_trans_dark) + /* Any condition conducive to dark calib */ + && ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white + || (*calc & inst_calc_cond_mask) == inst_calc_man_em_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_am_dark + || (*calc & inst_calc_cond_mask) == inst_calc_man_trans_dark) && ((s->emiss && s->adaptive && s->scan) || (s->trans && s->adaptive && s->scan))) { int j; @@ -2006,8 +2012,8 @@ i1pro_code i1pro_imp_calibrate( /* If we are doing a white reference calibrate */ if ((*calt & (inst_calt_ref_white | inst_calt_trans_vwhite | inst_calt_ap_flag)) - && ((*calc == inst_calc_man_ref_white && s->reflective) - || (*calc == inst_calc_man_trans_white && s->trans))) { + && (((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white && s->reflective) + || ((*calc & inst_calc_cond_mask) == inst_calc_man_trans_white && s->trans))) { double scale; a1logd(p->log,2,"\nDoing initial white calibration with current inttime %f, gainmode %d\n", @@ -2034,7 +2040,8 @@ i1pro_code i1pro_imp_calibrate( || (scale < 0.3 || scale > 2.0)) { /* Need to have done adaptive black measure to change inttime/gain params */ - if (*calc != inst_calc_man_ref_white && !s->idark_valid) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white + && !s->idark_valid) { m->mmode = mmode; /* Restore actual mode */ return I1PRO_RD_TRANSWHITERANGE; } @@ -2046,7 +2053,7 @@ i1pro_code i1pro_imp_calibrate( if (!s->emiss) s->cal_valid = 0; - if (*calc == inst_calc_man_ref_white) { + if ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white) { nummeas = i1pro_comp_nummeas(p, s->dadaptime, s->inttime); a1logd(p->log,2,"Doing another black calibration with dadaptime %f, min inttime %f, nummeas %d, gainmode %d\n", s->dadaptime, s->inttime, nummeas, s->gainmode); if ((ev = i1pro_dark_measure(p, s->dark_data, @@ -2093,7 +2100,7 @@ i1pro_code i1pro_imp_calibrate( a1logd(p->log,2,"Computed optimal white inttime %f and gainmode %d\n", s->inttime,s->gainmode); - if (*calc == inst_calc_man_ref_white) { + if ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white) { nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime); a1logd(p->log,2,"Doing final black calibration with dcaltime %f, opt inttime %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode); if ((ev = i1pro_dark_measure(p, s->dark_data, @@ -2173,7 +2180,7 @@ i1pro_code i1pro_imp_calibrate( a1logd(p->log,2, "scan white reference is not bright enough by %f\n",scale); } - if (*calc == inst_calc_man_ref_white) { + if ((*calc & inst_calc_cond_mask) == inst_calc_man_ref_white) { nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime); a1logd(p->log,2,"Doing final black calibration with dcaltime %f, opt inttime %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode); if ((ev = i1pro_dark_measure(p, s->dark_data, @@ -2252,7 +2259,7 @@ i1pro_code i1pro_imp_calibrate( /* Deal with a display integration time selection */ if ((*calt & (inst_calt_emis_int_time | inst_calt_ap_flag)) - && *calc == inst_calc_emis_white + && (*calc & inst_calc_cond_mask) == inst_calc_emis_white && (s->emiss && !s->adaptive && !s->scan)) { double scale; double *data; @@ -2323,45 +2330,49 @@ i1pro_code i1pro_imp_calibrate( if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) { sprintf(id, "Serial no. %d",m->serno); - if (*calc != inst_calc_man_ref_white) { - *calc = inst_calc_man_ref_white; /* Calibrate using white tile */ + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) { + /* Calibrate using white tile */ + *calc = inst_calc_man_ref_white; return I1PRO_CAL_SETUP; } } else if (*calt & inst_calt_wavelength) { /* Wavelength calibration */ if (cs->emiss && cs->ambient) { id[0] = '\000'; - if (*calc != inst_calc_man_am_dark) { - *calc = inst_calc_man_am_dark; /* Calibrate using ambient adapter */ + if ((*calc & inst_calc_cond_mask) != inst_calc_man_am_dark) { + /* Calibrate using ambient adapter */ + *calc = inst_calc_man_am_dark; return I1PRO_CAL_SETUP; } } else { sprintf(id, "Serial no. %d",m->serno); - if (*calc != inst_calc_man_ref_white) { - *calc = inst_calc_man_ref_white; /* Calibrate using white tile */ + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) { + /* Calibrate using white tile */ + *calc = inst_calc_man_ref_white; return I1PRO_CAL_SETUP; } } } else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */ id[0] = '\000'; - if (*calc != inst_calc_man_em_dark) { - *calc = inst_calc_man_em_dark; /* Any sort of dark reference */ + if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) { + /* Any sort of dark reference */ + *calc = inst_calc_man_em_dark; return I1PRO_CAL_SETUP; } } else if (*calt & inst_calt_trans_dark) { /* Transmissvice dark */ id[0] = '\000'; - if (*calc != inst_calc_man_trans_dark) { + 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 */ id[0] = '\000'; - if (*calc != inst_calc_man_trans_white) { + 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) { id[0] = '\000'; - if (*calc != inst_calc_emis_white) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) { *calc = inst_calc_emis_white; return I1PRO_CAL_SETUP; } @@ -7812,7 +7823,7 @@ i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw) { /* Compute standard/high res. downsampling filters for the given mode */ /* given the current wl_led_off, and set them as current, */ /* using triangular filters of the lagrange interpolation of the */ -/* CCD values. */ +/* CCD values (i.e. the same type of filter used by the OEM driver) */ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) { i1proimp *m = (i1proimp *)p->m; i1pro_state *s = &m->ms[m->mmode]; @@ -8033,7 +8044,7 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) { int ix1, ix1c; double aerr = 0.0; - a1logd(p->log,2,"Checking gemertated tables against EEProm table\n"); + a1logd(p->log,2,"Checking genertated tables against EEProm table\n"); ix1 = ix1c = 0; for (i = 0; i < m->nwav[0]; i++) { double err; @@ -8103,7 +8114,7 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) { /* High res congiguration */ /* Pick one of these: */ -#undef USE_TRI_LAGRANGE /* [und] Use normal res filter shape */ +#undef USE_TRI_LAGRANGE /* [und] Use OEM/normal res. filter shape for HiRes */ #undef USE_LANCZOS2 /* [und] Use lanczos2 filter shape */ #undef USE_LANCZOS3 /* [und] Use lanczos3 filter shape */ #undef USE_DECONV /* [und] Use deconvolution curve */ @@ -8112,7 +8123,7 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) { #undef USE_CUBIC /* [und] Use cubic spline filter */ #define DO_CCDNORM /* [def] Normalise CCD values to original */ -#define DO_CCDNORMAVG /* [und] Normalise averages rather than per CCD bin */ +#define DO_CCDNORMAVG /* [und ???] Normalise averages rather than per CCD bin */ /* (We relly on fine cal & white cal to fix it) */ #undef COMPUTE_DISPERSION /* Compute slit & optics dispersion from red laser data */ @@ -8321,14 +8332,15 @@ static double lanczos2(double wi, double x) { #ifdef USE_GAUSSIAN /* gausian */ - wi = wi/(2.0 * sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */ - x = x/(sqrt(2.0) * wi); + wi = wi/(sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */ + x = x/wi; // y = 1.0/(wi * sqrt(2.0 * DBL_PI)) * exp(-(x * x)); /* Unity area */ y = exp(-(x * x)); /* Center at 1.0 */ #endif #ifdef USE_LANCZOS2 /* lanczos2 */ + wi *= 1.05; // Improves smoothness. Why ? x = fabs(1.0 * x/wi); if (x >= 2.0) return 0.0; @@ -8398,7 +8410,6 @@ static double lanczos2(double wi, double x) { // bb = cc = 1.0/3.0; /* Mitchell */ bb = 0.5; cc = 0.5; - xx *= 1.2; if (xx < 1.0) { y = ( 12.0 - 9.0 * bb - 6.0 * cc) * xx * xx * xx @@ -8760,6 +8771,9 @@ i1pro_code i1pro_create_hr(i1pro *p) { /* From our crossover data, create a rspl that maps raw CCD index */ /* value into wavelegth. */ + /* (Generating a 4th order polynomial would probably be better, */ + /* since this is almost certainly what was used to create the original */ + /* filters.) */ { co sd[101]; /* Scattered data points */ datai glow, ghigh; @@ -9355,8 +9369,8 @@ i1pro_code i1pro_create_hr(i1pro *p) { /* Create or re-create the high resolution filters */ for (refl = 0; refl < 2; refl++) { /* for emis/trans and reflective */ -#define MXNOWL 500 /* Max hires bands */ -#define MXNOFC 64 /* Max hires coeffs */ +#define MXNOWL 200 /* Max hires bands */ +#define MXNOFC 32 /* Max hires coeffs */ #ifndef USE_TRI_LAGRANGE /* Use decimation filter */ int super = 0; /* nz if we're super sampling */ @@ -9490,7 +9504,7 @@ i1pro_code i1pro_create_hr(i1pro *p) { #else # define FINC 0.05 #endif - nn = (int)(fabs(w2 - w1)/0.2 + 0.5); /* Number to integrate over */ + nn = (int)(fabs(w2 - w1)/FINC + 0.5); /* Number to integrate over */ lw = w1; /* start at lower boundary of CCD cell */ ll = lanczos2(twidth, w1- cwl); @@ -9585,7 +9599,7 @@ i1pro_code i1pro_create_hr(i1pro *p) { m->mtx[1][refl] = m->mtx_c[1][refl]; } -#else /* USE_TRI_LAGRANGE, use triangle over lagrange interp */ +#else /* USE_TRI_LAGRANGE, OEM/normal res. triangle over lagrange interp */ /* Compute high res. reflective wavelength corrected filters */ if ((ev = i1pro_compute_wav_filters(p, 1, refl)) != I1PRO_OK) { diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h index 6bf8de4..6bf8de4 100644..100755 --- a/spectro/i1pro_imp.h +++ b/spectro/i1pro_imp.h diff --git a/spectro/icoms.c b/spectro/icoms.c index fb0fa20..b69b72a 100644..100755 --- a/spectro/icoms.c +++ b/spectro/icoms.c @@ -47,6 +47,7 @@ icompath icomFakeDevice = { instFakeDisp, "Fake Display Device" }; + /* Free an icompath */ static void icompath_del_contents(icompath *p) { @@ -101,6 +102,7 @@ static icompath *icompaths_get_path( return &icomFakeDevice; + if (port <= 0 || port > p->npaths) return NULL; @@ -152,7 +154,7 @@ static int icompaths_add_path(icompaths *p) { /* Add a serial path */ /* return icom error */ -static int icompaths_add_serial(icompaths *p, char *name, char *spath, int fast) { +static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_ser_attr sattr) { int rv; if ((rv = icompaths_add_path(p)) != ICOM_OK) @@ -166,7 +168,7 @@ static int icompaths_add_serial(icompaths *p, char *name, char *spath, int fast) a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n"); return ICOM_SYS; } - p->paths[p->npaths-1]->fast = fast; + p->paths[p->npaths-1]->sattr = sattr; return ICOM_OK; } @@ -319,7 +321,7 @@ 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->fast = pp->fast; + p->sattr = pp->sattr; } else { p->spath = NULL; } @@ -369,17 +371,17 @@ static int icoms_write_read( icoms *p, char *wbuf, /* Write puffer */ -int nwch, /* if > 0, number of characters to write */ +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 +double tout /* Timeout for write and then read (i.e. max = 2 x tout) */ ) { int rv = ICOM_OK; - a1logd(p->log, 8, "icoms_write_read: called with '%s'\n",icoms_fix(wbuf)); + 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"); @@ -387,14 +389,15 @@ double tout } #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) - /* Flush any stray chars if serial */ - if (p->usbd == NULL && p->hidd == NULL) { + /* Flush any stray chars if serial ?? */ + if (0 && p->usbd == NULL && p->hidd == NULL) { + char tbuf[100]; int debug = p->log->debug; if (debug < 8) p->log->debug = 0; for (; rv == ICOM_OK;) /* Until we get a timeout */ - rv = p->read(p, rbuf, bsize, NULL, NULL, bsize, 0.01); + rv = p->read(p, tbuf, 100, NULL, NULL, 100, 0.01); p->log->debug = debug; rv = ICOM_OK; } @@ -417,6 +420,14 @@ double tout return rv; } +/* Optional callback to client from device */ +/* Default implementation is a NOOP */ +static int icoms_interrupt(icoms *p, + int icom_int /* Interrupt cause */ +) { + return ICOM_OK; +} + /* icoms Constructor */ /* Return NULL on error */ icoms *new_icoms( @@ -472,6 +483,7 @@ icoms *new_icoms( p->write = NULL; /* Serial open or set_methods will set */ p->read = NULL; p->write_read = icoms_write_read; + p->interrupt = icoms_interrupt; p->del = icoms_del; diff --git a/spectro/icoms.h b/spectro/icoms.h index a9d8d34..2a282f0 100644..100755 --- a/spectro/icoms.h +++ b/spectro/icoms.h @@ -72,6 +72,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 */ @@ -81,7 +92,7 @@ struct _icompath{ char *name; /* instance description */ #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) char *spath; /* Serial device path */ - int fast; /* Virtual serial port that can be identified quickly */ + icom_ser_attr sattr; /* Virtual serial port that can be identified quickly */ #endif #ifdef ENABLE_USB int nep; /* Number of end points */ @@ -105,7 +116,7 @@ struct _icompaths { #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, int fast); + int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_ser_attr sattr); #endif /* ENABLE_SERIAL */ #ifdef ENABLE_USB @@ -209,10 +220,10 @@ typedef enum { icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */ } icomuflags; -/* Type of port */ +/* Type of port driver */ typedef enum { icomt_serial, /* Serial port */ - icomt_usbserial, /* USB (fast) Serial port, i.e. FTDI */ + icomt_usbserial, /* Serial port using fastserio.c driver */ icomt_usb, /* USB port */ icomt_hid /* HID (USB) port */ } icom_type; @@ -241,7 +252,10 @@ typedef enum { #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 */ +} icom_int; /* Cancelation token. */ typedef struct _usb_cancelt usb_cancelt; @@ -261,6 +275,8 @@ struct _icoms { int is_open; /* Flag, NZ if this port is open */ + void *icntx; /* Optional instrument context */ + #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) /* Serial port parameters */ @@ -274,7 +290,7 @@ struct _icoms { #if defined (UNIX) || defined(__APPLE__) int fd; /* Unix file descriptor */ #endif - int fast; /* Virtual serial port that can be identified quickly */ + icom_ser_attr sattr; /* Serial port attributes, such as being fast */ flow_control fc; baud_rate br; @@ -369,8 +385,8 @@ struct _icoms { /* return icom error */ int (*write)( struct _icoms *p, - char *buf, /* null terminated unless nch > 0 */ - int nch, /* if > 0, number of characters to write */ + char *buf, /* nul terminated unless nch > 0 */ + int nch, /* if > 0, number of characters to write, else nul terminated */ double tout); /* Timeout in seconds */ /* "Serial" read characters into the buffer */ @@ -379,11 +395,10 @@ struct _icoms { int (*read)( struct _icoms *p, char *buf, /* Buffer to store characters read */ - int bsize, /* Buffer size */ + int bsize, /* Buffer size. Make this larger than chars required! */ int *bread, /* Bytes read (not including forced '\000') */ char *tc, /* Terminating characters, NULL for none or char count mode */ - int ntc, /* Number of terminating characters or char count needed, */ - /* if 0 use bsize. */ + int ntc, /* Number of terminating characters or char count needed. */ double tout); /* Timeout in seconds */ /* "Serial" write and read */ @@ -391,9 +406,9 @@ struct _icoms { int (*write_read)( struct _icoms *p, char *wbuf, /* Write puffer */ - int nwch, /* if > 0, number of characters to write */ + int nwch, /* if > 0, number of characters to write, else nul terminated */ char *rbuf, /* Read buffer */ - int bsize, /* Buffer size */ + 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 */ @@ -466,6 +481,11 @@ struct _icoms { int *bwritten, /* Bytes written */ double tout); /* Timeout in seconds */ + /* Optional callback to client from device */ + /* Default implementation is a NOOP */ + int (*interrupt)(struct _icoms *p, + int icom_int); /* Interrupt cause */ + /* Destroy ourselves */ void (*del)(struct _icoms *p); diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c index 6e2741d..14258e9 100644..100755 --- a/spectro/icoms_nt.c +++ b/spectro/icoms_nt.c @@ -16,12 +16,6 @@ #include <conio.h> -/* Link list element to hold fast_serial port names */ -typedef struct fast_com_name { - char name[100]; - struct fast_com_name *next; -} fast_com_name; - #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *); #endif /* ENABLE_SERIAL */ @@ -36,7 +30,6 @@ int icompaths_refresh_paths(icompaths *p) { int i, j; LONG stat; HKEY sch; /* Serial coms handle */ - fast_com_name *fastlist = NULL, *fn, *fn2; a1logd(p->log, 8, "icoms_get_paths: called\n"); @@ -56,128 +49,9 @@ int icompaths_refresh_paths(icompaths *p) { #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) // (Beware KEY_WOW64_64KEY ?) - /* See if there are and FTDI fast_serial ports, and make a list of them */ - if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", - 0, KEY_READ, &sch)) != ERROR_SUCCESS) { - a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any FTDI serial ports\n"); - } else { - #define MXKSIZE 500 #define MXVSIZE 300 - a1logd(p->log, 6, "icoms_get_paths: looking through FTDI ports\n"); - for (i = 0; ; i++) { - char ftdiname[MXKSIZE]; - DWORD ftdisize = MXKSIZE; - HKEY devkey; - - stat = RegEnumKeyEx( - sch, /* handle to key to enumerate */ - i, /* index of subkey to enumerate */ - ftdiname, /* address of buffer for value name */ - &ftdisize, /* address for size of value name buffer */ - NULL, /* reserved */ - NULL, /* Address of value type */ - NULL, /* Address of value buffer */ - NULL /* Address of value buffer size */ - ); - if (stat == ERROR_NO_MORE_ITEMS) { - a1logd(p->log, 9, "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; - } - ftdiname[MXKSIZE-1] = '\000'; - - /* Enumerate subkeys, looking for Device Parameters/PortName */ - if ((stat = RegOpenKeyEx(sch, ftdiname, 0, KEY_READ, &devkey)) != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: OpenKey '%s' failed with %d\n",ftdiname,stat); - continue; - } - - a1logd(p->log, 6, "icoms_get_paths: looking through '%s'\n",ftdiname); - - for (j = 0; ; j++) { - char skname[MXKSIZE + 50]; /* Allow for cat of "\Device Parameters" */ - DWORD sksize = MXKSIZE; - HKEY skkey; - DWORD vtype; - char value[MXVSIZE]; - DWORD vsize = MXVSIZE; - - stat = RegEnumKeyEx( - devkey, /* handle to key to enumerate */ - j, /* index of subkey to enumerate */ - skname, /* address of buffer for value name */ - &sksize, /* address for size of value name buffer */ - NULL, /* reserved */ - NULL, /* Address of value type */ - NULL, /* Address of value buffer */ - NULL /* Address of value buffer size */ - ); - if (stat == ERROR_NO_MORE_ITEMS) { - a1logd(p->log, 9, "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; - } - skname[MXKSIZE-1] = '\000'; - - /* See if there is a Device Parameters\PortName */ - strcat(skname, "\\Device Parameters"); - - if ((stat = RegOpenKeyEx(devkey, skname, 0, KEY_READ, &skkey)) != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: OpenKey '%s' failed with %d\n",skname,stat); - continue; - } - stat = RegQueryValueEx( - skkey, /* handle to key to enumerate */ - "PortName", /* address of buffer for value name */ - NULL, /* reserved */ - &vtype, /* Address of value type */ - value, /* Address of value buffer */ - &vsize /* Address of value buffer size */ - ); - RegCloseKey(skkey); - - if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */ - || stat != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: RegQueryValueEx '%s' failed with %d\n",skname,stat); - break; - } - if (vtype != REG_SZ) { - a1logw(p->log, "icoms_get_paths: RegEnumValue '%s' didn't return stringz type\n",skname); - continue; - } - value[MXVSIZE-1] = '\000'; - - if ((fn = malloc(sizeof(fast_com_name))) == NULL) { - a1loge(p->log, 1, "icoms_get_paths: malloc failed\n"); - continue; - } - strcpy(fn->name, value); - fn->next = fastlist; - fastlist = fn; - a1logd(p->log, 2, "icoms_get_paths: got FTDI port '%s'\n",value); - - } - if ((stat = RegCloseKey(devkey)) != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat); - } - - } - if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat); - } - } - - /* Look in the registry for serial ports */ if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &sch)) != ERROR_SUCCESS) { @@ -189,12 +63,12 @@ int icompaths_refresh_paths(icompaths *p) { a1logd(p->log, 8, "icoms_get_paths: looking through all the values in the SERIALCOMM key\n"); for (i = 0; ; i++) { - char valname[MXKSIZE]; + char valname[MXKSIZE], *vp; DWORD vnsize = MXKSIZE; DWORD vtype; char value[MXVSIZE]; DWORD vsize = MXVSIZE; - int fast = 0; + icom_ser_attr sattr = icom_normal; stat = RegEnumValue( sch, /* handle to key to enumerate */ @@ -223,24 +97,33 @@ int icompaths_refresh_paths(icompaths *p) { continue; } - /* Check if it's a fast serial port */ - for (fn = fastlist; fn != NULL; fn = fn->next) { - if (strcmp(fn->name, value) == 0) - fast = 1; + if ((vp = strrchr(valname, '\\')) == NULL) + vp = valname; + else + vp++; + + /* See if it looks like a fast port */ + if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */ + sattr |= icom_fast; + } + + if (strncmp(vp, "BtPort", 6) == 0) { /* Blue tooth */ + sattr |= icom_fast; + sattr |= icom_bt; } #ifndef ENABLE_SERIAL - if (fast) { /* Only add fast ports if !ENABLE_SERIAL */ + if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */ #endif /* Add the port to the list */ - p->add_serial(p, value, value, fast); - a1logd(p->log, 8, "icoms_get_paths: Added path '%s' fast %d\n",value,fast); + p->add_serial(p, value, value, sattr); + a1logd(p->log, 8, "icoms_get_paths: Added path '%s' sattr 0x%x\n",value,sattr); #ifndef ENABLE_SERIAL } #endif /* If fast, try and identify it */ - if (fast) { + if (sattr & icom_fast) { icompath *path; icoms *icom; if ((path = p->get_last_path(p)) != NULL @@ -275,12 +158,6 @@ int icompaths_refresh_paths(icompaths *p) { a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths); - /* Free fast list */ - for (fn = fastlist; fn != NULL; fn = fn2) { - fn2 = fn->next; - free(fn); - } - return ICOM_OK; } @@ -330,11 +207,11 @@ 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); + ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word); if (p->is_open) p->close_port(p); @@ -547,7 +424,7 @@ word_length word) } /* ---------------------------------------------------------------------------------*/ -/* Serial write/read */ +/* Serial write, read */ /* Write the characters in the buffer out */ /* Data will be written up to the terminating nul */ @@ -563,69 +440,80 @@ double tout) COMMTIMEOUTS tmo; DWORD wbytes; int len; - long toc, i, top; /* Timout count, counter, timeout period */ - int rv = ICOM_OK; + long ttop, top; /* Total timeout period, timeout period */ + unsigned int stime, etime; /* Start and end times of USB operation */ + int retrv = ICOM_OK; + + a1logd(p->log, 8, "\nicoms_ser_write: writing '%s'\n", + nwch > 0 ? icoms_tohex(wbuf, nwch) : icoms_fix(wbuf)); - a1logd(p->log, 8, "icoms_ser_write: About to write '%s' ",icoms_fix(wbuf)); if (!p->is_open) { a1loge(p->log, ICOM_SYS, "icoms_ser_write: device not initialised\n"); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } if (nwch != 0) len = nwch; else len = strlen(wbuf); - tout *= 1000.0; /* Timout in msec */ - top = 20; /* Timeout period in msecs */ - toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */ - if (toc < 1) - toc = 1; + ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ + + a1logd(p->log, 8, "\nicoms_ser_write: ep 0x%x, bytes %d, ttop %d, quant %d\n", p->rd_ep, len, ttop, p->rd_qa); /* Set the timout value */ - tmo.ReadIntervalTimeout = top; + tmo.ReadIntervalTimeout = 0; tmo.ReadTotalTimeoutMultiplier = 0; - tmo.ReadTotalTimeoutConstant = top; + tmo.ReadTotalTimeoutConstant = ttop; tmo.WriteTotalTimeoutMultiplier = 0; - tmo.WriteTotalTimeoutConstant = top; + tmo.WriteTotalTimeoutConstant = ttop; if (!SetCommTimeouts(p->phandle, &tmo)) { a1loge(p->log, ICOM_SYS, "icoms_ser_write: SetCommTimeouts failed with %d\n",GetLastError()); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } + etime = stime = msec_time(); + /* Until data is all written or we time out */ - for (i = toc; i > 0 && len > 0;) { - if (!WriteFile(p->phandle, wbuf, len, &wbytes, NULL)) { + for (top = ttop; top > 0 && len > 0;) { + int rv; + rv = WriteFile(p->phandle, wbuf, len, &wbytes, NULL); + etime = msec_time(); + + if (wbytes > 0) { /* Account for bytes done */ + a1logd(p->log, 8, "icoms_ser_write: wrote %d bytes\n",wbytes); + wbuf += wbytes; + len -= wbytes; + } + if (rv == 0) { DWORD errs; if (!ClearCommError(p->phandle,&errs,NULL)) - error("Write to COM port failed, and Clear error failed"); + error("icoms_ser_write: failed, and Clear error failed"); if (errs & CE_BREAK) - rv |= ICOM_BRK; + retrv |= ICOM_BRK; if (errs & CE_FRAME) - rv |= ICOM_FER; + retrv |= ICOM_FER; if (errs & CE_RXPARITY) - rv |= ICOM_PER; + retrv |= ICOM_PER; if (errs & CE_RXOVER) - rv |= ICOM_OER; + retrv |= ICOM_OER; + a1logd(p->log, 8, "icoms_ser_write: read failed with 0x%x\n",rv); break; - } else if (wbytes == 0) { - i--; /* Timeout */ - } else if (wbytes > 0) { /* Account for bytes done */ - i = toc; - len -= wbytes; - wbuf += len; } + + top = ttop - (etime - stime); /* Remaining time */ } - if (i <= 0) { /* Timed out */ - rv |= ICOM_TO; + if (top <= 0) { /* Must have timed out */ + a1logd(p->log, 8, "icoms_ser_write: timeout, took %d msec out of %d\n",etime - stime,ttop); + retrv |= ICOM_TO; } - a1logd(p->log, 8, "icoms_ser_write: returning ICOM err 0x%x\n",rv); - p->lserr = rv; - return rv; + 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; } @@ -644,74 +532,62 @@ double tout /* Time out in seconds */ COMMTIMEOUTS tmo; DWORD rbytes; int j; - long toc, i, top; /* Timout count, counter, timeout period */ + long ttop, top; /* Total timeout period, timeout period */ + unsigned int stime, etime; /* Start and end times of USB operation */ char *rrbuf = rbuf; /* Start of return buffer */ - DCB dcb; - int bread = 0; - int rv = ICOM_OK; + int retrv = ICOM_OK; + int nreads; /* Number of reads performed */ if (p->phandle == NULL) { - a1loge(p->log, ICOM_SYS, "icoms_read: device not initialised\n"); - p->lserr = rv = ICOM_SYS; - return rv; + a1loge(p->log, ICOM_SYS, "icoms_ser_read: device not initialised\n"); + p->lserr = ICOM_SYS; + return p->lserr; } if (bsize < 3) { - a1loge(p->log, ICOM_SYS, "icoms_read: given too small a buffer (%d)\n",bsize); - p->lserr = rv = ICOM_SYS; - return rv; + a1loge(p->log, ICOM_SYS, "icoms_ser_read: given too small a buffer (%d)\n",bsize); + p->lserr = ICOM_SYS; + return p->lserr; } - tout *= 1000.0; /* Timout in msec */ - bsize--; /* Allow space for forced final null */ + for (j = 0; j < bsize; j++) + rbuf[j] = 0; + + ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ - top = 20; /* Timeout period in msecs */ - toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */ - if (toc < 1) - toc = 1; + a1logd(p->log, 8, "\nicoms_ser_read: bytes %d, ttop %d, ntc %d\n", bsize, ttop, ntc); /* Set the timout value */ - tmo.ReadIntervalTimeout = top; - tmo.ReadTotalTimeoutMultiplier = 0; - tmo.ReadTotalTimeoutConstant = top; + tmo.ReadIntervalTimeout = 20; /* small inter character to detect tc */ + tmo.ReadTotalTimeoutMultiplier = 0; /* No per byte */ + tmo.ReadTotalTimeoutConstant = ttop; /* Just overall total */ tmo.WriteTotalTimeoutMultiplier = 0; - tmo.WriteTotalTimeoutConstant = top; + tmo.WriteTotalTimeoutConstant = ttop; if (!SetCommTimeouts(p->phandle, &tmo)) { a1loge(p->log, ICOM_SYS, "icoms_ser_read: SetCommTimeouts failed with %d\n",GetLastError()); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } - if (tc == NULL) { /* no tc or char count mode */ - j = -1; - if (ntc > 0 && ntc < bsize) - bsize = ntc; /* Don't read more than ntc */ - } else { - j = 0; - } + bsize -= 1; /* Allow space for null */ + + /* Until data is all read, we time out, or the user aborts */ + etime = stime = msec_time(); + top = ttop; j = (tc == NULL && ntc <= 0) ? -1 : 0; /* Until data is all read or we time out */ - for (i = toc; i > 0 && bsize > 0 && j < ntc ;) { - if (!ReadFile(p->phandle, rbuf, bsize, &rbytes, NULL)) { - DWORD errs; - if (!ClearCommError(p->phandle,&errs,NULL)) - error("Read from COM port failed, and Clear error failed"); - if (errs & CE_BREAK) - rv |= ICOM_BRK; - if (errs & CE_FRAME) - rv |= ICOM_FER; - if (errs & CE_RXPARITY) - rv |= ICOM_PER; - if (errs & CE_RXOVER) - rv |= ICOM_OER; - break; - } else if (rbytes == 0) { - i--; /* Timeout */ - } else if (rbytes > 0) { /* Account for bytes done */ - i = toc; + for (nreads = 0; top > 0 && bsize > 0 && j < ntc ;) { + int rv; + rv = ReadFile(p->phandle, rbuf, bsize, &rbytes, NULL); + etime = msec_time(); + nreads++; + + if (rbytes > 0) { /* Account for bytes read */ + + a1logd(p->log, 8, "icoms_ser_read: read %d bytes, rbuf = '%s'\n",rbytes,icoms_fix(rrbuf)); + bsize -= rbytes; - bread += rbytes; if (tc != NULL) { while(rbytes--) { /* Count termination characters */ char ch = *rbuf++, *tcp = tc; @@ -722,24 +598,51 @@ double tout /* Time out in seconds */ tcp++; } } + a1logd(p->log, 8, "icoms_ser_read: tc count %d\n",j); } else { if (ntc > 0) j += rbytes; rbuf += rbytes; } } + + /* Deal with any errors */ + if (rv == 0) { + DWORD errs; + if (!ClearCommError(p->phandle,&errs,NULL)) + error("icoms_ser_read: failed, and Clear error failed"); + if (errs & CE_BREAK) + retrv |= ICOM_BRK; + if (errs & CE_FRAME) + retrv |= ICOM_FER; + if (errs & CE_RXPARITY) + retrv |= ICOM_PER; + if (errs & CE_RXOVER) + retrv |= ICOM_OER; + a1logd(p->log, 8, "icoms_ser_read: read failed with 0x%x, rbuf = '%s'\n",rv,icoms_fix(rrbuf)); + break; + } + top = ttop - (etime - stime); /* Remaining time */ } - if (i <= 0) { /* timed out */ - rv |= ICOM_TO; - } + *rbuf = '\000'; + a1logd(p->log, 8, "icoms_ser_read: read %d total bytes with %d reads\n",rbuf - rrbuf, nreads); if (pbread != NULL) - *pbread = bread; + *pbread = (rbuf - rrbuf); + + /* If ran out of time and not completed */ + a1logd(p->log, 8, "icoms_ser_read: took %d msec\n",etime - stime); + if (top <= 0 && bsize > 0 && j < ntc) { + a1logd(p->log, 8, "icoms_ser_read: timeout, took %d msec out of %d\n",etime - stime,ttop); + retrv |= ICOM_TO; + } - a1logd(p->log, 8, "icoms_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),rv); + a1logd(p->log, 8, "icoms_ser_read: took %d msec, returning '%s' ICOM err 0x%x\n", + etime - stime, tc == NULL && ntc > 0 ? icoms_tohex(rrbuf, rbuf - rrbuf) + : icoms_fix(rrbuf), retrv); - p->lserr = rv; - return rv; + p->lserr = retrv; + return p->lserr; } #endif /* ENABLE_SERIAL */ diff --git a/spectro/icoms_ux.c b/spectro/icoms_ux.c index 8fd1b3e..7fb7359 100644..100755 --- a/spectro/icoms_ux.c +++ b/spectro/icoms_ux.c @@ -98,7 +98,7 @@ int icompaths_refresh_paths(icompaths *p) { /* Find all the matching serial ports */ for (;;) { char pname[200]; - int fast = 0; + icom_ser_attr sattr = icom_normal; CFTypeRef dfp; /* Device file path */ @@ -122,19 +122,19 @@ int icompaths_refresh_paths(icompaths *p) { /* Would be nice to identify FTDI serial ports more specifically ? */ if (strstr(pname, "usbserial") != NULL) - fast = 1; + sattr |= icom_fast; #ifndef ENABLE_SERIAL - if (fast) { /* Only add fast ports if !ENABLE_SERIAL */ + if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */ #endif /* Add the port to the list */ - p->add_serial(p, pname, pname, fast); - a1logd(p->log, 8, "icoms_get_paths: Added path '%s' fast %d\n",pname, fast); + p->add_serial(p, pname, pname, sattr); + a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",pname, sattr); #ifndef ENABLE_SERIAL } #endif /* If fast, try and identify it */ - if (fast) { + if (sattr & icom_fast) { icompath *path; icoms *icom; if ((path = p->get_last_path(p)) != NULL @@ -217,7 +217,7 @@ int icompaths_refresh_paths(icompaths *p) { for (;;) { int fd; char *dpath; - int fast = 0; + icom_ser_attr sattr = icom_normal; if ((de = readdir(dd)) == NULL) break; @@ -271,21 +271,21 @@ int icompaths_refresh_paths(icompaths *p) { a1logd(p->log, 8, "icoms_get_paths: open'd serial \"%s\" - assume real\n",dpath); if (strncmp(de->d_name, "ttyUSB", 5) == 0) - fast = 1; + sattr |= icom_fast; #ifndef ENABLE_SERIAL - if (fast) { /* Only add fast ports if !ENABLE_SERIAL */ + if (sattr & icom_fast) { /* 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' fast %d\n",dpath,fast); + a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",dpath,sattr); #ifndef ENABLE_SERIAL } #endif free(dpath); /* If fast, try and identify it */ - if (fast) { + if (sattr & icom_fast) { icompath *path; icoms *icom; if ((path = p->get_last_path(p)) != NULL @@ -630,17 +630,21 @@ char *wbuf, /* null terminated unless nwch > 0 */ int nwch, /* if > 0, number of characters to write */ double tout ) { - int rv, retrv = ICOM_OK; int len, wbytes; - long toc, i, top; /* Timout count, counter, timeout period */ + long ttop, top; /* Total timeout period, timeout period */ + unsigned int stime, etime; /* Start and end times of USB operation */ struct pollfd pa[1]; /* Poll array to monitor serial write and stdin */ int nfd = 1; /* Number of fd's to poll */ struct termios origs, news; + int retrv = ICOM_OK; + + a1logd(p->log, 8, "\nicoms_ser_write: writing '%s'\n", + nwch > 0 ? icoms_tohex((unsigned char *)wbuf, nwch) : icoms_fix(wbuf)); if (!p->is_open) { a1loge(p->log, ICOM_SYS, "icoms_ser_write: device not initialised\n"); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } /* Setup to wait for serial output not block */ @@ -648,52 +652,56 @@ double tout pa[0].events = POLLOUT; pa[0].revents = 0; - /* Until timed out, aborted, or transmitted */ if (nwch != 0) len = nwch; else len = strlen(wbuf); - tout *= 1000.0; /* Timout in msec */ - a1logd(p->log, 8, "icoms_ser_write: About to write %d bytes",len); - top = 100; /* Timeout period in msecs */ - toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */ - if (toc < 1) - toc = 1; + ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ + + a1logd(p->log, 8, "\nicoms_ser_write: ep 0x%x, bytes %d, ttop %d, quant %d\n", p->rd_ep, len, ttop, p->rd_qa); + + etime = stime = msec_time(); + + /* Until data is all written or we time out */ + for (top = ttop; top > 0 && len > 0;) { + + if (poll_x(pa, nfd, top) > 0) { /* Wait for something */ - /* Until data is all written, we time out, or the user aborts */ - for(i = toc; i > 0 && len > 0;) { - if (poll_x(pa, nfd, top) > 0) { if (pa[0].revents != 0) { if (pa[0].revents != POLLOUT) { a1loge(p->log, ICOM_SYS, "icoms_ser_write: poll returned " "unexpected value 0x%x",pa[0].revents); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } /* We can write it without blocking */ - if ((wbytes = write(p->fd, wbuf, len)) < 0) { + wbytes = write(p->fd, wbuf, len); + if (wbytes < 0) { + a1logd(p->log, 8, "icoms_ser_write: write failed with %d\n",wbytes); retrv |= ICOM_SERW; break; + } else if (wbytes > 0) { - i = toc; + a1logd(p->log, 8, "icoms_ser_write: wrote %d bytes\n",wbytes); len -= wbytes; wbuf += wbytes; } } - } else { - i--; /* timeout (or error!) */ } - } - if (i <= 0) { /* Timed out */ - retrv |= ICOM_TO; + etime = msec_time(); + top = ttop - (etime - stime); /* Remaining time */ } - a1logd(p->log, 8, "icoms_ser_write: returning ICOM err 0x%x\n",retrv); + if (top <= 0) { /* Must have timed out */ + a1logd(p->log, 8, "icoms_ser_write: timeout, took %d msec out of %d\n",etime - stime,ttop); + retrv |= ICOM_TO; + } + a1logd(p->log, 8, "icoms_ser_write: took %d msec, returning ICOM err 0x%x\n",etime - stime,retrv); p->lserr = retrv; - return retrv; + return p->lserr; } /* Read characters into the buffer */ @@ -709,69 +717,71 @@ char *tc, /* Terminating characers, NULL for none or char count mode */ int ntc, /* Number of terminating characters or char count needed, if 0 use bsize */ double tout /* Time out in seconds */ ) { - int rv, retrv = ICOM_OK; - int rbytes; - long j, toc, i, top; /* Timout count, counter, timeout period */ + int j, rbytes; + long ttop, top; /* Total timeout period, timeout period */ + unsigned int stime, etime; /* Start and end times of USB operation */ struct pollfd pa[1]; /* Poll array to monitor serial read and stdin */ int nfd = 1; /* Number of fd's to poll */ struct termios origs, news; char *rrbuf = rbuf; /* Start of return buffer */ int bread = 0; + int retrv = ICOM_OK; + int nreads; /* Number of reads performed */ if (!p->is_open) { a1loge(p->log, ICOM_SYS, "icoms_ser_read: device not initialised\n"); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } if (bsize < 3) { a1loge(p->log, ICOM_SYS, "icoms_ser_read: given too small a buffer\n"); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } - a1logd(p->log, 8, "icoms_ser_read: About to read buf %d, tc %p ntc %d tout %f",bsize,tc,ntc,tout); + for (j = 0; j < bsize; j++) + rbuf[j] = 0; + + ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ + + a1logd(p->log, 8, "\nicoms_ser_read: bytes %d, ttop %d, ntc %d\n", bsize, ttop, ntc); /* Wait for serial input to have data */ pa[0].fd = p->fd; pa[0].events = POLLIN | POLLPRI; pa[0].revents = 0; - bsize--; /* Allow space for forced null */ - tout *= 1000.0; /* Timout in msec */ - - top = 100; /* Timeout period in msecs */ - toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */ - if (toc < 1) - toc = 1; + bsize -=1; /* Allow space for forced null */ - if (tc == NULL) { /* no tc or char count mode */ - j = -1; - if (ntc > 0 && ntc < bsize) - bsize = ntc; /* Don't read more than ntc */ - } else { - j = 0; - } /* Until data is all read, we time out, or the user aborts */ - for (i = toc; i > 0 && bsize > 0 && j < ntc ;) { + etime = stime = msec_time(); + j = (tc == NULL && ntc <= 0) ? -1 : 0; + + /* Until data is all read or we time out */ + for (top = ttop, nreads = 0; top > 0 && bsize > 0 && j < ntc ;) { + if (poll_x(pa, nfd, top) > 0) { if (pa[0].revents != 0) { int btr; if (pa[0].revents != POLLIN && pa[0].revents != POLLPRI) { a1loge(p->log, ICOM_SYS, "icoms_ser_read: poll on serin returned " "unexpected value 0x%x",pa[0].revents); - p->lserr = rv = ICOM_SYS; - return rv; + p->lserr = ICOM_SYS; + return p->lserr; } /* We have data to read from input */ - if ((rbytes = read(p->fd, rbuf, bsize)) < 0) { + rbytes = read(p->fd, rbuf, bsize); + if (rbytes < 0) { + a1logd(p->log, 8, "icoms_ser_read: read failed with %d, rbuf = '%s'\n",rbytes,icoms_fix(rrbuf)); retrv |= ICOM_SERR; break; + } else if (rbytes > 0) { - i = toc; /* Reset time */ + a1logd(p->log, 8, "icoms_ser_read: read %d bytes, rbuf = '%s'\n",rbytes,icoms_fix(rrbuf)); + bsize -= rbytes; - bread += rbytes; if (tc != NULL) { while(rbytes--) { /* Count termination characters */ char ch = *rbuf++, *tcp = tc; @@ -782,6 +792,7 @@ double tout /* Time out in seconds */ tcp++; } } + a1logd(p->log, 8, "icoms_ser_read: tc count %d\n",j); } else { if (ntc > 0) j += rbytes; @@ -789,22 +800,30 @@ double tout /* Time out in seconds */ } } } - } else { - i--; /* We timed out (or error!) */ } + etime = msec_time(); + top = ttop - (etime - stime); /* Remaining time */ } - if (i <= 0) /* timed out */ - retrv |= ICOM_TO; - *rbuf = '\000'; + a1logd(p->log, 8, "icoms_ser_read: read %d total bytes with %d reads\n",rbuf - rrbuf, nreads); if (pbread != NULL) - *pbread = bread; + *pbread = (rbuf - rrbuf); + + /* If ran out of time and not completed */ + a1logd(p->log, 8, "icoms_ser_read: took %d msec\n",etime - stime); + if (top <= 0 && bsize > 0 && j < ntc) { + a1logd(p->log, 8, "icoms_ser_read: timeout, took %d msec out of %d\n",etime - stime,ttop); + retrv |= ICOM_TO; + } - a1logd(p->log, 8, "icoms_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),retrv); + a1logd(p->log, 8, "icoms_ser_read: took %d msec, returning '%s' ICOM err 0x%x\n", + etime - stime, tc == NULL && ntc > 0 + ? icoms_tohex((unsigned char *)rrbuf, rbuf - rrbuf) + : icoms_fix(rrbuf), retrv); p->lserr = retrv; - return retrv; + return p->lserr; } #endif /* ENABLE_SERIAL */ diff --git a/spectro/ifiles b/spectro/ifiles index b2806f5..706d0b7 100644..100755 --- a/spectro/ifiles +++ b/spectro/ifiles @@ -17,3 +17,5 @@ hcfr.c colorhug.c specbos.c kleink10.c +ex1.c +smcube.c diff --git a/spectro/illumread.c b/spectro/illumread.c index 381f6b6..381f6b6 100644..100755 --- a/spectro/illumread.c +++ b/spectro/illumread.c diff --git a/spectro/inflate.c b/spectro/inflate.c index 55d8e65..55d8e65 100644..100755 --- a/spectro/inflate.c +++ b/spectro/inflate.c diff --git a/spectro/inst.c b/spectro/inst.c index 9aba1bd..ba12f9d 100644..100755 --- a/spectro/inst.c +++ b/spectro/inst.c @@ -51,6 +51,7 @@ #include "insttypes.h" #include "icoms.h" #include "inst.h" +#include "rspec.h" #include "insttypeinst.h" #include "ccmx.h" #include "ccss.h" @@ -376,6 +377,44 @@ char id[CALIDLEN]) { /* Condition identifier (ie. white reference ID, filter ID) return inst_unsupported; } +/* Return a description of the calibration type */ +char *calt2str(inst_cal_type calt) { + calt &= inst_calt_all_mask; + + if (calt & inst_calt_all) + return "All"; + if (calt & inst_calt_needed) + return "Needed"; + if (calt & inst_calt_available) + return "Needed"; + if (calt & inst_calt_wavelength) + return "Wavelength"; + if (calt & inst_calt_ref_white) + return "Reflective White or Emissive Dark"; + if (calt & inst_calt_ref_dark) + return "Reflective Light Trap (Black)"; + if (calt & inst_calt_ref_dark_gl) + return "Reflective Gloss"; + if (calt & inst_calt_emis_offset) + return "Emissive Offset"; + if (calt & inst_calt_emis_ratio) + return "Emissive Ratio"; + if (calt & inst_calt_em_dark) + return "Emissive Dark"; + if (calt & inst_calt_trans_white) + return "Transmissive White"; + if (calt & inst_calt_trans_vwhite) + return "Transmissive Variable White"; + if (calt & inst_calt_trans_dark) + return "Transmissive Dark"; + if (calt & inst_calt_emis_int_time) + return "Emissive Integration Time"; + if (calt & inst_calt_ref_freq) + return "Display Refresh Rate"; + + return "None or Unknown"; +} + /* Measure a display update delay. It is assumed that a */ /* black to white change has been made to the displayed color, */ /* and this will measure the time it took for the update to */ @@ -569,11 +608,12 @@ void *cntx /* Context for callback */ } + /* Set instrument type from USB port, if not specified */ itype = icom->itype; /* Instrument type if its known from usb/hid */ #if defined(ENABLE_FAST_SERIAL) - if (itype == instUnknown && !nocoms && icom->fast) { + if (itype == instUnknown && !nocoms && (icom->sattr & icom_fast)) { itype = fast_ser_inst_type(icom, 1, uicallback, cntx); /* Else type from serial */ } #endif /* ENABLE_FAST_SERIAL */ @@ -638,12 +678,14 @@ void *cntx /* Context for callback */ p = (inst *)new_spyd2(icom, itype); else if (itype == instSpyder5) p = (inst *)new_spyd2(icom, itype); - else if (itype == instHuey) + else if (itype == instEX1) + p = (inst *)new_ex1(icom, itype); + if (itype == instHuey) p = (inst *)new_huey(icom, itype); else if (itype == instSmile) p = (inst *)new_i1disp(icom, itype); - else if (itype == instEX1) - p = (inst *)new_ex1(icom, itype); + else if (itype == instSMCube) + p = (inst *)new_smcube(icom, itype); else if (itype == instHCFR) p = (inst *)new_hcfr(icom, itype); else if (itype == instColorHug @@ -801,14 +843,13 @@ static inst_disptypesel *expand_dlist(inst_disptypesel *list, int nlist, int *na if already used, remove it. if no selector remain, - allocate a free one. + allocate a free one from the fallback list. mark all used selectors We treat the first selector as more important - than any aliases that come after it, so we need - to do two passes to resolve what gets used. - - Use disptechs_set_sel() utility function to some of the work. + than any aliases that come after it, and the + aliases as more important than the fallback list, + so we need to do three passes through all the selections. */ /* Create the display type list */ @@ -823,6 +864,7 @@ int doccmx /* Add matching installed ccmx files */ int i, j, k, nlist = 0, nalist = 0; char usels[256]; /* Used selectors */ static char *asels = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int fail = 0; /* free the old list */ inst_del_disptype_list(*pdtlist, *pndtlist); @@ -830,25 +872,22 @@ int doccmx /* Add matching installed ccmx files */ *pndtlist = 0; for (i = 0; i < 256; i++) - usels[i] = 0; + usels[i] = ((char)-1); k = 0; /* Next selector index */ /* Add entries from the static list and their primary selectors */ - /* Count the number in the static list */ + /* (We're currently assuming that calibrations that the instrument */ + /* returns are not custom) */ + /* Count the number in the static list. */ for (i = 0; !(sdtlist[i].flags & inst_dtflags_end); i++) { if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL) return inst_internal_error; list[nlist-1] = sdtlist[i]; /* Struct copy */ - - if (disptechs_set_sel(2, list[nlist-1].sel, usels, &k, asels)) { - a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n"); - break; - } } - /* Add any ccss's */ + /* Add any OEM and custom ccss's */ if (doccss) { iccss *ss_list; if ((ss_list = list_iccss(NULL)) == NULL) { @@ -862,16 +901,13 @@ int doccmx /* Add matching installed ccmx files */ return inst_internal_error; list[nlist-1].flags = inst_dtflags_ccss | inst_dtflags_ld | inst_dtflags_wr; + if (!ss_list[i].oem) + list[nlist-1].flags |= inst_dtflags_custom; if (ss_list[i].sel != NULL) { strncpy(list[nlist-1].sel, ss_list[i].sel, INST_DTYPE_SEL_LEN); list[nlist-1].sel[INST_DTYPE_SEL_LEN-1] = '\000'; } - if (disptechs_set_sel(2, list[nlist-1].sel, usels, &k, asels)) { - a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n"); - break; - } - strncpy(list[nlist-1].desc, ss_list[i].desc, INST_DTYPE_DESC_LEN); list[nlist-1].desc[INST_DTYPE_DESC_LEN-1] = '\000'; list[nlist-1].dtech = ss_list[i].dtech; @@ -884,7 +920,7 @@ int doccmx /* Add matching installed ccmx files */ } } - /* Add any ccmx's */ + /* Add any OEM and custom ccmx's */ if (doccmx) { iccmx *ss_list; @@ -899,7 +935,7 @@ int doccmx /* Add matching installed ccmx files */ /* Check that there is a matching base calibation */ for (j = 0; j < nlist; j++) { if (ss_list[i].cc_cbid != 0 - && list[j].cbid == ss_list[i].cc_cbid) + && list[j].cbid == ss_list[i].cc_cbid) break; } if (j >= nlist) { @@ -911,15 +947,13 @@ int doccmx /* Add matching installed ccmx files */ return inst_internal_error; list[nlist-1].flags = inst_dtflags_ccmx | inst_dtflags_ld | inst_dtflags_wr; + if (!ss_list[i].oem) + list[nlist-1].flags |= inst_dtflags_custom; if (ss_list[i].sel != NULL) { strncpy(list[nlist-1].sel, ss_list[i].sel, INST_DTYPE_SEL_LEN); list[nlist-1].sel[INST_DTYPE_SEL_LEN-1] = '\000'; } - if (disptechs_set_sel(2, list[nlist-1].sel, usels, &k, asels)) { - a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n"); - break; - } strncpy(list[nlist-1].desc, ss_list[i].desc, INST_DTYPE_DESC_LEN); list[nlist-1].desc[INST_DTYPE_DESC_LEN-1] = '\000'; list[nlist-1].dtech = ss_list[i].dtech; @@ -932,19 +966,37 @@ int doccmx /* Add matching installed ccmx files */ } } - /* Create needed selectors */ + /* Set selectors from primary for cbid or custom first */ + for (i = 0; i < nlist; i++) { + if (list[i].cbid > 0 + || (list[i].flags & inst_dtflags_custom) != 0) { + disptechs_set_sel(0, i, list[i].sel, usels, &k, asels); + } + } + + /* Set selectors from primary for rest */ for (i = 0; i < nlist; i++) - disptechs_set_sel(4, list[i].sel, usels, &k, asels); + disptechs_set_sel(0, i, list[i].sel, usels, &k, asels); - /* Verify or delete any secondary selectors */ + /* Set remaining selectors from secondaries */ for (i = 0; i < nlist; i++) - disptechs_set_sel(3, list[i].sel, usels, &k, asels); + disptechs_set_sel(1, i, list[i].sel, usels, &k, asels); + + /* Set remaining from fallback (or give up and set to null) */ + for (i = 0; i < nlist; i++) { + fail = disptechs_set_sel(3, i, list[i].sel, usels, &k, asels); + } if (pndtlist != NULL) *pndtlist = nlist; if (pdtlist != NULL) *pdtlist = list; + if (fail) { + a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n"); + return inst_internal_error; + } + return inst_ok; } @@ -1045,6 +1097,7 @@ iccmx *list_iccmx(instType itype, int *no) { rv[j].dtech = dtech; rv[j].refr = refr; rv[j].sel = cs->sel; cs->sel = NULL; + rv[j].oem = cs->oem; icmCpy3x3(rv[j].mat, cs->matrix); cs->del(cs); j++; @@ -1056,6 +1109,7 @@ iccmx *list_iccmx(instType itype, int *no) { rv[j].dtech = disptech_unknown; rv[j].refr = -1; rv[j].sel = NULL; + rv[j].oem = 0; if (no != NULL) *no = j; @@ -1174,6 +1228,7 @@ iccss *list_iccss(int *no) { rv[j].dtech = dtech; rv[j].refr = refr; rv[j].sel = cs->sel; cs->sel = NULL; + rv[j].oem = cs->oem; rv[j].sets = cs->samples; cs->samples = NULL; rv[j].no_sets = cs->no_samp; cs->no_samp = 0; cs->del(cs); @@ -1185,6 +1240,7 @@ iccss *list_iccss(int *no) { rv[j].dtech = disptech_unknown; rv[j].refr = -1; rv[j].sel = NULL; + rv[j].oem = 0; rv[j].sets = NULL; rv[j].no_sets = 0; if (no != NULL) @@ -1233,7 +1289,8 @@ instType fast_ser_inst_type( void *cntx /* Context for callback */ ) { instType rv = instUnknown; - char buf[100]; +#define BUFSZ (128 + 10) + char buf[BUFSZ]; baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_9600, baud_nc }; unsigned int etime; unsigned int i; @@ -1255,18 +1312,18 @@ instType fast_ser_inst_type( if (!tryhard) break; /* try only once */ } + 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) { a1logd(p->log, 5, "fser_inst_type: set_ser_port failed with 0x%x\n",se); return instUnknown; /* Give up */ } -// a1logd(p->log, 5, "brt = %d\n",brt[i]); - if (brt[i] == baud_9600) { /* See if it's a Klein K10 */ - if ((se = p->write_read(p, "P0\r", 0, buf, 100, NULL, ">", 1, 0.100)) != inst_ok) { + 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; @@ -1279,19 +1336,50 @@ instType fast_ser_inst_type( } len = strlen(buf); - a1logd(p->log, 5, "len = %d\n",len); - /* 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; } - } else { + } + if (brt[i] == baud_38400) + { + int bread; + + /* See if it's a SwatchMate Cube. */ + /* The Cube uses RTS/CTS handshaking, but ignore this for identification. */ + buf[0] = 0x7e; + 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; + } + } + 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; + } + } + } + /* Bluetooth only uses baud_115200 */ + if ((p->sattr & icom_bt) == 0 || brt[i] == baud_115200) { + /* See if it's a JETI specbos */ - if ((se = p->write_read(p, "*idn?\r", 0, buf, 100, NULL, "\r", 1, 0.100)) != inst_ok) { + 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; @@ -1304,20 +1392,18 @@ instType fast_ser_inst_type( } len = strlen(buf); - a1logd(p->log, 5, "len = %d\n",len); - /* 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, "specbos1201\n"); + 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, "specbos\n"); + a1logd(p->log, 5, "fser_inst_type: found JETI specbos\n"); rv = instSpecbos; break; } @@ -1337,6 +1423,7 @@ instType fast_ser_inst_type( return rv; } +#undef BUFSZ #endif /* ENABLE_FAST_SERIAL */ @@ -1355,7 +1442,8 @@ static instType ser_inst_type( void *cntx /* Context for callback */ ) { instType rv = instUnknown; - char buf[100]; +#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 }; @@ -1374,7 +1462,7 @@ static instType ser_inst_type( bi = 0; /* The tick to give up on */ - etime = msec_time() + (long)(1000.0 * 20.0 + 0.5); + etime = msec_time() + (long)(20.0 * 1000.0 + 0.5); a1logd(p->log, 1, "ser_inst_type: Trying different baud rates (%u msec to go)\n",etime - msec_time()); @@ -1388,9 +1476,9 @@ static instType ser_inst_type( return instUnknown; /* Give up */ } -// a1logd(p->log, 5, "brt = %d\n",brt[i]); + 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, 100, &bread, "\r", 1, 0.5)) != inst_ok) { + if ((se = p->write_read(p, ";D024\r\n", 0, buf, BUFSZ, &bread, "\r", 1, 0.5)) != inst_ok) { /* Check for user abort */ if (uicallback != NULL) { inst_code ev; @@ -1445,7 +1533,7 @@ static instType ser_inst_type( /* SpectroScan */ if (ss) { rv = instSpectroScan; - if ((se = p->write_read(p, ";D030\r\n", 0, buf, 100, NULL, "\n", 1, 1.5)) == 0) { + if ((se = p->write_read(p, ";D030\r\n", 0, buf, BUFSZ, NULL, "\n", 1, 1.5)) == 0) { if (strlen(buf) >= 41) { hex2bin(&buf[5], 12); // a1logd(p->log, 5, "spectroscan type = '%s'\n",buf); @@ -1457,7 +1545,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, 100, NULL, ">", 1, 2.5)) != 0) + if ((se = p->write_read(p, "SV\r\n", 0, buf, BUFSZ, NULL, ">", 1, 2.5)) != 0) return instUnknown; if (strlen(buf) >= 12) { @@ -1486,6 +1574,7 @@ static instType ser_inst_type( return rv; } +#undef BUFSZ #endif /* ENABLE_SERIAL */ @@ -1567,7 +1656,7 @@ void inst_mode_to_sym(char sym[MAX_INST_MODE_SYM_SZ], inst_mode mode) { *cp++ = '\000'; } -/* Return a set of mode flags that correspondf to the symbolic encoding */ +/* Return a set of mode flags that correspond to the symbolic encoding */ /* Return nz if a symbol wasn't recognized */ int sym_to_inst_mode(inst_mode *mode, const char *sym) { int i; diff --git a/spectro/inst.h b/spectro/inst.h index a4184d4..00dd9b3 100644..100755 --- a/spectro/inst.h +++ b/spectro/inst.h @@ -308,13 +308,15 @@ typedef enum { inst2_has_scan_toll = 0x00004000, /* Instrument will honour modified scan tollerance */ inst2_no_feedback = 0x00008000, /* Instrument doesn't give any user feedback */ + inst2_opt_calibs = 0x00010000, /* Instrument has optional calibrations */ + inst2_has_leds = 0x00200000, /* Instrument has some user viewable indicator LEDs */ inst2_has_target = 0x00400000, /* Instrument has aiming target */ inst2_has_sensmode = 0x00800000, /* Instrument can report it's sensors mode */ inst2_has_battery = 0x01000000, /* Instrument is battery powered */ - inst2_disptype = 0x02000000, /* Has a display type selector */ + inst2_disptype = 0x02000000, /* Has a display/calibration type selector */ /* (ie. get_disptypesel(), set_disptype */ inst2_ccmx = 0x04000000, /* Colorimeter Correction Matrix capability */ @@ -361,9 +363,10 @@ typedef enum { inst_dtflags_mtx = 0x0001, /* matrix read from instrument */ inst_dtflags_ccss = 0x0002, /* ccss file */ inst_dtflags_ccmx = 0x0004, /* ccmx file */ - inst_dtflags_wr = 0x0010, /* Writable slot */ - inst_dtflags_ld = 0x0020, /* mtx/ccss/ccmx is loaded */ - inst_dtflags_default = 0x1000, /* Dafault calibration to use */ + inst_dtflags_custom = 0x0010, /* custom (i.e. not built in or OEM) */ + inst_dtflags_wr = 0x0020, /* Writable slot */ + inst_dtflags_ld = 0x0040, /* mtx/ccss/ccmx is loaded */ + inst_dtflags_default = 0x1000, /* Default calibration to use */ inst_dtflags_end = 0x8000 /* end marker */ } inst_dtflags; @@ -462,7 +465,10 @@ typedef enum { inst_opt_set_target_state = 0x001C, /* Set the aiming target state 0 = off, 1 == on, 2 = toggle [int] */ 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_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_type; @@ -488,6 +494,7 @@ typedef enum { /* Type of calibration needed/available/requested - corresponds to capabilities */ /* [ inst_calt_trans_vwhite is "variable" white transmission calibration, needed */ /* where transmission mode is being emulated. ] */ +/* Remember to update calt2str() */ typedef enum { /* Response to needs_calibration() */ inst_calt_none = 0x00000000, /* No calibration or unknown */ @@ -504,13 +511,14 @@ typedef enum { /* Specific type of calibration - corresponds to capabilities */ inst_calt_wavelength = 0x00000010, /* Wavelength calibration using refl. cal. surface */ inst_calt_ref_white = 0x00000020, /* Reflective white/emissive dark calibration */ - inst_calt_ref_dark = 0x00000040, /* Reflective dark calibration (in dark) */ - inst_calt_emis_offset = 0x00000080, /* Emissive offset/black calibration (dark surface) */ - inst_calt_emis_ratio = 0x00000100, /* Emissive ratio calibration */ - inst_calt_em_dark = 0x00000200, /* Emissive dark calibration (in dark) */ - inst_calt_trans_white = 0x00000400, /* Transmissive white reference calibration */ - inst_calt_trans_vwhite = 0x00000800, /* Transmissive variable white reference calibration */ - inst_calt_trans_dark = 0x00001000, /* Transmissive dark reference calibration */ + inst_calt_ref_dark = 0x00000040, /* Reflective dark calibration (light trap) */ + inst_calt_ref_dark_gl = 0x00000080, /* Reflective gloss calibration (black gloss surface) */ + inst_calt_emis_offset = 0x00000100, /* Emissive offset/black calibration (dark surface) */ + inst_calt_emis_ratio = 0x00000200, /* Emissive ratio calibration */ + inst_calt_em_dark = 0x00000400, /* Emissive dark calibration (in dark) */ + inst_calt_trans_white = 0x00000800, /* Transmissive white reference calibration */ + inst_calt_trans_vwhite = 0x00001000, /* Transmissive variable white reference calibration */ + inst_calt_trans_dark = 0x00002000, /* Transmissive dark reference calibration */ inst_calt_n_dfrble_mask = 0x0000fff0, /* Mask of non-deferrable calibrations */ @@ -526,6 +534,9 @@ typedef enum { } inst_cal_type; +/* Return a description of the first calibration type */ +char *calt2str(inst_cal_type calt); + /* Calibration conditions. */ /* This is how the instrument communicates to the calling program */ /* about how to facilitate a calibration, or what it's current measurement */ @@ -549,13 +560,14 @@ typedef enum { /* to be on the correct reference for the software triggered cal. */ inst_calc_man_ref_white = 0x00000010, /* place instrument on reflective white reference */ inst_calc_man_ref_whitek = 0x00000020, /* click instrument on reflective white reference */ - inst_calc_man_ref_dark = 0x00000030, /* place instrument in dark, not close to anything */ - inst_calc_man_em_dark = 0x00000040, /* place cap on instrument, put on dark surface or white ref. */ - inst_calc_man_am_dark = 0x00000050, /* Place cap over ambient sensor (wl calib capable) */ - inst_calc_man_cal_smode = 0x00000060, /* Put instrument sensor in calibration position */ - - inst_calc_man_trans_white = 0x00000070, /* place instrument on transmissive white reference */ - inst_calc_man_trans_dark = 0x00000080, /* place instrument on transmissive dark reference */ + inst_calc_man_ref_dark = 0x00000030, /* place instrument on light trap */ + inst_calc_man_dark_gloss = 0x00000040, /* place instrument on gloss black reference */ + inst_calc_man_em_dark = 0x00000050, /* place cap on instrument, put on dark surface or white ref. */ + inst_calc_man_am_dark = 0x00000060, /* Place cap over ambient sensor (wl calib capable) */ + inst_calc_man_cal_smode = 0x00000070, /* Put instrument sensor in calibration position */ + + inst_calc_man_trans_white = 0x00000080, /* place instrument on transmissive white reference */ + inst_calc_man_trans_dark = 0x00000090, /* place instrument on transmissive dark reference */ inst_calc_man_man_mask = 0x000000F0, /* user configured calibration mask */ inst_calc_emis_white = 0x00000100, /* Provide a white test patch */ @@ -567,7 +579,12 @@ typedef enum { inst_calc_emis_mask = 0x00000F00, /* Emmissive/display provided reference patch */ inst_calc_change_filter = 0x00010000, /* Filter needs changing on device - see id[] */ - inst_calc_message = 0x00020000 /* Issue a message. - see id[] */ + inst_calc_message = 0x00020000, /* Issue a message. - see id[] */ + + inst_calc_cond_mask = 0x0fffffff, /* Mask for conditions (i.e. remove flags) */ + + inst_calc_optional_flag = 0x80000000 /* Flag indicating calibration can be skipped */ + } inst_cal_cond; /* Clamping state */ @@ -600,6 +617,8 @@ typedef enum { inst_conf_ambient } inst_config; +# define EXRA_INST_OBJ + /* Off-line pending readings available (status) */ #define CALIDLEN 200 /* Maxumum length of calibration tile ID string */ @@ -610,6 +629,7 @@ typedef enum { /* after initialisation. */ #define INST_OBJ_BASE \ \ + EXRA_INST_OBJ \ a1log *log; /* Pointer to debug & error logging class */ \ instType itype; /* Instrument type determined by driver */ \ icoms *icom; /* Instrument coms object */ \ @@ -691,7 +711,8 @@ typedef enum { int allconfig, /* nz to return list for all configs, not just current. */ \ int recreate); /* nz to re-check for new ccmx & ccss files */ \ \ - /* Set the display type. index is into the inst_disptypesel[] returned */ \ + /* Set the display type or calibration mode. */ \ + /* index is into the inst_disptypesel[] returned */ \ /* returned by get_disptypesel(). clears col_cor_mat() and */ \ /* col_cal_spec_set(). */ \ inst_code (*set_disptype)( \ @@ -699,9 +720,10 @@ typedef enum { int index); \ \ /* Get the disptech and other corresponding info for the current */ \ - /* selected display type. Returns disptype_unknown by default. */ \ - /* Because refrmode can be overridden, it may not match the refrmode */ \ - /* of the dtech. (Pointers may be NULL if not needed) */ \ + /* selected display type or calibration mode. Returns disptype_unknown */ \ + /* by default. Because refrmode can be overridden, it may not */ \ + /* match the refrmode of the dtech. */ \ + /* (Pointers may be NULL if not needed) */ \ inst_code (*get_disptechi)( \ struct _inst *p, \ disptech *dtech, \ @@ -863,7 +885,7 @@ typedef enum { /* to determine the required calibration types and conditions. */ \ /* (The corresponding calibration types will be used & returned. */ \ \ - /* If no error is returned to the first call to calibrate() with */ \ + /* If no error is returned to the first call to calibrate() */ \ /* then the instrument was capable of calibrating without user or */ \ /* application intervention. If on the other hand calibrate() returns */ \ /* inst_cal_setup, then the appropriate action indicated by the value */ \ @@ -875,6 +897,13 @@ typedef enum { /* calibration to be performed. calibrate() returns inst_ok when no */ \ /* more calibrations remain. */ \ \ + /* If the calc has the inst_calc_optional_flag flag set, */ \ + /* then the user should be offered the option of skipping the */ \ + /* calibration. If they decide to skip it, return a calc with */ \ + /* inst_calc_optional_flag set, and if they want to proceed, */ \ + /* make sure the inst_calc_optional_flag is cleared in the returned */ \ + /* calc. */ \ + \ /* DOESN'T use the trigger mode */ \ /* Return inst_unsupported if *calt is not appropriate, */ \ /* inst_cal_setup if *calc is not appropriate. */ \ @@ -1067,6 +1096,7 @@ typedef struct { int cc_cbid; /* Calibration display type base ID required */ int refr; /* Refresh mode flag */ char *sel; /* UI selector characters (may be NULL) */ + int oem; /* nz if oem origin */ double mat[3][3]; /* The matrix values */ } iccmx; @@ -1089,6 +1119,7 @@ typedef struct { disptech dtech; /* Display Technology enumeration (optional if disp) */ int refr; /* Refresh mode flag */ char *sel; /* UI selector characters (may be NULL) */ + int oem; /* nz if oem origin */ xspect *sets; /* Set of sample spectra */ int no_sets; /* Number on set */ } iccss; diff --git a/spectro/instappsup.c b/spectro/instappsup.c index 112bab5..0762bbe 100644..100755 --- a/spectro/instappsup.c +++ b/spectro/instappsup.c @@ -33,6 +33,7 @@ #include "icoms.h" #include "inst.h" +#include "rspec.h" #include "insttypeinst.h" #include "instappsup.h" @@ -187,7 +188,7 @@ inst_code inst_handle_calibrate( /* We're done */ if ((ev & inst_mask) == inst_ok) { - if (calc == inst_calc_message) + if ((calc & inst_calc_cond_mask) == inst_calc_message) printf("%s\n",id); if (usermes) printf("Calibration complete\n"); @@ -226,94 +227,88 @@ inst_code inst_handle_calibrate( return inst_user_abort; } - /* Get user to do/setup calibration */ } else { - switch (calc) { + printf("\n"); + + /* Get user to do/setup calibration */ + switch (calc & inst_calc_cond_mask) { case inst_calc_uop_ref_white: printf("Do a reflective white calibration,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_uop_trans_white: printf("Do a transmissive white calibration,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_uop_trans_dark: printf("Do a transmissive dark calibration,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_ref_white: printf("Place the instrument on its reflective white reference %s,\n",id); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_ref_whitek: printf("Click the instrument on its reflective white reference %s,\n",id); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_ref_dark: - printf("Place the instrument in the dark, not in contact with any surface,\n"); + printf("Place the instrument on light trap, or in the dark,\n"); + printf("and distant from any surface,\n"); + printf(" and then hit any key to continue,\n"); + break; + + case inst_calc_man_dark_gloss: + printf("Place the instrument on black gloss reference\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_em_dark: printf("Place cap on the instrument, or place on a dark surface,\n"); printf("or place on the calibration reference,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_am_dark: printf("Place ambient adapter and cap on the instrument,\n"); printf("or place on the calibration reference,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_cal_smode: printf("Set instrument sensor to calibration position,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_trans_white: printf("Place the instrument on its transmissive white source,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_man_trans_dark: printf("Use the appropriate tramissive blocking to block the transmission path,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_change_filter: printf("Change filter on instrument to %s,\n",id); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_message: printf("%s\n",id); printf(" Hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); break; case inst_calc_emis_white: if (disp_setup == NULL || dwi == NULL) { /* No way of creating a test window */ printf("Place the instrument on a 100%% white test patch,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); } else { /* We need to display a 100% white patch to proceed with this */ /* type of calibration */ @@ -326,7 +321,6 @@ inst_code inst_handle_calibrate( if (disp_setup == NULL || dwi == NULL) { /* No way of creating a test window */ printf("Place the instrument on a 80%% white test patch,\n"); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); } else { /* We need to display a 80% white patch to proceed with this */ /* type of calibration */ @@ -339,13 +333,13 @@ inst_code inst_handle_calibrate( case inst_calc_emis_grey_darker: case inst_calc_emis_grey_ligher: if (dwi == NULL) { /* No way of creating a test window */ - if (calc == inst_calc_emis_grey) { + if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey) { p->cal_gy_level = 0.6; p->cal_gy_count = 0; - } else if (calc == inst_calc_emis_grey_darker) { + } else if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey_darker) { p->cal_gy_level *= 0.7; p->cal_gy_count++; - } else if (calc == inst_calc_emis_grey_ligher) { + } else if ((calc & inst_calc_cond_mask) == inst_calc_emis_grey_ligher) { p->cal_gy_level *= 1.4; if (p->cal_gy_level > 1.0) p->cal_gy_level = 1.0; @@ -358,7 +352,6 @@ inst_code inst_handle_calibrate( } else { printf("Place the instrument on a %d%% white test patch,\n", (int)(p->cal_gy_level * 100.0 + 0.5)); printf(" and then hit any key to continue,\n"); - printf(" or hit Esc or Q to abort: "); } } else { @@ -390,21 +383,37 @@ inst_code inst_handle_calibrate( a1logd(p->log,1,"inst_handle_calibrate unhandled calc case 0x%x, err 0x%x\n",calc,inst_internal_error); return inst_internal_error; } + if (calc & inst_calc_optional_flag) + printf(" or hit Esc or Q to abort, or S to skip: "); + else + printf(" or hit Esc or Q to abort: "); fflush(stdout); usermes = 1; + /* If we should wait for user to say we're in the right condition, */ + /* and this isn't a calibration that requires clicking the instrument */ + /* on the calibration tile, then wait for the an OK or abort or skip. */ if (!doimmediately - && calc != inst_calc_man_ref_whitek) { + && (calc & inst_calc_cond_mask) != inst_calc_man_ref_whitek) { empty_con_chars(); ch = next_con_char(); printf("\n"); + /* If optional calib. and user wants to skip it */ + /* Loop back to calibrate() with inst_calc_optional_flag still set */ + if ((calc & inst_calc_optional_flag) != 0 && ch == 's' || ch == 'S') { + printf("Skipped\n"); + goto oloop; + } if (ch == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') { a1logd(p->log,1,"inst_handle_calibrate user aborted 0x%x\n",inst_user_abort); return inst_user_abort; } } + /* Remove any skip flag and continue with the calibration */ + calc &= inst_calc_cond_mask; } + oloop:; } } diff --git a/spectro/instappsup.h b/spectro/instappsup.h index 8da4325..8da4325 100644..100755 --- a/spectro/instappsup.h +++ b/spectro/instappsup.h diff --git a/spectro/instlib.ksh b/spectro/instlib.ksh index 88796f8..88796f8 100644..100755 --- a/spectro/instlib.ksh +++ b/spectro/instlib.ksh diff --git a/spectro/instlib.txt b/spectro/instlib.txt index 661584d..661584d 100644..100755 --- a/spectro/instlib.txt +++ b/spectro/instlib.txt diff --git a/spectro/insttypeinst.h b/spectro/insttypeinst.h index a55c3d4..ad8047d 100644..100755 --- a/spectro/insttypeinst.h +++ b/spectro/insttypeinst.h @@ -20,6 +20,7 @@ #ifdef ENABLE_FAST_SERIAL # include "specbos.h" # include "kleink10.h" +# include "smcube.h" #endif #ifdef ENABLE_USB diff --git a/spectro/insttypes.c b/spectro/insttypes.c index 729b328..5a660a8 100644..100755 --- a/spectro/insttypes.c +++ b/spectro/insttypes.c @@ -98,6 +98,8 @@ char *inst_sname(instType itype) { return "K-10"; case instEX1: return "EX1"; + case instSMCube: + return "Cube"; case instColorHug: return "ColorHug"; case instColorHug2: @@ -169,6 +171,8 @@ char *inst_name(instType itype) { return "Klein K-10"; case instEX1: return "Image Engineering EX1"; + case instSMCube: + return "SwatchMate Cube"; case instColorHug: return "Hughski ColorHug"; case instColorHug2: @@ -258,6 +262,8 @@ instType inst_enum(char *name) { return instKleinK10; else if (strcmp(name, "Image Engineering EX1") == 0) return instEX1; + else if (strcmp(name, "SwatchMate Cube") == 0) + return instSMCube; else if (strcmp(name, "Hughski ColorHug") == 0) return instColorHug; else if (strcmp(name, "Hughski ColorHug2") == 0) @@ -447,6 +453,9 @@ int inst_illuminant(xspect *sp, instType itype) { case instEX1: return 1; /* Not applicable */ + 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 58c5bfe..ab80cd2 100644..100755 --- a/spectro/insttypes.h +++ b/spectro/insttypes.h @@ -26,16 +26,20 @@ /* Possible types of instruments */ typedef enum { instUnknown = 0, /* Undefined Instrument */ - instDTP20, /* Xrite DTP20 (Pulse) */ instDTP22, /* Xrite DTP22 (Digital Swatchbook) */ instDTP41, /* Xrite DTP41 */ instDTP51, /* Xrite DTP51 */ - instDTP92, /* Xrite DTP92 */ - instDTP94, /* Xrite DTP94 (Optix) */ instSpectrolino, /* GretagMacbeth Spectrolino */ instSpectroScan, /* GretagMacbeth SpectroScan */ instSpectroScanT, /* GretagMacbeth SpectroScanT */ instSpectrocam, /* Avantes Spectrocam */ + instSpecbos1201, /* JETI specbos 1201 */ + instSpecbos, /* JETI specbos XXXX */ + instKleinK10, /* Klein K10-A */ + instSMCube, /* SwatchMate Cube */ + instDTP20, /* Xrite DTP20 (Pulse) */ + instDTP92, /* Xrite DTP92 */ + instDTP94, /* Xrite DTP94 (Optix) */ instI1Disp1, /* GretagMacbeth i1 Display 1 */ instI1Disp2, /* GretagMacbeth i1 Display 2 */ instI1Disp3, /* Xrite i1 DisplayPro, ColorMunki Display */ @@ -51,9 +55,6 @@ typedef enum { instSpyder5, /* Datacolor Spyder5 */ instHuey, /* GretagMacbeth Huey */ instSmile, /* X-rite Colormunki Smile */ - instSpecbos1201, /* JETI specbos 1201 */ - instSpecbos, /* JETI specbos XXXX */ - instKleinK10, /* Klein K10-A */ instEX1, /* Image Engineering EX1 */ instColorHug, /* Hughski ColorHug */ instColorHug2, /* Hughski ColorHug2 */ diff --git a/spectro/iusb.h b/spectro/iusb.h index a254ec0..a254ec0 100644..100755 --- a/spectro/iusb.h +++ b/spectro/iusb.h diff --git a/spectro/kleink10.c b/spectro/kleink10.c index d632bdb..461cb28 100644..100755 --- a/spectro/kleink10.c +++ b/spectro/kleink10.c @@ -2252,7 +2252,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ /* Do the appropriate calibration */ if (*calt & inst_calt_emis_offset) { - if (*calc != inst_calc_man_em_dark) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) { *calc = inst_calc_man_em_dark; return inst_cal_setup; } @@ -2797,7 +2797,7 @@ extern kleink10 *new_kleink10(icoms *icom, instType itype) { p->del = k10_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; p->dtech = disptech_unknown; amutex_init(p->lock); diff --git a/spectro/kleink10.h b/spectro/kleink10.h index 4dcc334..4dcc334 100644..100755 --- a/spectro/kleink10.h +++ b/spectro/kleink10.h diff --git a/spectro/linear.cal b/spectro/linear.cal new file mode 100755 index 0000000..ac93eb5 --- /dev/null +++ b/spectro/linear.cal @@ -0,0 +1,272 @@ +CAL + +DESCRIPTOR "Argyll Device Calibration Curves" +ORIGINATOR "Argyll synthcal" +CREATED "Tue Aug 18 00:14:21 2015" +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/linear.sp b/spectro/linear.sp index 8851462..8851462 100644..100755 --- a/spectro/linear.sp +++ b/spectro/linear.sp diff --git a/spectro/madvrwin.c b/spectro/madvrwin.c index b96cd80..e131e5e 100644..100755 --- a/spectro/madvrwin.c +++ b/spectro/madvrwin.c @@ -20,15 +20,6 @@ # include <winsock2.h> # include <shlwapi.h> #endif -#ifdef UNIX -# include <sys/types.h> -# include <ifaddrs.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# ifdef __FreeBSD__ -# include <sys/socket.h> -# endif /* __FreeBSD__ */ -#endif #include "copyright.h" #include "aconfig.h" #include "icc.h" @@ -356,12 +347,12 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ return 0; } -/* Set/unset the blackground color flag */ +/* Set/unset the full screen black flag */ /* Return nz on error */ -static int madvrwin_set_bg(dispwin *p, int blackbg) { +static int madvrwin_set_fc(dispwin *p, int fullscreen) { int perc, bgperc, bgmode, border; - p->blackbg = blackbg; + p->fullscreen = fullscreen; /* Parameters that shouldn't change can be set to -1, but this doesn't seem */ /* to work for background level, so get current background level */ @@ -369,16 +360,16 @@ static int madvrwin_set_bg(dispwin *p, int blackbg) { debugr2((errout,"madVR_GetPatternConfig failed\n")); return 1; } - debugr2((errout,"madvrwin_set_bg: got pattern config %i, %i, %i, %i\n", + debugr2((errout,"madvrwin_set_fc: got pattern config %i, %i, %i, %i\n", perc, bgperc, bgmode, border)); /* Default test window is 10% of the width/height = 1% of the area*/ perc = (int)((p->width/100.0 * 0.1 * p->height/100.0 * 0.1) * 100.0 + 0.5); /* Background level is 1..100 in percent */ - debugr2((errout,"madvrwin_set_bg: setting pattern config %i, %i\n", - perc, blackbg ? 0 : bgperc)); - if (!madVR_SetPatternConfig(perc, blackbg ? 0 : bgperc, -1, -1)) { + debugr2((errout,"madvrwin_set_fc: setting pattern config %i, %i\n", + perc, fullscreen ? 0 : bgperc)); + if (!madVR_SetPatternConfig(perc, fullscreen ? 0 : bgperc, -1, -1)) { debugr2((errout,"madVR_SetPatternConfig failed\n")); return 1; } @@ -459,7 +450,7 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ) { @@ -487,7 +478,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->nowin = nowin; p->native = native; p->out_tvenc = 0; - p->blackbg = blackbg; + p->fullscreen = fullscreen; p->ddebug = ddebug; p->get_ramdac = madvrwin_get_ramdac; p->set_ramdac = madvrwin_set_ramdac; @@ -495,7 +486,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->uninstall_profile = madvrwin_uninstall_profile; p->get_profile = madvrwin_get_profile; p->set_color = madvrwin_set_color; - p->set_bg = madvrwin_set_bg; + p->set_fc = madvrwin_set_fc; p->set_pinfo = madvrwin_set_pinfo; p->set_update_delay = dispwin_set_update_delay; p->set_settling_delay = dispwin_set_settling_delay; @@ -535,7 +526,7 @@ int ddebug /* >0 to print debug statements to stderr */ madVR_Disable3dlut(); } - p->set_bg(p, blackbg); + p->set_fc(p, fullscreen); /* Create a suitable description */ { diff --git a/spectro/madvrwin.h b/spectro/madvrwin.h index 74c8f4f..bbaf32e 100644..100755 --- a/spectro/madvrwin.h +++ b/spectro/madvrwin.h @@ -28,7 +28,7 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding - will error */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ); diff --git a/spectro/mongoose.c b/spectro/mongoose.c index 019101e..019101e 100644..100755 --- a/spectro/mongoose.c +++ b/spectro/mongoose.c diff --git a/spectro/mongoose.h b/spectro/mongoose.h index 1ee0c47..1ee0c47 100644..100755 --- a/spectro/mongoose.h +++ b/spectro/mongoose.h diff --git a/spectro/munki.c b/spectro/munki.c index cc875c9..57f5ce8 100644..100755 --- a/spectro/munki.c +++ b/spectro/munki.c @@ -972,7 +972,7 @@ extern munki *new_munki(icoms *icom, instType itype) { p->del = munki_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; /* Preliminary capabilities */ munki_determine_capabilities(p); diff --git a/spectro/munki.h b/spectro/munki.h index 01eda29..01eda29 100644..100755 --- a/spectro/munki.h +++ b/spectro/munki.h diff --git a/spectro/munki_imp.c b/spectro/munki_imp.c index ee7b2b1..6f49d0d 100644..100755 --- a/spectro/munki_imp.c +++ b/spectro/munki_imp.c @@ -1015,11 +1015,11 @@ munki_code munki_imp_calibrate( /* Make sure that the instrument configuration matches the */ /* conditions */ - if (*calc == inst_calc_man_cal_smode) { + if ((*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode) { if (!m->nosposcheck && spos != mk_spos_calib) { return MUNKI_SPOS_CALIB; } - } else if (*calc == inst_calc_man_trans_white) { + } else if ((*calc & inst_calc_cond_mask) == inst_calc_man_trans_white) { if (!m->nosposcheck && spos != mk_spos_surf) { return MUNKI_SPOS_SURF; } @@ -1058,7 +1058,7 @@ munki_code munki_imp_calibrate( if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && *calc == inst_calc_man_cal_smode + && (*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode && ( s->reflective || (s->emiss && !s->adaptive && !s->scan) || (s->trans && !s->adaptive))) { @@ -1151,7 +1151,7 @@ if (ss->dark_int_time2 != s->dark_int_time2 /* Emissive scan black calibration: */ /* Emsissive scan (flash) uses the fastest possible scan rate (??) */ if ((*calt & (inst_calt_em_dark | inst_calt_ap_flag)) - && *calc == inst_calc_man_cal_smode + && (*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode && (s->emiss && !s->adaptive && s->scan)) { int stm; @@ -1199,7 +1199,7 @@ if (ss->dark_int_time2 != s->dark_int_time2 if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && *calc == inst_calc_man_cal_smode + && (*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode && ((s->emiss && s->adaptive && !s->scan) || (s->trans && s->adaptive && !s->scan))) { /* Adaptive where we can't measure the black reference on the fly, */ @@ -1364,7 +1364,7 @@ if (ss->idark_int_time[j] != s->idark_int_time[j]) if ((*calt & (inst_calt_ref_dark | inst_calt_em_dark | inst_calt_trans_dark | inst_calt_ap_flag)) - && *calc == inst_calc_man_cal_smode + && (*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode && ((s->emiss && s->adaptive && s->scan) || (s->trans && s->adaptive && s->scan))) { int j; @@ -1443,8 +1443,8 @@ if (ss->idark_int_time[j] != s->idark_int_time[j]) /* or a we are doing a tranmisive white reference calibrate */ if ((*calt & (inst_calt_ref_white | inst_calt_trans_vwhite | inst_calt_ap_flag)) - && ((*calc == inst_calc_man_cal_smode && s->reflective) - || (*calc == inst_calc_man_trans_white && s->trans))) { + && (((*calc & inst_calc_cond_mask) == inst_calc_man_cal_smode && s->reflective) + || ((*calc & inst_calc_cond_mask) == inst_calc_man_trans_white && s->trans))) { // && s->cfdate < cdate) double dead_time = 0.0; /* Dead integration time */ double scale; @@ -1596,7 +1596,7 @@ if (ss->idark_int_time[j] != s->idark_int_time[j]) /* Deal with a display integration time selection */ if ((*calt & (inst_calt_emis_int_time | inst_calt_ap_flag)) - && *calc == inst_calc_emis_white + && (*calc & inst_calc_cond_mask) == inst_calc_emis_white // && s->cfdate < cdate && (s->emiss && !s->adaptive && !s->scan)) { double scale; @@ -1665,31 +1665,31 @@ if (ss->idark_int_time[j] != s->idark_int_time[j]) /* Make sure there's the right condition for the calibration */ if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) { /* Reflective calib */ - if (*calc != inst_calc_man_cal_smode) { + 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_em_dark) { /* Emissive Dark calib */ id[0] = '\000'; - if (*calc != inst_calc_man_cal_smode) { + 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 */ id[0] = '\000'; - if (*calc != inst_calc_man_cal_smode) { + 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. */ id[0] = '\000'; - if (*calc != inst_calc_man_trans_white) { + 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) { id[0] = '\000'; - if (*calc != inst_calc_emis_white) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) { *calc = inst_calc_emis_white; return MUNKI_CAL_SETUP; } @@ -6256,7 +6256,7 @@ void munki_scale_specrd( #define USE_GAUSSIAN /* [def] Use gaussian filter shape, else lanczos2 */ #define DO_CCDNORM /* [def] Normalise CCD values to original */ -#define DO_CCDNORMAVG /* [unde] Normalise averages rather than per CCD bin */ +#define DO_CCDNORMAVG /* [und???] Normalise averages rather than per CCD bin */ #ifdef NEVER /* Plot the matrix coefficients */ @@ -6352,13 +6352,15 @@ static double lanczos2(double wi, double x) { #ifdef USE_GAUSSIAN /* gausian */ - wi = wi/(2.0 * sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */ - x = x/(sqrt(2.0) * wi); + wi = wi/(sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */ + x = x/wi; // y = 1.0/(wi * sqrt(2.0 * DBL_PI)) * exp(-(x * x)); /* Unity area */ y = exp(-(x * x)); /* Center at 1.0 */ #else + /* lanczos2 */ + wi *= 1.05; // Improves smoothness. Why ? x = fabs(1.0 * x/wi); if (x >= 2.0) return 0.0; @@ -6821,8 +6823,8 @@ munki_code munki_create_hr(munki *p, int ref) { { double fshmax; /* filter shape max wavelength from center */ -#define MXNOWL 500 /* Max hires bands */ -#define MXNOFC 64 +#define MXNOWL 200 /* Max hires bands */ +#define MXNOFC 32 munki_fc coeff2[MXNOWL][MXNOFC]; /* New filter cooefficients */ double twidth; diff --git a/spectro/munki_imp.h b/spectro/munki_imp.h index ea9451f..ea9451f 100644..100755 --- a/spectro/munki_imp.h +++ b/spectro/munki_imp.h diff --git a/spectro/oemarch.c b/spectro/oemarch.c index e3e262c..a9bbda1 100644..100755 --- a/spectro/oemarch.c +++ b/spectro/oemarch.c @@ -1845,9 +1845,9 @@ static ccss *parse_EDR( dtech = dinfo->dtech; trefmode = dinfo->refr; - /* Set it's values */ + /* Set it's values (OEM set) */ rv->set_ccss(rv, "X-Rite", creatdate, NULL, dispdesc, dtech, trefmode, tsel, - "CS1000", samples, nsets); + "CS1000", 1, samples, nsets); } free(tdtypes); diff --git a/spectro/oemarch.h b/spectro/oemarch.h index b0b1a65..b0b1a65 100644..100755 --- a/spectro/oemarch.h +++ b/spectro/oemarch.h diff --git a/spectro/oeminst.c b/spectro/oeminst.c index bce7a67..bce7a67 100644..100755 --- a/spectro/oeminst.c +++ b/spectro/oeminst.c diff --git a/spectro/pollem.c b/spectro/pollem.c index f7578c8..f7578c8 100644..100755 --- a/spectro/pollem.c +++ b/spectro/pollem.c diff --git a/spectro/pollem.h b/spectro/pollem.h index f8a86ee..f8a86ee 100644..100755 --- a/spectro/pollem.h +++ b/spectro/pollem.h diff --git a/spectro/rspec.c b/spectro/rspec.c new file mode 100755 index 0000000..49d725b --- /dev/null +++ b/spectro/rspec.c @@ -0,0 +1,1258 @@ + +/* + * Argyll Color Correction System + * + * Author: Graeme W. Gill + * Date: 20015 + * + * Copyright 2006 - 2015 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 i1pro_imp.c & munki_imp.c + */ + +/* + * A library for processing raw spectrometer values. + * + * Currently this is setup for the EX1 spectrometer, + * but the longer term plan is to expand the functionality + * so that it becomes more generic, and can replace a lot + * of common code in i1pro_imp.c & munki_imp.c. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <time.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 */ +#include "xspect.h" +#include "insttypes.h" +#include "conv.h" +#include "icoms.h" +#include "inst.h" +#include "rspec.h" + +/* -------------------------------------------------- */ +#if defined(__APPLE__) && defined(__POWERPC__) + +/* Workaround for a ppc gcc 3.3 optimiser bug... */ +static int gcc_bug_fix(int i) { + static int nn; + nn += i; + return nn; +} +#endif /* APPLE */ + +/* -------------------------------------------------- */ +/* Setup code */ + +/* Fit a wavelength polynomial to a set of mapping points */ +// ~~~~9999 + +/* Completely clear an rspec_inf. */ +void clear_rspec_inf(rspec_inf *inf) { + memset(inf, 0, sizeof(rspec_inf)); +} + +/* Completely free contesnt of rspec_inf. */ +void free_rspec_inf(rspec_inf *inf) { + + if (inf != NULL) { + if (inf->straylight != NULL) { + error("rspec_inf: help - don't know how to free straylight!"); + } + + if (inf->wlcal) + free(inf->wlcal); + + if (inf->findex != NULL) + free(inf->findex); + if (inf->fnocoef != NULL) + free(inf->fnocoef); + if (inf->fcoef != NULL) + free(inf->fcoef); + + if (inf->lin != NULL) + free(inf->lin); + + if (inf->idark[0] != NULL) + del_rspec(inf->idark[0]); + if (inf->idark[1] != NULL) + del_rspec(inf->idark[1]); + + if (inf->ecal != NULL) + free(inf->ecal); + + clear_rspec_inf(inf); /* In case it gets reused */ + } +} + + +/* return the number of samples for the given spectral type */ +int rspec_typesize(rspec_inf *inf, rspec_type ty) { + int no; + if (ty == rspec_sensor) + no = inf->nsen; + else if (ty == rspec_raw) + no = inf->nraw; + else if (ty == rspec_wav) + no = inf->nwav; + else + error("rspec_typesize type %d unknown",ty); + return no; +} + +/* Compute the valid raw range from the calibration information */ +void rspec_comp_raw_range_from_ecal(rspec_inf *inf) { + int i; + + if (inf->ecaltype != rspec_raw) + error("rspec_comp_raw_range_from_ecal: ecaltype not raw"); + + for (i = 0; i < inf->nraw; i++) { + if (inf->ecal[i] != 0.0) { + inf->rawrange.off = i; + break; + } + } + if (i >= inf->nraw) + error("rspec_comp_raw_range_from_ecal: ecal is zero"); + + for (i = inf->rawrange.off; i < inf->nraw; i++) { + if (inf->ecal[i] == 0.0) { + break; + } + } + inf->rawrange.num = i - inf->rawrange.off; +} + +/* Convert a raw index to nm using polynomial */ +double rspec_raw2nm(rspec_inf *inf, double rix) { + int k; + double wl; + + if (inf->nwlcal == 0) + error("rspec_raw2nm: nwlcal == 0"); + +// ~~~~9999 test fudge +// rix += 15; + + /* Compute polinomial */ + for (wl = inf->wlcal[inf->nwlcal-1], k = inf->nwlcal-2; k >= 0; k--) + wl = wl * rix + inf->wlcal[k]; + + return wl; +} + +/* Convert a cooked index to nm */ +double rspec_wav2nm(rspec_inf *inf, double ix) { + return inf->wl_short + ix * inf->wl_space; +} + +/* -------------------------------------------------- */ + +/* Create a new rspec from scratch. */ +/* Don't allocate samp if nmeas == 0 */ +/* This always succeeds (i.e. application bombs if malloc fails) */ +rspec *new_rspec(rspec_inf *inf, rspec_type ty, int nmeas) { + rspec *p; + int no; + + if ((p = (rspec *)calloc(1, sizeof(rspec))) == NULL) { + error("Malloc failure in rspec()"); + } + p->inf = inf; + p->stype = ty; + + p->nmeas = nmeas; + p->nsamp = rspec_typesize(inf, p->stype); + if (nmeas > 0) + p->samp = dmatrix(0, p->nmeas-1, 0, p->nsamp-1); + + return p; +} + +/* Create a new rspec based on an existing prototype */ +/* If nmeas == 0, create space for the same number or measurements */ +rspec *new_rspec_proto(rspec *rs, int nmeas) { + rspec *p; + + if ((p = (rspec *)calloc(1, sizeof(rspec))) == NULL) { + error("Malloc failure in rspec()"); + } + p->inf = rs->inf; + p->stype = rs->stype; + p->mtype = rs->mtype; + p->state = rs->state; + p->inttime = rs->inttime; + + if (nmeas == 0) + p->nmeas = rs->nmeas; + else + p->nmeas = nmeas; + p->nsamp = rs->nsamp; + p->samp = dmatrix(0, p->nmeas-1, 0, p->nsamp-1); + + return p; +} + +/* Create a new rspec by cloning an existing one */ +rspec *new_rspec_clone(rspec *rs) { + rspec *p; + int i, j; + + if ((p = (rspec *)calloc(1, sizeof(rspec))) == NULL) { + error("Malloc failure in rspec()"); + } + p->inf = rs->inf; + p->stype = rs->stype; + p->mtype = rs->mtype; + p->state = rs->state; + p->inttime = rs->inttime; + + p->nmeas = rs->nmeas; + p->nsamp = rs->nsamp; + p->samp = dmatrix(0, p->nmeas-1, 0, p->nsamp-1); + + for (i = 0; i < p->nmeas; i++) { + for (j = 0; j < p->nsamp; j++) { + p->samp[i][j] = rs->samp[i][j]; + } + } + + return p; +} + +/* Free a rspec */ +void del_rspec(rspec *p) { + if (p != NULL) { + if (p->samp != NULL) + free_dmatrix(p->samp, 0, p->nmeas-1, 0, p->nsamp-1); + free(p); + } +} + +/* Plot the first rspec */ +void plot_rspec1(rspec *p) { + int i, no; + double xx[RSPEC_MAXSAMP]; + double yy[RSPEC_MAXSAMP]; + + no = rspec_typesize(p->inf, p->stype); + + for (i = 0; i < no; i++) { + if (p->stype == rspec_wav) + xx[i] = rspec_wav2nm(p->inf, (double)i); + else + xx[i] = (double)i; + yy[i] = p->samp[0][i]; + } + do_plot(xx, yy, NULL, NULL, no); +} + +/* Plot the first rspec of 2 */ +void plot_rspec2(rspec *p1, rspec *p2) { + int i, no; + double xx[RSPEC_MAXSAMP]; + double y1[RSPEC_MAXSAMP]; + double y2[RSPEC_MAXSAMP]; + + // Should check p1 & p2 are compatible ?? + + no = rspec_typesize(p1->inf, p1->stype); + + for (i = 0; i < no; i++) { + if (p1->stype == rspec_wav) + xx[i] = rspec_wav2nm(p1->inf, (double)i); + else + xx[i] = (double)i; + y1[i] = p1->samp[0][i]; + y2[i] = p2->samp[0][i]; + } + do_plot(xx, y1, y2, NULL, no); +} + +void plot_ecal(rspec_inf *inf) { + int i, no; + double xx[RSPEC_MAXSAMP]; + double yy[RSPEC_MAXSAMP]; + + no = rspec_typesize(inf, inf->ecaltype); + + for (i = 0; i < no; i++) { + if (inf->ecaltype == rspec_wav) + xx[i] = rspec_wav2nm(inf, (double)i); + else + xx[i] = (double)i; + yy[i] = inf->ecal[i]; + } + do_plot(xx, yy, NULL, NULL, no); +} + + +/* -------------------------------------------------- */ + +/* Return the largest value */ +/* Optionally return the measurement and sample idex of that sample */ +double largest_val_rspec(int *pmix, int *psix, rspec *raw) { + double mx = -1e38; + int mi = -1, mj = -1; + int i, j; + + if (raw->nmeas <= 0) + error("largest_val_rspec: raw has zero measurements"); + + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + if (raw->samp[i][j] > mx) { + mx = raw->samp[i][j]; + mi = i; + mj = j; + } + } + } + if (pmix != NULL) + *pmix = mi; + if (psix != NULL) + *psix = mj; + + return mx; +} + +/* return a raw rspec from a sensor rspec */ +/* (This does not make any adjustments to the values) */ +rspec *extract_raw_from_sensor_rspec(rspec *sens) { + rspec *raw; + int off, i, j; + + if (sens->stype != rspec_sensor) + error("extract_raw_from_sensor_rspec: input is not sensor type"); + + raw = new_rspec(sens->inf, rspec_raw, sens->nmeas); + + raw->mtype = sens->mtype; + raw->state = sens->state; + raw->inttime = sens->inttime; + + off = sens->inf->lightrange.off; + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + raw->samp[i][j] = sens->samp[i][off + j]; + } + } + + return raw; +} + +/* Return an interpolated dark reference value from idark */ +double ex1_interp_idark_val(rspec_inf *inf, int mix, int six, double inttime) { + double idv; + double w0, w1; + int i, j; + + w1 = (inttime - inf->idark[0]->inttime)/(inf->idark[1]->inttime - inf->idark[0]->inttime); + w0 = 1.0 - w1; + + idv = w0 * inf->idark[0]->samp[mix][six] + w1 * inf->idark[1]->samp[mix][six]; + + return idv; +} + +/* Return an interpolated dark reference from idark */ +rspec *ex1_interp_idark(rspec_inf *inf, double inttime) { + double w0, w1; + int i, j; + rspec *dark; + + w1 = (inttime - inf->idark[0]->inttime)/(inf->idark[1]->inttime - inf->idark[0]->inttime); + w0 = 1.0 - w1; + + dark = new_rspec_proto(inf->idark[0], 0); + + for (i = 0; i < inf->idark[0]->nmeas; i++) { + for (j = 0; j < inf->idark[0]->nsamp; j++) + dark->samp[i][j] = w0 * inf->idark[0]->samp[i][j] + w1 * inf->idark[1]->samp[i][j]; + } + + return dark; +} + +/* Subtract the adaptive black */ +void subtract_idark_rspec(rspec *raw) { + rspec_inf *inf = raw->inf; + int i, j; + rspec *dark; + + if (raw->state & rspec_dcal) + error("subtract_idark_rspec: already done"); + + if (raw->stype != inf->idark[0]->stype) + error("subtract_idark_rspect: idark does not match rspec type"); + + dark = ex1_interp_idark(inf, raw->inttime); + + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + raw->samp[i][j] -= dark->samp[0][j]; + } + } + + raw->state |= rspec_dcal; +} + +/* Apply non-linearity */ +double linearize_val_rspec(rspec_inf *inf, double ival) { + double oval = ival; + int k; + + if (ival >= 0.0) { + for (oval = inf->lin[inf->nlin-1], k = inf->nlin-2; k >= 0; k--) { + oval = oval * ival + inf->lin[k]; + } + + if (inf->lindiv) /* EX1 divides */ + oval = ival/oval; + } + return oval; +} + +/* Invert non-linearity. */ +/* Since the linearisation is nearly a straight line, */ +/* a simple Newton inversion will suffice. */ +double inv_linearize_val_rspec(rspec_inf *inf, double targv) { + double oval, ival = targv, del = 100.0; + int i, k; + + for (i = 0; i < 200 && fabs(del) > 1e-7; i++) { + for (oval = inf->lin[inf->nlin-1], k = inf->nlin-2; k >= 0; k--) + oval = oval * ival + inf->lin[k]; + if (inf->lindiv) /* EX1 divides */ + oval = ival/oval; + + del = (targv - oval); + ival += 0.99 * del; + } + return ival; +} + +/* Correct non-linearity */ +void linearize_rspec(rspec *raw) { + rspec_inf *inf = raw->inf; + int i, j; + rspec *dark; + + if (raw->state & rspec_lin) + error("linearize_rspec: already done"); + + if (raw->state & rspec_int) + error("linearize_rspec: can't be integration time adjusted"); + + if (!(raw->state & rspec_dcal)) + error("linearize_rspec: needs black subtract"); + + if (inf->nlin > 0) { + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + raw->samp[i][j] = linearize_val_rspec(inf, raw->samp[i][j]); + } + } + } + raw->state |= rspec_lin; +} + +/* Apply the emsissive calibration */ +void emis_calibrate_rspec(rspec *raw) { + rspec_inf *inf = raw->inf; + int i, j; + + if (raw->state & rspec_cal) + error("emis_calibrate_rspec: already done"); + + if (raw->stype != raw->inf->ecaltype) + error("emis_calibrate_rspec: ecaltype does not match rspec type"); + + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + raw->samp[i][j] *= inf->ecal[j]; + } + } + raw->state |= rspec_cal; +} + +/* Scale to the integration time */ +void inttime_calibrate_rspec(rspec *raw) { + rspec_inf *inf = raw->inf; + int i, j; + + if (raw->state & rspec_int) + error("inttime_calibrate_rspec: already done"); + + for (i = 0; i < raw->nmeas; i++) { + for (j = 0; j < raw->nsamp; j++) { + raw->samp[i][j] /= raw->inttime; + } + } + + raw->inttime = 1.0; + + raw->state |= rspec_int; +} + +/* return a wav rspec from a raw rspec */ +/* (This does not make any adjustments to the values) */ +rspec *convert_wav_from_raw_rspec(rspec *raw) { + rspec_inf *inf = raw->inf; + rspec *wav; + int cx, sx, i, j, k; + + if (raw->stype != rspec_raw) + error("extract_raw_from_sensor_rspec: input is not raw type"); + + wav = new_rspec(raw->inf, rspec_wav, raw->nmeas); + + wav->mtype = raw->mtype; + wav->state = raw->state; + wav->inttime = raw->inttime; + + for (i = 0; i < wav->nmeas; i++) { /* For each measurement */ + for (cx = j = 0; j < inf->nwav; j++) { /* For each wav sample */ + double oval = 0.0; + + sx = inf->findex[j]; /* Starting index */ + for (k = 0; k < inf->fnocoef[j]; k++, cx++, sx++) /* For each matrix value */ + oval += inf->fcoef[cx] * raw->samp[i][sx]; + wav->samp[i][j] = oval; + } + } + + return wav; +} + +/* -------------------------------------------------- */ + + +/* Filter code in i1pro_imp is in: + + i1pro_compute_wav_filters() X-Rite way + i1pro_create_hr() Using gausian + + */ + +/* Resampling kernels. (There are more in i1pro_imp.c) */ + +/* They aren't expected to be unity area, as they will be */ +/* normalized anyway. */ +/* wi is the width of the filter */ + +static double triangle(double wi, double x) { + double y = 0.0; + + x = fabs(x/wi); + y = 1.0 - x; + if (y < 0.0) + y = 0.0; + + return y; +} + +static double gausian(double wi, double x) { + double y = 0.0; + + wi = wi/(sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */ + x = x/wi; + y = exp(-(x * x)); /* Center at 1.0 */ + + return y; +} + +static double lanczos2(double wi, double x) { + double y = 0.0; + + wi *= 1.05; // Improves smoothness. Why ? + + x = fabs(1.0 * x/wi); + if (x >= 2.0) + return 0.0; + if (x < 1e-6) + return 1.0; + y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/2.0)/(DBL_PI * x/2.0); + + return y; +} + +static double lanczos3(double wi, double x) { + double y = 0.0; + + x = fabs(1.0 * x/wi); + if (x >= 3.0) + return 0.0; + if (x < 1e-6) + return 1.0; + y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/3.0)/(DBL_PI * x/3.0); + + return y; +} + +static double cubicspline(double wi, double x) { + double y = 0.0; + double xx = x; + double bb, cc; + + xx = fabs(1.0 * x/wi); + +// bb = cc = 1.0/3.0; /* Mitchell */ + bb = 0.5; + cc = 0.5; + + if (xx < 1.0) { + y = ( 12.0 - 9.0 * bb - 6.0 * cc) * xx * xx * xx + + (-18.0 + 12.0 * bb + 6.0 * cc) * xx * xx + + ( 6.0 - 2.0 * bb); + y /= (6.0 - 2.0 * bb); + } else if (xx < 2.0) { + y = ( -1.0 * bb - 6.0 * cc) * xx * xx * xx + + ( 6.0 * bb + 30.0 * cc) * xx * xx + + (-12.0 * bb - 48.0 * cc) * xx + + ( 8.0 * bb + 24.0 * cc); + y /= (6.0 - 2.0 * bb); + } else { + y = 0.0; + } + + return y; +} + +/* Create the wavelength resampling filters */ +void rspec_make_resample_filters(rspec_inf *inf) { + double twidth = inf->wl_space; + double rawspace; /* Average raw band spacing wl */ + double fshmax; /* filter shape max wavelength from center */ + double finc; /* Integration step size */ + int maxcoeffs; /* Maximum coefficients per filter */ + int **coeff_ix; /* [band][coef] Raw index */ + double **coeff_we; /* [band][coef] Weighting */ + double (*kernel)(double wi, double x) = NULL; /* Filter kernel */ + int xcount; + int i, j, k; + + if (inf->ktype == rspec_triangle) + kernel = triangle; + else if (inf->ktype == rspec_gausian) + kernel = gausian; + else if (inf->ktype == rspec_lanczos2) + kernel = lanczos2; + else if (inf->ktype == rspec_lanczos3) + kernel = lanczos3; + else if (inf->ktype == rspec_cubicspline) + kernel = cubicspline; + else + error("rspec_make_resample_filters: unknown kernel %d",inf->ktype); + +#ifdef NEVER // Check kernel sums to 1.0 +{ + double x, y; + + for (x = 0.0; x < 5.0; x += 0.1) { + y = kernel(1.0, x - 4.0) + + kernel(1.0, x - 3.0) + + kernel(1.0, x - 2.0) + + kernel(1.0, x - 1.0) + + kernel(1.0, x) + + kernel(1.0, x + 1.0) + + kernel(1.0, x + 2.0); + + kernel(1.0, x + 3.0); + + kernel(1.0, x + 4.0); + + printf("Offset %f sum %f\n",x,y); + } + +} +#endif // NEVER + + /* Aproximate raw value spacing in nm */ + rawspace = (inf->wl_long - inf->wl_short)/inf->rawrange.num; +//printf("~1 rawspace = %f\n",rawspace); + + /* Figure the extent of the filter kernel. We assume they */ + /* all have a finite extent. */ + for (fshmax = 50.0; fshmax >= 0.0; fshmax -= 0.01) { + if (fabs(kernel(twidth, fshmax)) > 1e-6) { + fshmax += 0.01; + break; + } + } +//printf("~1 fshmax = %f\n",fshmax); + + if (fshmax <= 0.0) + error("rspec_make_resample_filters: fshmax search failed\n"); + + a1logd(inf->log, 4,"rspec_make_resample_filters: fshmax = %f\n",fshmax); + + /* Figure number of raw samples over kernel extent. */ + /* (Allow generous factor for non-linearity) */ + maxcoeffs = (int)floor(2.0 * 1.4 * fshmax/rawspace + 3.0); + + a1logd(inf->log, 4,"rspec_make_resample_filters: maxcoeffs = %d\n",maxcoeffs); + + /* Figure out integration step size */ +#ifdef FAST_HIGH_RES_SETUP + finc = twidth/50.0; + if (rawspace/finc < 10.0) + finc = rawspace/10.0; +#else + finc = twidth/15.0; + if (rawspace/finc < 4.0) + finc = rawspace/4.0; +#endif + + a1logd(inf->log, 4,"rspec_make_resample_filters: integration step = %f\n",finc); + + if (inf->fnocoef != NULL) + free(inf->fnocoef); + if ((inf->fnocoef = (int *)calloc(inf->nwav, sizeof(int))) == NULL) + error("rspec_make_resample_filters: malloc failure"); + + /* Space to build filter coeficients */ + coeff_ix = imatrix(0, inf->nwav-1, 0, maxcoeffs-1); + coeff_we = dmatrix(0, inf->nwav-1, 0, maxcoeffs-1); + + /* For all the usable raw bands */ + for (i = inf->rawrange.off+1; i < (inf->rawrange.off+inf->rawrange.num-1); i++) { + double w1, wl, w2; + + /* Translate CCD center and boundaries to calibrated wavelength */ + wl = rspec_raw2nm(inf, (double)i); + w1 = rspec_raw2nm(inf, (double)i - 0.5); + w2 = rspec_raw2nm(inf, (double)i + 0.5); + +// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2); + + /* For each output filter */ + for (j = 0; j < inf->nwav; j++) { + double cwl, rwl; /* center, relative wavelegth */ + double we; + + cwl = rspec_wav2nm(inf, (double)j); + rwl = wl - cwl; /* raw relative wavelength to filter */ + + if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax) + continue; /* Doesn't fall into this filter */ + + /* Integrate in finc nm increments from filter shape */ + /* using triangular integration. */ + { + int nn; + double lw, ll; + + nn = (int)(fabs(w2 - w1)/finc + 0.5); /* Number to integrate over */ + + lw = w1; /* start at lower boundary of CCD cell */ + ll = kernel(twidth, w1 - cwl); + we = 0.0; + for (k = 0; k < nn; k++) { + double cw, cl; + +#if defined(__APPLE__) && defined(__POWERPC__) + gcc_bug_fix(k); +#endif + cw = w1 + (k+1.0)/(nn + 1.0) * fabs(w2 - w1); /* wl to sample */ + cl = kernel(twidth, cw - cwl); + we += 0.5 * (cl + ll) * fabs(lw - cw); /* Area under triangle */ + ll = cl; + lw = cw; + } + } + + if (inf->fnocoef[j] >= maxcoeffs) + error("rspec_make_resample_filters: run out of high res filter space\n"); + + coeff_ix[j][inf->fnocoef[j]] = i; + coeff_we[j][inf->fnocoef[j]++] = we; +// printf("~1 filter %d, cwl %f, rwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,rwl,i,we,info->fnocoef[j]); + } + } + + /* Convert hires filters into runtime format: */ + + /* Allocate or reallocate high res filter tables */ + if (inf->findex != NULL) + free(inf->findex); + if (inf->fcoef != NULL) + free(inf->fcoef); + + if ((inf->findex = (int *)calloc(inf->nraw, sizeof(int))) == NULL) + error("rspec_make_resample_filters: malloc index failed!\n"); + + /* Count the total number of coefficients */ + for (xcount = j = 0; j < inf->nwav; j++) { + inf->findex[j] = coeff_ix[j][0]; /* raw starting index */ + xcount += inf->fnocoef[j]; + } + +//printf("~1 total coefs = %d\n",xcount); + + /* Allocate space for them */ + if ((inf->fcoef = (double *)calloc(xcount, sizeof(double))) == NULL) + error("rspec_make_resample_filters: malloc index failed!\n"); + + /* Normalize the weight * nm to 1.0, and pack them into the run-time format */ + for (i = j = 0; j < inf->nwav; j++) { + int sx; + double rwi, twe = 0.0; + + sx = inf->findex[j]; /* raw starting index */ + + for (k = 0; k < inf->fnocoef[j]; sx++, k++) { + /* Width of raw band in nm */ + rwi = fabs(rspec_raw2nm(inf, (double)sx - 0.5) + - rspec_raw2nm(inf, (double)sx + 0.5)); + twe += rwi * coeff_we[j][k]; + } + + if (twe > 0.0) + twe = 1.0/twe; + else + twe = 1.0; + +// printf("Output %d, nocoefs %d, norm weight %f:\n",j,inf->fnocoef[j],twe); + + for (k = 0; k < inf->fnocoef[j]; k++, i++) { + inf->fcoef[i] = coeff_we[j][k] * twe; +// printf(" coef %d packed %d from raw %d val %f\n",k,i,inf->findex[j]+k,inf->fcoef[i]); + } + } + + free_imatrix(coeff_ix, 0, inf->nwav-1, 0, maxcoeffs-1); + free_dmatrix(coeff_we, 0, inf->nwav-1, 0, maxcoeffs-1); +} + +//printf("~1 line %d\n",__LINE__); + +/* Plot the wave resampling filters */ +void plot_resample_filters(rspec_inf *inf) { + double *xx, *ss; + double **yy; + int i, j, k, sx; + +//printf("~1 nraw = %d\n",inf->nraw); + + xx = dvectorz(0, inf->nraw-1); /* X index */ + yy = dmatrixz(0, 5, 0, inf->nraw-1); /* Curves distributed amongst 5 graphs */ + /* with 6th holding sum */ + for (i = 0; i < inf->nraw; i++) + xx[i] = i; + + /* For each output wavelength */ + for (i = j = 0; j < inf->nwav; j++) { + + sx = inf->findex[j]; /* raw starting index */ +//printf("Output %d raw sx %d\n",j,sx); + + /* For each matrix value */ + for (k = 0; k < inf->fnocoef[j]; k++, sx++, i++) { + yy[5][sx] += 0.5 * inf->fcoef[i]; + yy[j % 5][sx] = inf->fcoef[i]; +//printf(" filter %d six %d weight = %e\n",k,sx,inf->fcoef[i]); + } + } + + printf("Wavelength re-sampling curves:\n"); +// do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], 150); + 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); +} + +/* ================================================== */ +/* Calibration file support */ + +/* Open the file. nz wr for write mode, else read */ +/* Return nz on error */ +int calf_open(calf *x, a1log *log, char *fname, int wr) { + char nmode[10]; + char cal_name[200]; + char **cal_paths = NULL; + int no_paths = 0; + + memset((void *)x, 0, sizeof(calf)); + x->log = log; + + if (wr) + strcpy(nmode, "w"); + else + strcpy(nmode, "r"); + +#if !defined(O_CREAT) && !defined(_O_CREAT) +# error "Need to #include fcntl.h!" +#endif +#if defined(O_BINARY) || defined(_O_BINARY) + strcat(nmode, "b"); +#endif + + /* Create the file name */ + if (wr) + sprintf(cal_name, "ArgyllCMS/%s", fname); + else + sprintf(cal_name, "ArgyllCMS/%s" SSEPS "color/%s", fname, fname); + if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_write, xdg_user, cal_name)) < 1) { + a1logd(x->log,1,"calf_open: xdg_bds returned no paths\n"); + return 1; + } + + a1logd(x->log,2,"calf_open: %s file '%s'\n",cal_paths[0], wr ? "saving to" : "restoring from"); + + /* Check the last modification time */ + if (!wr) { + struct sys_stat sbuf; + + if (sys_stat(cal_paths[0], &sbuf) == 0) { + x->lo_secs = time(NULL) - sbuf.st_mtime; + a1logd(x->log,2,"calf_open:: %d secs from instrument last open\n",x->lo_secs); + } else { + a1logd(x->log,2,"calf_open:: stat on file failed\n"); + } + } + + if ((wr && create_parent_directories(cal_paths[0])) + || (x->fp = fopen(cal_paths[0], nmode)) == NULL) { + a1logd(x->log,2,"calf_open: failed to open file for %s\n",wr ? "writing" : "reading"); + xdg_free(cal_paths, no_paths); + return 1; + } + xdg_free(cal_paths, no_paths); + + a1logd(x->log,2,"calf_open: suceeded\n"); + + return 0; +} + +/* Update the modification time */ +/* Return nz on error */ +int calf_touch(a1log *log, char *fname) { + char cal_name[200]; + char **cal_paths = NULL; + int no_paths = 0; + int rv; + + /* Locate the file name */ + sprintf(cal_name, "ArgyllCMS/%s" SSEPS "color/%s", fname, fname); + + if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_read, xdg_user, cal_name)) < 1) { + a1logd(log,2,"calf_touch: xdg_bds failed to locate file'\n"); + return 1; + } + + a1logd(log,2,"calf_touch: touching file '%s'\n",cal_paths[0]); + + if ((rv = sys_utime(cal_paths[0], NULL)) != 0) { + a1logd(log,2,"calf_touch: failed with %d\n",rv); + xdg_free(cal_paths, no_paths); + return 1; + } + xdg_free(cal_paths, no_paths); + + return 0; +} + +/* Rewind and reset for another read */ +void calf_rewind(calf *x) { + x->ef = 0; + x->chsum = 0; + x->nbytes = 0; + rewind(x->fp); +} + +/* Close the file and free any memory */ +/* return nz on error */ +int calf_done(calf *x) { + int rv = 0; + + if (x->fp != NULL) { + if (fclose(x->fp)) { + a1logd(x->log,2,"calf_done: closing file failed\n"); + rv = 1; + } + } + + if (x->buf != NULL) + free(x->buf); + x->buf = NULL; + return rv; +} + +static void sizebuf(calf *x, size_t size) { + if (x->bufsz < size) + x->buf = realloc(x->buf, size); + if (x->buf == NULL) + error("calf: sizebuf malloc failed"); +} + +static void update_chsum(calf *x, unsigned char *p, int nn) { + int i; + for (i = 0; i < nn; i++, p++) + x->chsum = ((x->chsum << 13) | (x->chsum >> (32-13))) + *p; + x->nbytes += nn; +} + +/* Write an array of ints to the file. Set the error flag to nz on error */ +void calf_wints(calf *x, int *dp, int n) { + if (x->ef) + return; + + if (fwrite((void *)dp, sizeof(int), n, x->fp) != n) { + x->ef = 1; + a1logd(x->log,2,"calf_wints: write failed for %d ints at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char *)dp, sizeof(int) * n); + } +} + +/* Write an array of doubles to the file. Set the error flag to nz on error */ +void calf_wdoubles(calf *x, double *dp, int n) { + if (x->ef) + return; + + if (fwrite((void *)dp, sizeof(double), n, x->fp) != n) { + x->ef = 1; + a1logd(x->log,2,"calf_wdoubles: write failed for %d doubles at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char *)dp, sizeof(double) * n); + } +} + +/* Write an array of time_t's to the file. Set the error flag to nz on error */ +/* (This will cause file checksum fail if different executables on the same */ +/* system have different time_t values) */ +void calf_wtime_ts(calf *x, time_t *dp, int n) { + if (x->ef) + return; + + if (fwrite((void *)dp, sizeof(time_t), n, x->fp) != n) { + x->ef = 1; + a1logd(x->log,2,"calf_wtime_ts: write failed for %d time_ts at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char *)dp, sizeof(time_t) * n); + } +} + +/* Write a zero terminated string */ +void calf_wstrz(calf *x, char *dp) { + int n; + + if (x->ef) + return; + + n = strlen(dp) + 1; + + calf_wints(x, &n, 1); + + if (fwrite((void *)dp, sizeof(char), n, x->fp) != n) { + x->ef = 1; + a1logd(x->log,2,"calf_wstrz: write failed for %d long string at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char *)dp, sizeof(char) * n); + } +} + + +/* Read an array of ints from the file. Set the error flag to nz on error */ +/* Always read (ignore rd flag) */ +void calf_rints2(calf *x, int *dp, int n) { + if (x->ef) + return; + + if (fread((void *)dp, sizeof(int), n, x->fp) != n) { + x->ef = 1; + a1logd(x->log,2,"calf_rints2: read failed for %d ints at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char *)dp, sizeof(int) * n); + } +} + + +/* Read an array of ints from the file. Set the error flag to nz on error */ +void calf_rints(calf *x, int *dp, int n) { + size_t nbytes = n * sizeof(int); + void *dest = (void *)dp; + + if (x->ef) + return; + + if (x->rd == 0) { /* Dummy read */ + sizebuf(x, nbytes); + dest = x->buf; + } + + if (fread(dest, 1, nbytes, x->fp) != nbytes) { + x->ef = 1; + a1logd(x->log,2,"calf_rints: read failed for %d ints at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, dest, nbytes); + } +} + +/* Read an array of doubles from the file. Set the error flag to nz on error */ +void calf_rdoubles(calf *x, double *dp, int n) { + size_t nbytes = n * sizeof(double); + void *dest = (void *)dp; + + if (x->ef) + return; + + if (x->rd == 0) { /* Dummy read */ + sizebuf(x, nbytes); + dest = x->buf; + } + + if (fread(dest, 1, nbytes, x->fp) != nbytes) { + x->ef = 1; + a1logd(x->log,2,"calf_rdoubles: read failed for %d ints at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, dest, nbytes); + } +} + +/* Read an array of time_t's from the file. Set the error flag to nz on error */ +/* (This will cause file checksum fail if different executables on the same */ +/* system have different time_t values) */ +void calf_rtime_ts(calf *x, time_t *dp, int n) { + size_t nbytes = n * sizeof(time_t); + void *dest = (void *)dp; + + if (x->ef) + return; + + if (x->rd == 0) { /* Dummy read */ + sizebuf(x, nbytes); + dest = x->buf; + } + + if (fread(dest, 1, nbytes, x->fp) != nbytes) { + x->ef = 1; + a1logd(x->log,2,"calf_rtime_ts: read failed for %d ints at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, dest, nbytes); + } +} + +/* Read a zero terminated string. */ +void calf_rstrz(calf *x, char **dp) { + int n; + size_t nbytes = 0; + char *dest = NULL; + + if (x->ef) + return; + + calf_rints2(x, &n, 1); + nbytes = sizeof(char) * n; + + if (x->ef || n == 0) + return; + + if (x->rd != 0) { /* Reading for real */ + if (*dp != NULL) + free(*dp); + if ((*dp = dest = malloc(nbytes)) == NULL) + error("calf: calf_rstrz malloc failed"); + } else { + sizebuf(x, nbytes); + dest = x->buf; + } + if (fread(dest, 1, nbytes, x->fp) != nbytes) { + x->ef = 1; + a1logd(x->log,2,"calf_rstrz: read failed for %d long string at offset %d\n",n,x->nbytes); + } else { + update_chsum(x, (unsigned char*)dest, nbytes); + } +} + +void calf_rstrz2(calf *x, char **dp) { + int rd = x->rd; + x->rd = 1; + calf_rstrz(x, dp); + x->rd = rd; +} + +/* ================================================== */ + +/* Save a rspec to a calibration file */ +void calf_wrspec(calf *x, rspec *s) { + int i; + + if (x->ef) + return; + + calf_wints(x, (int *)&s->stype, 1); + calf_wints(x, (int *)&s->mtype, 1); + calf_wints(x, (int *)&s->state, 1); + calf_wdoubles(x, &s->inttime, 1); + calf_wints(x, &s->nmeas, 1); + calf_wints(x, &s->nsamp, 1); + + for (i = 0; i < s->nmeas; i++) { + calf_wdoubles(x, s->samp[i], s->nsamp); + } +} + +/* Create a rspec from a calibration file */ +void calf_rrspec(calf *x, rspec **dp, rspec_inf *inf) { + rspec *s, dumy; + int no, i; + + if (x->ef) + return; + + if (x->rd != 0) { + if (*dp != NULL) + del_rspec(*dp); + *dp = s = new_rspec(inf, rspec_sensor, 0); + } else { + s = &dumy; + } + + calf_rints2(x, (int *)&s->stype, 1); + calf_rints2(x, (int *)&s->mtype, 1); + calf_rints2(x, (int *)&s->state, 1); + calf_rdoubles(x, &s->inttime, 1); + calf_rints2(x, &s->nmeas, 1); + calf_rints2(x, &s->nsamp, 1); + + /* Sanity check. */ + no = rspec_typesize(inf, s->stype); + if (no != s->nsamp) { + a1logd(inf->log, 4,"calf_rrspec: unexpected nsamp %d (expect %d)\n",s->nsamp,no); + x->ef = 1; + return; + } + + if (x->rd != 0) { + s->samp = dmatrix(0, s->nmeas-1, 0, s->nsamp-1); + for (i = 0; i < s->nmeas; i++) { + calf_rdoubles(x, s->samp[i], s->nsamp); + } + } else { + for (i = 0; i < s->nmeas; i++) { + calf_rdoubles(x, NULL, s->nsamp); + } + } +} + diff --git a/spectro/rspec.h b/spectro/rspec.h new file mode 100755 index 0000000..bc5d427 --- /dev/null +++ b/spectro/rspec.h @@ -0,0 +1,265 @@ +#ifndef RSPEC_H + +/* + * Argyll Color Correction System + * + * Author: Graeme W. Gill + * Date: 20015 + * + * Copyright 2006 - 2015 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 i1pro_imp.c & munki_imp.c + */ + +/* + * A library for processing raw spectrometer values. + * + * Currently this is setup for the EX1 spectrometer, + * but the longer term plan is to expand the functionality + * so that it becomes more generic, and can replace a lot + * of common code in i1pro_imp.c & munki_imp.c. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +#define RSPEC_MAXSAMP 2048 + +/* - - - - - - - - - - - - - */ +/* Collection of raw samples */ +typedef enum { + rspec_sensor, /* Includes shielded/temperaturee values */ + rspec_raw, /* Potential light values */ + rspec_wav /* Valid wavelength values */ +} rspec_type; + +/* The order the state is changed in is device workflow dependent */ +typedef enum { + rspec_none = 0x0000, /* No processing */ + rspec_shld = 0x0002, /* Shielded cell corrected */ + rspec_dcal = 0x0004, /* Dark calibration subtracted */ + rspec_lin = 0x0010, /* Linearized */ + rspec_int = 0x0020, /* Integration time adjusted */ + rspec_temp = 0x0001, /* Temperature corrected */ + rspec_cal = 0x0040 /* Calibrated */ +} rspec_state; + +struct _rspec { + struct _rspec_inf *inf; /* Base information */ + + rspec_type stype; /* Spectral type - sensor, raw, cooked */ + inst_meas_type mtype; /* Measurement type (emis, ambient, reflective etc.) */ + rspec_state state; /* Processing state */ + + double inttime; /* Integration time */ + + int nmeas; /* Number of measurements */ + int nsamp; /* Number of sensor/wavelength samples */ + double **samp; /* [mesa][samples] allocated using numlib. */ + +}; typedef struct _rspec rspec; + + +/* - - - - - - - - - - - - - */ +/* Base information about characteristics in a given mode */ + +/* Wavelength resample kernel type */ +typedef enum { + rspec_triangle, + rspec_gausian, + rspec_lanczos2, + rspec_lanczos3, + rspec_cubicspline +} rspec_kernel; + +/* Group of values */ +typedef struct { + int off; /* Offset to start of group */ + int num; /* Number in group */ +} rspec_group; + +struct _rspec_inf { + a1log *log; + + int nsen; /* Number of sensor values */ + int nshgrps; /* Number of shielded sensor groups */ + rspec_group shgrps[2]; /* Shielded group definition */ + + int nilltkgrps; /* Number of illuminant level tracking groups */ + rspec_group illtkgrps[2]; /* illuminant level tracking groups definition */ + + rspec_group lightrange; /* Range of sensor potential light values transferred to raw */ + + int nraw; /* Number of raw light sensor values */ + rspec_group rawrange; /* Valid range of raw values for filter to wav */ + + rspec_kernel ktype; /* Re-sampling kernel type */ + int nwav; /* Cooked spectrum bands */ + double wl_space; /* Wavelength spacing */ + double wl_short; /* Cooked spectrum bands short wavelength nm */ + double wl_long; /* Cooked spectrum bands short wavelength nm */ + + + /* (Stray light is not currently implemented) */ + rspec_type straytype; /* Stray light spectral type - sensor, raw, cooked */ + double **straylight; /* [][] Stray light convolution matrix (size ??) */ + + /* raw index to wavelength polynomial */ + unsigned int nwlcal; /* Number in array */ + double *wlcal; /* Array of wavelenght cal polinomial factors. */ + + /* raw index to wavelength re-sampling filters */ + int *findex; /* [nwav] raw starting index for each out wavelength */ + int *fnocoef; /* [nwav] Number of matrix cooeficients for each out wavelength */ + double *fcoef; /* [nwav * nocoef] Packed cooeficients to compute each wavelength */ + + unsigned int nlin; /* Number in array */ + double *lin; /* Array of linearisation polinomial factors. */ + int lindiv; /* nz if polinomial result should be divided */ + + /* Black calibration */ + rspec *idark[2]; /* Adaptive dark cal for two integration times */ + + /* Emission calibration */ + rspec_type ecaltype; /* Emissioni calibration type - sensor, raw, cooked */ + double *ecal; /* Emission calibration values */ + +}; typedef struct _rspec_inf rspec_inf; + +/* - - - - - - - - - - - - - */ + +/* Completely clear an rspec_inf. */ +void clear_rspec_inf(rspec_inf *inf); + +/* Completely free contesnt of rspec_inf. */ +void free_rspec_inf(rspec_inf *inf); + +/* return the number of samples for the given spectral type */ +int rspec_typesize(rspec_inf *inf, rspec_type ty); + +/* Compute the valid raw range from the calibration information */ +void rspec_comp_raw_range_from_ecal(rspec_inf *inf); + +/* Convert a raw index to nm */ +double rspec_raw2nm(rspec_inf *inf, double rix); + +/* Convert a cooked index to nm */ +double rspec_wav2nm(rspec_inf *inf, double ix); + +/* Create the wavelength resampling filters */ +void rspec_make_resample_filters(rspec_inf *inf); + + +/* Plot the first rspec */ +void plot_rspec1(rspec *p); + +/* Plot the first rspec of 2 */ +void plot_rspec2(rspec *p1, rspec *p2); + +/* Plot the wave resampling filters */ +void plot_resample_filters(rspec_inf *inf); + +/* Plot the calibration curves */ +void plot_ecal(rspec_inf *inf); + +/* - - - - - - - - - - - - - */ + +/* Create a new rspec from scratch */ +/* This always succeeds (i.e. application bombs if malloc fails) */ +rspec *new_rspec(rspec_inf *inf, rspec_type ty, int nmeas); + +/* Create a new rspec based on an existing prototype */ +/* If nmes == 0, create space for the same number or measurements */ +rspec *new_rspec_proto(rspec *rs, int nmeas); + +/* Create a new rspec by cloning an existing one */ +rspec *new_rspec_clone(rspec *rs); + +/* Free a rspec */ +void del_rspec(rspec *rs); + +/* - - - - - - - - - - - - - */ +/* Return the largest value */ +double largest_val_rspec(int *pmix, int *psix, rspec *raw); + +/* return a raw rspec from a sensor rspec */ +rspec *extract_raw_from_sensor_rspec(rspec *sens); + +/* Return an interpolated dark reference value from idark */ +double ex1_interp_idark_val(rspec_inf *inf, int mix, int six, double inttime); + +/* Return an interpolated dark reference from idark */ +rspec *ex1_interp_idark(rspec_inf *inf, double inttime); + +/* Subtract the adaptive black */ +void subtract_idark_rspec(rspec *raw); + +/* Apply non-linearity to a single value */ +double linearize_val_rspec(rspec_inf *inf, double ival); + +/* Invert non-linearity of a single value */ +double inv_linearize_val_rspec(rspec_inf *inf, double targv); + +/* Correct non-linearity */ +void linearize_rspec(rspec *raw); + +/* Apply the emsissive calibration */ +void emis_calibrate_rspec(rspec *sens); + +/* Scale to the integration time */ +void inttime_calibrate_rspec(rspec *sens); + +/* return a wav rspec from a raw rspec */ +rspec *convert_wav_from_raw_rspec(rspec *sens); + + +/* - - - - - - - - - - - - - */ +/* Calibration file support */ + +typedef struct { + a1log *log; + int lo_secs; /* Seconds since last opened (from file mod time) */ + FILE *fp; + int rd; /* 0 = dummy read, 1 = real read */ + int ef; /* Error flag, 1 = write failed, 2 = close failed */ + unsigned int chsum; /* Checksum */ + int nbytes; /* Number of bytes checksummed */ + + char *buf; /* Dummy read buffer */ + size_t bufsz; /* Size of dumy read buffer */ +} calf; + +int calf_open(calf *x, a1log *log, char *fname, int wr); +void calf_rewind(calf *x); +int calf_touch(a1log *log, char *fname); +int calf_done(calf *x); + +void calf_wints(calf *x, int *dp, int n); +void calf_wdoubles(calf *x, double *dp, int n); +void calf_wtime_ts(calf *x, time_t *dp, int n); +void calf_wstrz(calf *x, char *dp); + +void calf_rints(calf *x, int *dp, int n); +void calf_rints2(calf *x, int *dp, int n); +void calf_rdoubles(calf *x, double *dp, int n); +void calf_rtime_ts(calf *x, time_t *dp, int n); +void calf_rstrz(calf *x, char **dp); +void calf_rstrz2(calf *x, char **dp); + +/* Save a rspec to a calibration file */ +void calf_wrspec(calf *x, rspec *dp); + +/* Restore a rspec from a calibration file */ +void calf_rrspec(calf *x, rspec **dp, rspec_inf *inf); + +#ifdef __cplusplus + } +#endif + +#define RSPEC_H +#endif /* RSPEC_H */ diff --git a/spectro/smcube.c b/spectro/smcube.c new file mode 100755 index 0000000..1618447 --- /dev/null +++ b/spectro/smcube.c @@ -0,0 +1,2187 @@ + +/* + * Argyll Color Correction System + * + * SwatchMate Cube related functions + * + * Author: Graeme W. Gill + * Date: 18/5/2015 + * + * Copyright 1996 - 2015, 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. + * + * Based on specbos.c + */ + +/* + If you make use of the instrument driver code here, please note + that it is the author(s) of the code who take responsibility + for its operation. Any problems or queries regarding driving + instruments with the Argyll drivers, should be directed to + the Argyll's author(s), and not to any other party. + + If there is some instrument feature or function that you + would like supported here, it is recommended that you + contact Argyll's author(s) first, rather than attempt to + modify the software yourself, if you don't have firm knowledge + of the instrument communicate protocols. There is a chance + that an instrument could be damaged by an incautious command + sequence, and the instrument companies generally cannot and + will not support developers that they have not qualified + and agreed to support. + */ + +/* + + TTBD: + + Need inst call to clear optional user calibrations - + add capability, then option to check if set, and + option to clear. + + + Investigate clash between button triggered and progromatic. + Need to check why calibration times out ?? + + Need to make startup more robust - often fails to find instrument ? + Need to cleanup shutdown (^C) ? + + Like to test on OS X and Linux. + - hard to do this, as FT231XS driver support is only recent. + + Like to add BlueTooth LE to MSWin/OS X/Linux. + - hard to do this, as BTLE support is only recent. + +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <time.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 */ +#include "xspect.h" +#include "insttypes.h" +#include "conv.h" +#include "icoms.h" +#include "inst.h" +#include "rspec.h" +#include "smcube.h" +#include "cubecal.h" /* Calibration */ + +#undef USEW /* [Und] Use white sensor rather than R,G,B */ + +#define ENABLE_NONVCAL /* [Def] Enable saving calibration state between program runs in a file */ + +#define WCALTOUT (1 * 60 * 60) /* [1 Hour ??] White Calibration timeout in seconds */ + +#define DEFTO 1.0 /* [1.0] Default command timeout */ + +/* Cube white reference RGB reflectivity as measured by cube */ +//static double cwref[3] = { 0.646601, 0.668981, 0.703421 }; +static double cwref[3] = { 0.795893, 0.818593, 0.855143 }; + +/* Assumed 45/0 RGB reflectance of gloss black reference */ +static double glref[3] = { 0.012632, 0.009568, 0.010130 }; + +/* Default black offset if not calibrated with a light trap */ +static double dsoff[3] = { 0.059465, 0.063213, 0.069603 }; + +/* Default gloss offset if not calibrated with a gloss reference */ +static double dgoff[3] = { 0.056007, 0.052993, 0.054589 }; + +/* Assumed temperature coefficients for sensor output */ +static double tempc[3] = { 0.0048, 0.0017, 0.0014 }; + +/* ------------------------------------------------- */ + +static inst_code smcube_interp_code(inst *pp, int ec); +static inst_code smcube_poll_measure(smcube *p, double to, int nd); +static inst_code smcube_black_calib(smcube *p, int ctype); +static inst_code smcube_get_temp(smcube *p, double *tval); +static inst_code smcube_get_cal_temp(smcube *p, int addr, double *tval); + +#define MAX_MES_SIZE 500 /* Maximum normal message reply size */ + +/* Interpret an icoms error into a SMCUBE error */ +static int icoms2smcube_err(int se) { + if (se != ICOM_OK) { + if (se & ICOM_TO) + return SMCUBE_TIMEOUT; + return SMCUBE_COMS_FAIL; + } + return SMCUBE_OK; +} + +/* Commands */ +static inst_code smcube_ping(smcube *p); +static inst_code smcube_get_version(smcube *p, int *val); +static inst_code smcube_get_idle_time(smcube *p, int *pitime, int nd); +static inst_code smcube_fact_measure(smcube *p, double *XYZ); +static inst_code smcube_get_cal_val(smcube *p, int addr, double *cval); +static inst_code smcube_fact_white_calib(smcube *p); +static inst_code smcube_meas_wrgb(smcube *p, int ichan, int *wrgb); + + +static inst_code smcube_white(smcube *p, int ctype); +static inst_code smcube_measure(smcube *p, double *XYZ); + +static void cube_rgb2XYZ(double *xyz, double *irgb); + +/* Do a full command/response echange with the smcube */ +/* (This level is not multi-thread safe) */ +/* Return the smcube error code. */ +static int +smcube_fcommand( +struct _smcube *p, +unsigned char *in, /* Command string */ +int ilen, /* Number of bytes to send */ +unsigned char *out, /* Reply string buffer */ +int olen, /* Number of bytes expected in reply (buffer expected to be MAX_MES_SIZE) */ +double to, /* Timeout for response in seconds */ +int nd /* nz to disable debug messages */ +) { + int se; + + if (!nd) a1logd(p->log, 4, "smcube_fcommand: command '%s'\n", icoms_tohex(in,ilen)); + if ((se = p->icom->write(p->icom, (char *)in, ilen, 0.2)) != 0) { + if (!nd) a1logd(p->log, 1, "smcube_fcommand: failure on serial write '%s' 0x%x\n", + icoms_tohex(in,ilen),se); + return icoms2smcube_err(se); + } + + /* Now wait for a reply */ + if ((se = p->icom->read(p->icom, (char *)out, MAX_MES_SIZE, NULL, NULL, olen, to)) != 0) { + if (!nd) a1logd(p->log, 1, "smcube_fcommand: failure on serial 0x%x\n",se); + return icoms2smcube_err(se); + } + if (!nd) a1logd(p->log, 4, "smcube_fcommand: returned '%s' err 0x%x\n", + icoms_tohex(out,olen), se); + return se; +} + +/* Do a normal command/response echange with the smcube. */ +/* (This level is not multi-thread safe) */ +/* Return the inst code */ +static inst_code +smcube_command( +struct _smcube *p, +unsigned char *in, /* Command string */ +int ilen, /* Number of bytes to send */ +unsigned char *out, /* Reply string buffer */ +int olen, /* Number of bytes expected in reply (buffer expected to be MAX_MES_SIZE) */ +double to) { /* Timout in seconds */ + int rv = smcube_fcommand(p, in, ilen, out, olen, to, 0); + return smcube_interp_code((inst *)p, rv); +} + +/* Establish communications with a smcube */ +/* Return SMCUBE_COMS_FAIL on failure to establish communications */ +static inst_code +smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { + smcube *p = (smcube *) pp; + unsigned char buf[MAX_MES_SIZE]; + baud_rate brt[] = { baud_38400, baud_nc }; + unsigned int etime; + unsigned int i; + instType itype = pp->itype; + int se; + + inst_code ev = inst_ok; + + 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"); + return inst_coms_fail; + } + + if (p->bt) { + amutex_lock(p->lock); + + /* Check instrument is responding */ + 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_ok) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "smcube_init_coms: ping didn't return\n"); + return ev; + } + if (buf[0] != 0x7e || buf[1] != 0x20 || buf[2] != 0x02 || buf[3] != 0x00) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "smcube_init_coms: ping reply is wrong\n"); + return inst_unknown_model; + } + amutex_unlock(p->lock); + + } else { + + amutex_lock(p->lock); + + /* The tick to give up on */ + etime = msec_time() + (long)(1500.0 + 0.5); + + a1logd(p->log, 1, "smcube_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 = 0; msec_time() < etime; i++) { + if (brt[i] == baud_nc) { + i = 0; + } + a1logd(p->log, 5, "smcube_init_coms: trying %s baud\n",baud_rate_to_str(brt[i])); + 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); + a1logd(p->log, 5, "smcube_init_coms: set_ser_port failed with 0x%x\n",se); + return smcube_interp_code((inst *)p, icoms2smcube_err(se));; /* Give up */ + } + + /* Check instrument is responding */ + 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 */ + } + + /* 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, "smcube_init_coms: user aborted\n"); + return inst_user_abort; + } + } + } + + 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; + } + + /* Check the response */ + if (buf[0] != 0x7e || buf[1] != 0x20 || buf[2] != 0x02 || buf[3] != 0x00) { + amutex_unlock(p->lock); + a1logd(p->log, 2, "smcube_init_coms: ping didn't return\n"); + return inst_unknown_model; + } + amutex_unlock(p->lock); + } + a1logd(p->log, 2, "smcube_init_coms: init coms has suceeded\n"); + + p->gotcoms = 1; + + return inst_ok; +} + +/* Get idle time loop and user measurement detect */ +/* Poll the instrument at 500msec intervals */ +int smcube_mon_thread(void *pp) { + int nfailed = 0; + smcube *p = (smcube *)pp; + inst_code rv1 = inst_ok; + a1logd(p->log,3,"Polling thread started\n"); + /* Try indefinitely, in case instrument is put to sleep */ + for (;;) { + int itime; + + /* See if there is a button generated measure */ + rv1 = smcube_poll_measure(p, 0.1, 1); + if ((rv1 & inst_mask) == inst_user_trig) { + a1logd(p->log,3,"Found user trigger\n"); + p->switch_count++; + if (!p->hide_switch && p->eventcallback != NULL) { + p->eventcallback(p->event_cntx, inst_event_switch); + } + } + + /* Presumably this stops it going to sleep */ + rv1 = smcube_get_idle_time(p, &itime, 1); + + if (p->th_term) { + p->th_termed = 1; + break; + } + if (rv1 != inst_ok) { + nfailed++; + a1logd(p->log,3,"Monitor thread failed with 0x%x\n",rv1); + continue; + } + msec_sleep(500); + } + a1logd(p->log,3,"Monitor thread returning\n"); + return rv1; +} + +/* Try and read the user measurement, and then trigger measure here. */ +int smcube_utrig_thread(void *pp) { + smcube *p = (smcube *)pp; + inst_code rv = inst_ok; + + /* Give caller a chance to return */ + msec_sleep(50); + + /* See if there is a button generated measure */ + rv = smcube_poll_measure(p, 0.1, 1); + if ((rv & inst_mask) == inst_user_trig) { + p->switch_count++; + if (!p->hide_switch && p->eventcallback != NULL) { + a1logd(p->log,3,"Found user trigger\n"); + p->eventcallback(p->event_cntx, inst_event_switch); + } + } + return 0; +} + +/* icoms interrupt callback - used did measurement ? */ +int smcube_interrupt(icoms *icom, int icom_int) { + smcube *p = (smcube *)icom->icntx; /* Fetch the instrument context */ + inst_code rv = inst_ok; + + a1logd(p->log,3,"smcube_interrupt called with %d\n",icom_int); + + if (icom_int != icomi_data_available) + return ICOM_OK; + + /* See if there is a measurement */ + new_athread(smcube_utrig_thread, (void *)p); + + return 0; +} + + +/* Initialise the SMCUBE */ +/* return non-zero on an error, with dtp error code */ +static inst_code +smcube_init_inst(inst *pp) { + smcube *p = (smcube *)pp; + char mes[100]; + inst_code ev = inst_ok; + int ver; + + a1logd(p->log, 2, "smcube_init_inst: called\n"); + + if (p->gotcoms == 0) + return inst_internal_error; /* Must establish coms before calling init */ + +#ifdef NEVER + if ((ev = smcube_get_version(p, &p->version)) != inst_ok) { + return SMCUBE_UNKNOWN_MODEL; + } +#endif + + amutex_lock(p->lock); + + if (p->log->verb) { + /* Hmm. There is nothing to report */ + } + + if (!p->bt) { + /* Start the polling loop thread */ + if ((p->th = new_athread(smcube_mon_thread, (void *)p)) == NULL) { + amutex_unlock(p->lock); + return SMCUBE_INT_THREADFAILED; + } + } else { + /* Get called back if data becomes available */ + p->icom->interrupt = smcube_interrupt; + } + + p->lo_secs = 2000000000; /* A very long time */ + +#ifdef ENABLE_NONVCAL + /* Restore idarl calibration from the local system */ + smcube_restore_calibration(p); + /* Touch it so that we know when the instrument was last opened */ + smcube_touch_calibration(p); +#endif + + p->inited = 1; + a1logd(p->log, 2, "smcube_init_inst: instrument inited OK\n"); + amutex_unlock(p->lock); + + if (p->log->verb) { + a1logv(p->log, 1, " Version: %d\n",p->version); + } + +#ifdef NEVER + /* Debug - dump the calibration */ + smcube_dump_cal(p); +#endif + + + return inst_ok; +} + +/* Read a single sample */ +/* Return the dtp error code */ +static inst_code +smcube_read_sample( +inst *pp, +char *name, /* Strip name (7 chars) */ +ipatch *val, /* Pointer to instrument patch value */ +instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ + smcube *p = (smcube *)pp; + int ec; + int switch_trig = 0; + int user_trig = 0; + inst_code rv = inst_protocol_error; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + /* Signal a calibration is needed */ + if (p->want_wcalib && !p->noinitcalib) { + return inst_needs_cal; /* Get user to calibrate */ + } + + if (p->trig == inst_opt_trig_user_switch) { + int currcount = p->switch_count; /* Variable set by thread */ + + p->hide_switch = 1; /* Supress switch events */ + + currcount = p->switch_count; /* Variable set by thread */ + while (currcount == p->switch_count) { + int cerr; + + /* Don't trigger on user key if scan, only trigger */ + /* on instrument switch */ + if (p->uicallback != NULL + && (rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) { + if (rv == inst_user_abort) { + return rv; /* Abort */ + } + if (rv == inst_user_trig) { + user_trig = 1; + break; /* Trigger */ + } + } + msec_sleep(100); + } + if (currcount != p->switch_count) + switch_trig = 1; + + a1logd(p->log,3,"############# triggered ##############\n"); + if (p->uicallback) /* Notify of trigger */ + p->uicallback(p->uic_cntx, inst_triggered); + + p->hide_switch = 0; /* Enable switch events again */ + + } else if (p->trig == inst_opt_trig_user) { + + if (p->uicallback == NULL) { + a1logd(p->log, 1, "smcube: inst_opt_trig_user but no uicallback function set!\n"); + return inst_unsupported; + } + + for (;;) { + if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) { + if (rv == inst_user_abort) { + return rv; /* Abort */ + } + if (rv == inst_user_trig) { + user_trig = 1; + break; /* Trigger */ + } + } + msec_sleep(200); + } + /* Notify of trigger */ + if (p->uicallback) + p->uicallback(p->uic_cntx, inst_triggered); + + /* Progromatic Trigger */ + } else { + /* Check for abort */ + if (p->uicallback != NULL + && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) { + return rv; /* Abort */ + } + } + + + /* Take a measurement */ + if (p->icx < 2) { /* Argyll calibrated measurement */ + + rv = smcube_measure(p, val->XYZ); + + /* Original factory measurement */ + } else { + if (switch_trig) { + icmCpy3(val->XYZ, p->XYZ); + rv = inst_ok; + + } else { + rv = smcube_fact_measure(p, val->XYZ); + } + } + + + if (rv != inst_ok) { + return rv; + } + + /* This may not change anything since instrument may clamp */ + if (clamp) + icmClamp3(val->XYZ, val->XYZ); + val->loc[0] = '\000'; + + val->mtype = inst_mrt_reflective; + val->XYZ_v = 1; /* These are absolute XYZ readings */ + + val->sp.spec_n = 0; + val->duration = 0.0; + rv = inst_ok; + + + + if (user_trig) + return inst_user_trig; + return rv; +} + +/* Return needed and available inst_cal_type's */ +static inst_code smcube_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) { + smcube *p = (smcube *)pp; + time_t curtime = time(NULL); + inst_cal_type n_cals = inst_calt_none; + inst_cal_type a_cals = inst_calt_none; + int white_valid = p->white_valid; + + if ((curtime - p->wdate) > WCALTOUT) { + a1logd(p->log,2,"Invalidating white cal as %d secs from last cal\n",curtime - p->wdate); + white_valid = 0; + } + + if (!white_valid + || (p->want_wcalib && !p->noinitcalib)) + n_cals |= inst_calt_ref_white; + + a_cals |= inst_calt_ref_white; + a_cals |= inst_calt_ref_dark; + + /* Gloss calibration if in gloss calibrated mode */ + if (p->icx == 1) + a_cals |= inst_calt_ref_dark_gl; + + if (pn_cals != NULL) + *pn_cals = n_cals; + + if (pa_cals != NULL) + *pa_cals = a_cals; + + a1logd(p->log,3,"smcube: returning n_cals 0x%x, a_cals 0x%x\n",n_cals, a_cals); + + if (pn_cals != NULL) + *pn_cals = n_cals; + + if (pa_cals != NULL) + *pa_cals = a_cals; + + return inst_ok; +} + +/* Request an instrument calibration. */ +inst_code smcube_calibrate( +inst *pp, +inst_cal_type *calt, /* Calibration type to do/remaining */ +inst_cal_cond *calc, /* Current condition/desired condition */ +char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ +) { + smcube *p = (smcube *)pp; + inst_cal_type needed, available; + int dosave = 0; + inst_code ev = inst_ok; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + id[0] = '\000'; + + if ((ev = smcube_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok) + return ev; + + /* Translate inst_calt_all/needed into something specific */ + if (*calt == inst_calt_all + || *calt == inst_calt_needed + || *calt == inst_calt_available) { + if (*calt == inst_calt_all) + *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag; + else if (*calt == inst_calt_needed) + *calt = needed & inst_calt_n_dfrble_mask; + else if (*calt == inst_calt_available) + *calt = available & inst_calt_n_dfrble_mask; + + a1logd(p->log,4,"smcube_calibrate: doing calt 0x%x\n",calt); + + if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */ + return inst_ok; + } + + /* See if it's a calibration we understand */ + if (*calt & ~available & inst_calt_all_mask) { + return inst_unsupported; + } + + if (*calt & inst_calt_ref_white) { /* White calibration */ + time_t cdate = time(NULL); + + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) { + *calc = inst_calc_man_ref_white; + ev = inst_cal_setup; + goto done; + } + + if ((ev = smcube_fact_white_calib(p)) != inst_ok) { + goto done; + } + + p->white_valid = 1; + p->want_wcalib = 0; + p->wdate = cdate; + *calt &= ~inst_calt_ref_white; + dosave = 1; + } + + /* Light trap calibration: */ + + /* Is the user skipping the Light trap calibration ? */ + if (*calt & inst_calt_ref_dark + && (*calc & inst_calc_cond_mask) == inst_calc_man_ref_dark + && *calc & inst_calc_optional_flag) { + *calt &= ~inst_calt_ref_dark; + } + + if (*calt & inst_calt_ref_dark) { + time_t cdate = time(NULL); + + if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_dark) { + *calc = inst_calc_man_ref_dark | inst_calc_optional_flag; + ev = inst_cal_setup; + goto done; + } + + if ((ev = smcube_black_calib(p, 0)) != inst_ok) { + goto done; + } + + p->dark_valid = 1; + p->dark_default = 0; + p->ddate = cdate; + *calt &= ~inst_calt_ref_dark; + dosave = 1; + } + + /* Gloss black calibration */ + + /* Is the user skipping the Gloss calibration ? */ + if (*calt & inst_calt_ref_dark_gl + && (*calc & inst_calc_cond_mask) == inst_calc_man_dark_gloss + && *calc & inst_calc_optional_flag) { + *calt &= ~inst_calt_ref_dark_gl; + } + + if (*calt & inst_calt_ref_dark_gl) { + time_t cdate = time(NULL); + + if ((*calc & inst_calc_cond_mask) != inst_calc_man_dark_gloss) { + *calc = inst_calc_man_dark_gloss | inst_calc_optional_flag; + ev = inst_cal_setup; + goto done; + } + + if ((ev = smcube_black_calib(p, 1)) != inst_ok) { + goto done; + } + + p->gloss_valid = 1; + p->gloss_default = 0; + p->gdate = cdate; + *calt &= ~inst_calt_ref_dark_gl; + dosave = 1; + } + + done:; + +#ifdef ENABLE_NONVCAL + if (dosave) { + /* Save the idark calibration to a file */ + smcube_save_calibration(p); + } +#endif + + return ev; +} + +/* Error codes interpretation */ +static char * +smcube_interp_error(inst *pp, int ec) { +// smcube *p = (smcube *)pp; + ec &= inst_imask; + switch (ec) { + case SMCUBE_INTERNAL_ERROR: + return "Internal software error"; + case SMCUBE_TIMEOUT: + return "Communications timeout"; + case SMCUBE_COMS_FAIL: + return "Communications failure"; + case SMCUBE_UNKNOWN_MODEL: + return "Not a SwatchMate Cube"; + case SMCUBE_DATA_PARSE_ERROR: + return "Data from smcube didn't parse as expected"; + + case SMCUBE_OK: + return "No device error"; + + case SMCUBE_INT_THREADFAILED: + return "Starting diffuser position thread failed"; + case SMCUBE_INT_ILL_WRITE: + return "Attemp to write to factory calibration"; + case SMCUBE_INT_WHITE_CALIB: + return "No valid white calibration"; + case SMCUBE_INT_BLACK_CALIB: + return "No valid black calibration"; + case SMCUBE_INT_GLOSS_CALIB: + return "No valid gloss calibration"; + case SMCUBE_INT_CAL_SAVE: + return "Saving calibration file failed"; + case SMCUBE_INT_CAL_RESTORE: + return "Restoring calibration file failed"; + case SMCUBE_INT_CAL_TOUCH: + return "Touching calibration file failed"; + + case SMCUBE_WHITE_CALIB_ERR: + return "White calibration is outside expected range"; + case SMCUBE_BLACK_CALIB_ERR: + return "Black calibration is outside expected range"; + case SMCUBE_GLOSS_CALIB_ERR: + return "Gloss calibration is outside expected range"; + + default: + return "Unknown error code"; + } +} + + +/* Convert a machine specific error code into an abstract dtp code */ +static inst_code +smcube_interp_code(inst *pp, int ec) { + + ec &= inst_imask; + switch (ec) { + + case SMCUBE_OK: + return inst_ok; + + case SMCUBE_INTERNAL_ERROR: + case SMCUBE_INT_THREADFAILED: + case SMCUBE_INT_ILL_WRITE: + case SMCUBE_INT_WHITE_CALIB: + case SMCUBE_INT_BLACK_CALIB: + case SMCUBE_INT_GLOSS_CALIB: + case SMCUBE_INT_CAL_SAVE: + case SMCUBE_INT_CAL_RESTORE: + case SMCUBE_INT_CAL_TOUCH: + return inst_internal_error | ec; + + case SMCUBE_TIMEOUT: + case SMCUBE_COMS_FAIL: + return inst_coms_fail | ec; + +// return inst_unknown_model | ec; + + case SMCUBE_DATA_PARSE_ERROR: + return inst_protocol_error | ec; + +// return inst_wrong_config | ec; + +// return inst_bad_parameter | ec; + + case SMCUBE_WHITE_CALIB_ERR: + case SMCUBE_BLACK_CALIB_ERR: + case SMCUBE_GLOSS_CALIB_ERR: + return inst_misread | ec; + +// return inst_hardware_fail | ec; + } + return inst_other_error | ec; +} + +/* Destroy ourselves */ +static void +smcube_del(inst *pp) { + if (pp != NULL) { + smcube *p = (smcube *)pp; + +#ifdef ENABLE_NONVCAL + smcube_touch_calibration(p); +#endif + + if (p->th != NULL) { /* Terminate diffuser monitor thread */ + int i; + p->th_term = 1; /* Tell thread to exit on error */ + for (i = 0; p->th_termed == 0 && i < 5; i++) + msec_sleep(100); /* Wait for thread to terminate */ + if (i >= 5) { + a1logd(p->log,3,"smcube diffuser thread termination failed\n"); + } + p->th->del(p->th); + } + if (p->icom != NULL) + p->icom->del(p->icom); + amutex_del(p->lock); + free(p); + } +} + +/* Return the instrument mode capabilities */ +static void smcube_capabilities(inst *pp, +inst_mode *pcap1, +inst2_capability *pcap2, +inst3_capability *pcap3) { + smcube *p = (smcube *)pp; + inst_mode cap1 = 0; + inst2_capability cap2 = 0; + + cap1 |= inst_mode_ref_spot + | inst_mode_colorimeter + ; + + /* can inst2_has_sensmode, but not report it asynchronously */ + cap2 |= inst2_prog_trig + | inst2_user_trig + | inst2_user_switch_trig + | inst2_disptype /* Calibration modes */ + | inst2_opt_calibs /* Has optional calibrations that can be cleared */ + ; + + if (pcap1 != NULL) + *pcap1 = cap1; + if (pcap2 != NULL) + *pcap2 = cap2; + if (pcap3 != NULL) + *pcap3 = inst3_none; +} + + +/* Check device measurement mode */ +static inst_code smcube_check_mode(inst *pp, inst_mode m) { + inst_mode cap; + + if (!pp->gotcoms) + return inst_no_coms; + if (!pp->inited) + return inst_no_init; + + pp->capabilities(pp, &cap, NULL, NULL); + + /* Simple test */ + if (m & ~cap) + return inst_unsupported; + + /* General check mode against specific capabilities logic: */ + if (!IMODETST(m, inst_mode_ref_spot)) { + return inst_unsupported; + } + + return inst_ok; +} + +/* Set device measurement mode */ +static inst_code smcube_set_mode(inst *pp, inst_mode m) { + smcube *p = (smcube *)pp; + int refrmode; + inst_code ev; + + if ((ev = smcube_check_mode(pp, m)) != inst_ok) + return ev; + + p->mode = m; + + return inst_ok; +} + +/* Calibration modes */ +static inst_disptypesel smcube_disptypesel[4] = { + { + inst_dtflags_default, /* flags */ + 0, /* cbix */ + "m", /* sel */ + "Matte", /* desc */ + 0, /* refr */ + disptech_none, /* disptype */ + 0 /* ix */ + }, + { + inst_dtflags_none, /* flags */ + 0, /* cbix */ + "g", /* sel */ + "Gloss", /* desc */ + 0, /* refr */ + disptech_none, /* disptype */ + 1 /* ix */ + }, + { + inst_dtflags_none, /* flags */ + 0, /* cbix */ + "N", /* sel */ + "Native Calibration", /* desc */ + 0, /* refr */ + disptech_none, /* disptype */ + 2 /* ix */ + }, + { + inst_dtflags_end, + 0, + "", + "", + 0, + disptech_none, + 0 + } +}; + +/* Get mode and option details */ +static inst_code smcube_get_disptypesel( +inst *pp, +int *pnsels, /* Return number of display types */ +inst_disptypesel **psels, /* Return the array of display types */ +int allconfig, /* nz to return list for all configs, not just current. */ +int recreate /* nz to re-check for new ccmx & ccss files */ +) { + smcube *p = (smcube *)pp; + inst_code rv = inst_ok; + + if (pnsels != NULL) + *pnsels = 3; + + if (psels != NULL) + *psels = smcube_disptypesel; + + return inst_ok; +} + +/* Given a display type entry, setup for that type */ +static inst_code set_disp_type(smcube *p, inst_disptypesel *dentry) { + inst_code rv; + int refrmode; + + p->icx = dentry->ix; + p->dtech = dentry->dtech; + + return inst_ok; +} + +/* Set the display type - refresh or not */ +static inst_code smcube_set_disptype(inst *pp, int ix) { + smcube *p = (smcube *)pp; + inst_code ev; + inst_disptypesel *dentry; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if (ix < 0 || ix > 2) + return inst_unsupported; + + a1logd(p->log,5,"smcube smcube_set_disptype ix %d\n",ix); + dentry = &smcube_disptypesel[ix]; + + if ((ev = set_disp_type(p, dentry)) != inst_ok) { + return ev; + } + + return inst_ok; +} + +/* Set the noinitcalib mode */ +static void smcube_set_noinitcalib(smcube *p, int v, int losecs) { + + /* Ignore disabling init calib if more than losecs since instrument was open */ + if (v && losecs != 0 && p->lo_secs >= losecs) { + a1logd(p->log,3,"initcalib disable ignored because %d >= %d secs\n",p->lo_secs,losecs); + return; + } + p->noinitcalib = v; +} + +static void set_optcalibs_default(smcube *p) { + /* Default black offset */ + p->soff[0] = dsoff[0]; + p->soff[1] = dsoff[1]; + p->soff[2] = dsoff[2]; + p->dark_valid = 1; + p->dark_default = 1; + + /* Default gloss offset */ + p->goff[0] = dgoff[0]; + p->goff[1] = dgoff[1]; + p->goff[2] = dgoff[2]; + p->gloss_valid = 1; + p->gloss_default = 1; +} + +/* + * set or reset an optional mode + * + * Some options talk to the instrument, and these will + * error if it hasn't been initialised. + */ +static inst_code +smcube_get_set_opt(inst *pp, inst_opt_type m, ...) +{ + smcube *p = (smcube *)pp; + inst_code ev = inst_ok; + + a1logd(p->log, 5, "smcube_get_set_opt: opt type 0x%x\n",m); + + if (m == inst_opt_initcalib) { /* default */ + smcube_set_noinitcalib(p, 0, 0); + return inst_ok; + + } else if (m == inst_opt_noinitcalib) { + va_list args; + int losecs = 0; + + va_start(args, m); + losecs = va_arg(args, int); + va_end(args); + + smcube_set_noinitcalib(p, 1, losecs); + return inst_ok; + + /* Record the trigger mode */ + } else if (m == inst_opt_trig_prog + || m == inst_opt_trig_user + || m == inst_opt_trig_user_switch) { + p->trig = m; + return inst_ok; + + /* Is there a black or gloss optional user calibration being used ? */ + } else if (m == inst_opt_opt_calibs_valid) { + va_list args; + int *valid; + + va_start(args, m); + valid = va_arg(args, int *); + va_end(args); + + if (p->dark_default && p->gloss_default) + *valid = 0; + else + *valid = 1; + + return inst_ok; + + /* Clear all the optional user calibrations back to default */ + } else if (m == inst_opt_clear_opt_calibs) { + va_list args; + + set_optcalibs_default(p); + +#ifdef ENABLE_NONVCAL + /* Save the updated calibration state to a file */ + smcube_save_calibration(p); +#endif + return inst_ok; + } + + /* Get/Sets that require instrument coms. */ + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + return inst_unsupported; +} + +/* Constructor */ +extern smcube *new_smcube(icoms *icom, instType itype) { + smcube *p; + if ((p = (smcube *)calloc(sizeof(smcube),1)) == NULL) { + a1loge(icom->log, 1, "new_smcube: malloc failed!\n"); + return NULL; + } + + p->log = new_a1log_d(icom->log); + + p->init_coms = smcube_init_coms; + p->init_inst = smcube_init_inst; + p->capabilities = smcube_capabilities; + p->check_mode = smcube_check_mode; + p->set_mode = smcube_set_mode; + p->get_disptypesel = smcube_get_disptypesel; + p->set_disptype = smcube_set_disptype; + p->get_set_opt = smcube_get_set_opt; + p->read_sample = smcube_read_sample; + p->get_n_a_cals = smcube_get_n_a_cals; + p->calibrate = smcube_calibrate; + p->interp_error = smcube_interp_error; + p->del = smcube_del; + + p->icom = icom; + icom->icntx = (void *)p; /* Allow us to get instrument from icom */ + p->itype = itype; + + amutex_init(p->lock); + + p->trig = inst_opt_trig_user; + + p->want_wcalib = 1; /* Do a white calibration each time we open the device */ + + set_optcalibs_default(p); + + return p; +} + +/* ============================================================================== */ +/* Implementation. All of these are thread safe unless noted */ + +static inst_code +smcube_ping(smcube *p) { + unsigned char buf[MAX_MES_SIZE]; + inst_code ev = inst_ok; + int se; + + a1logd(p->log, 2, "smcube_ping:\n"); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + buf[0] = 0x7e; + buf[1] = 0x00; + buf[2] = 0x02; + buf[3] = 0x00; + + if ((ev = smcube_command(p, buf, 4, buf, 4, DEFTO)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check the response */ + if (buf[0] != 0x7e || buf[1] != 0x20 || buf[2] != 0x02 || buf[3] == 0x00) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + a1logd(p->log, 2, "smcube_init_coms: ping sucesss\n"); + + amutex_unlock(p->lock); + + return inst_ok; +} + +static inst_code +smcube_get_idle_time(smcube *p, int *pitime, int nd) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + int se; + + if (!nd) + a1logd(p->log, 2, "smcube_get_idle_time:\n"); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 6); + buf[0] = 0x7e; + buf[1] = 0x02; + buf[2] = 0x51; + + if ((se = smcube_fcommand(p, buf, 6, buf, 6, 0.2, nd)) != inst_ok) { + amutex_unlock(p->lock); + return smcube_interp_code((inst *)p, se); + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x51) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + itime = read_ORD16_be(buf + 4); + + if (!nd) + a1logd(p->log, 2, "smcube_get_idle_time: returing %d\n",itime); + + if (pitime != NULL) + *pitime = itime; + + return inst_ok; +} + +/* Do a factory measurement */ +static inst_code +smcube_fact_measure(smcube *p, double *XYZ) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "smcube_fact_measure:\n"); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 16); + buf[0] = 0x7e; + buf[1] = 12; + buf[2] = 0x40; + + if ((ev = smcube_command(p, buf, 16, buf, 16, 3.5)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x40) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + XYZ[0] = IEEE754todouble(read_ORD32_be(buf + 4)); + XYZ[1] = IEEE754todouble(read_ORD32_be(buf + 8)); + XYZ[2] = IEEE754todouble(read_ORD32_be(buf + 12)); + a1logd(p->log, 2, "smcube_fact_measure: returing L*a*b* %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]); + + icmLab2XYZ(&icmD50_100, XYZ, XYZ); + + a1logd(p->log, 2, "smcube_fact_measure: returing XYZ %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]); + + return inst_ok; +} + +/* Try and fetch a button generated measurement meassage */ +/* Return inst_user_trig if found one */ +static inst_code +smcube_poll_measure(smcube *p, double to, int nd) { + unsigned char buf[MAX_MES_SIZE]; + int se; + inst_code ev = inst_ok; + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + if ((se = p->icom->read(p->icom, (char *)buf, MAX_MES_SIZE, NULL, NULL, 16, to)) != 0 + && (se & ICOM_TO) == 0) { + amutex_unlock(p->lock); + return icoms2smcube_err(se); + } + amutex_unlock(p->lock); + + /* If we got a timeout, ignore the read */ + if ((se & ICOM_TO) != 0) { + return inst_ok; + } + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x40) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + p->XYZ[0] = IEEE754todouble(read_ORD32_be(buf + 4)); + p->XYZ[1] = IEEE754todouble(read_ORD32_be(buf + 8)); + p->XYZ[2] = IEEE754todouble(read_ORD32_be(buf + 12)); + if (!nd) a1logd(p->log, 2, "smcube_poll_measure: returing L*a*b* %f %f %f\n",p->XYZ[0], p->XYZ[1], p->XYZ[2]); + + icmLab2XYZ(&icmD50_100, p->XYZ, p->XYZ); + + return inst_user_trig; +} + +/* wrgb channel numbers to use */ +#ifdef USEW +# define RCH 0 /* Use the White channel */ +# define GCH 0 +# define BCH 0 +#else +# define RCH 1 /* Use the R,G & B channels */ +# define GCH 2 +# define BCH 3 +#endif + +/* Measure a 4 channel intensity value */ +/* 0 = White */ +/* 1 = Red */ +/* 2 = Green */ +/* 3 = Blue */ + +static inst_code +smcube_meas_wrgb(smcube *p, int ichan, int *wrgb) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + int cmd = 0x47 + ichan; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "smcube_meas_wrgb: ichan %d\n",ichan); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 12); + buf[0] = 0x7e; + buf[1] = 8; + buf[2] = cmd; + + if ((ev = smcube_command(p, buf, 12, buf, 12, 1.5)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != cmd) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + wrgb[0] = read_ORD16_be(buf + 4); + wrgb[1] = read_ORD16_be(buf + 6); + wrgb[2] = read_ORD16_be(buf + 8); + wrgb[3] = read_ORD16_be(buf + 10); + + a1logd(p->log, 2, "smcube_meas_wrgb: WRGB %d %d %d %d\n",wrgb[0], wrgb[1], wrgb[2], wrgb[3]); + + return inst_ok; +} + +/* Get the version information */ +/* Doesn't seem to be implemented ? */ +static inst_code smcube_get_version(smcube *p, int *val) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "smcube_version:\n"); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 5); + buf[0] = 0x7e; + buf[1] = 1; + buf[2] = 0x19; + + if ((ev = smcube_command(p, buf, 5, buf, 5, 1.5)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x19) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + val[0] = read_ORD8(buf + 4); + + a1logd(p->log, 2, "smcube_version: val %d\n",val[0]); + + return inst_ok; +} + + +/* Read a calibration value */ +static inst_code +smcube_get_cal_val(smcube *p, int addr, double *cval) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "smcube_get_cal_val: addr %d\n",addr); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 9); + buf[0] = 0x7e; + buf[1] = 5; + buf[2] = 0x04; + + buf[4] = addr; + + if ((ev = smcube_command(p, buf, 9, buf, 9, DEFTO)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x04) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + *cval = IEEE754todouble(read_ORD32_be(buf + 5)); + + a1logd(p->log, 2, "smcube_get_cal_val: addr %d val %f",addr,*cval); + + return inst_ok; +} + +/* Diagnostic - dump all the calibration values */ +static void +smcube_dump_cal(smcube *p) { + int i; + double val; + inst_code ev = inst_ok; + + for (i = 0; i < 89; i++) { + if ((ev = smcube_get_cal_val(p, i, &val)) == inst_ok) { + printf("Cal addr %d = %f\n",i,val); + } + } +} + + +/* Write a calibration value */ +static inst_code +smcube_set_cal_val(smcube *p, int addr, double cval) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "smcube_set_cal_val: addr %d value %f\n",addr,cval); + + if (!p->gotcoms) + return inst_no_coms; + + if (addr <= 50 + || (addr >= 69 && addr <= 77) + || addr >= 87) { + return smcube_interp_code((inst *)p, SMCUBE_INT_ILL_WRITE); + } + + amutex_lock(p->lock); + + memset(buf, 0, 9); + buf[0] = 0x7e; + buf[1] = 5; + buf[2] = 0x03; + + buf[4] = addr; + write_ORD32_be(buf + 5, doubletoIEEE754(cval)); + + if ((ev = smcube_command(p, buf, 9, buf, 9, DEFTO)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x03) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + a1logd(p->log, 2, "smcube_set_cal_val: addr %d OK\n",addr); + + return inst_ok; +} + +/* Get the current temperature */ +static inst_code +smcube_get_temp(smcube *p, double *tval) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + double temp = 0.0; + + a1logd(p->log, 2, "smcube_get_temp:\n"); + + if (!p->gotcoms) + return inst_no_coms; + + amutex_lock(p->lock); + + memset(buf, 0, 8); + buf[0] = 0x7e; + buf[1] = 4; + buf[2] = 0x41; + + if ((ev = smcube_command(p, buf, 8, buf, 8, DEFTO)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x41) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + temp = IEEE754todouble(read_ORD32_be(buf + 4)); + + a1logd(p->log, 2, "smcube_get_temp: val %f OK\n",temp); + + if (tval != NULL) + *tval = temp; + + return inst_ok; +} + +/* Get a calibration temperature. */ +/* Is this stored automatically on smcube_set_cal_val() ? */ +/* Typically this is from addr 78, i.e. first user grey scale slot */ +static inst_code +smcube_get_cal_temp(smcube *p, int addr, double *tval) { + unsigned char buf[MAX_MES_SIZE]; + int itime; + inst_code ev = inst_ok; + double temp = 0.0; + + a1logd(p->log, 2, "smcube_get_cal_temp: addr %d\n",addr); + + if (!p->gotcoms) + return inst_no_coms; + + if (addr <= 50 + || (addr >= 69 && addr <= 77) + || addr >= 87) { + return smcube_interp_code((inst *)p, SMCUBE_INT_ILL_WRITE); + } + + amutex_lock(p->lock); + + memset(buf, 0, 9); + buf[0] = 0x7e; + buf[1] = 5; + buf[2] = 0x05; + + buf[4] = addr; + + if ((ev = smcube_command(p, buf, 9, buf, 9, DEFTO)) != inst_ok) { + amutex_unlock(p->lock); + return ev; + } + amutex_unlock(p->lock); + + /* Check protocol */ + if (buf[0] != 0x7e || buf[2] != 0x05) { + return smcube_interp_code((inst *)p, SMCUBE_DATA_PARSE_ERROR); + } + + /* Check error code */ + if (buf[3] != 0) { + return smcube_interp_code((inst *)p, buf[3]); + } + + temp = IEEE754todouble(read_ORD32_be(buf + 5)); + + a1logd(p->log, 2, "smcube_get_cal_temp: addr %d, val %f OK\n",addr,temp); + + if (tval != NULL) + *tval = temp; + + return inst_ok; +} + +/* Do a Factory & Argyll white calibration */ +static inst_code +smcube_fact_white_calib(smcube *p) { + inst_code ev = inst_ok; + int i, j; + int wrgb[3][4]; + +#ifdef USEW + int normal[3] = { 10009, 20382, 37705 }; +#else + int normal[3] = { 9221, 13650, 28568 }; +#endif + + a1logd(p->log, 2, "smcube_fact_white_calib:\n"); + + /* Meaure the R, G * B */ + for (i = 0; i < 3; i++) { + if ((ev = smcube_meas_wrgb(p, i + 1, wrgb[i])) != inst_ok) { + return ev; + } + } + + /* Write the R, G, & B to the Cube User Grey Scale calibration */ + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + if ((ev = smcube_set_cal_val(p, 78 + i * 3 + j, (double)wrgb[i][j+1])) != inst_ok) { + return ev; + } + } + } + + /* Compute Argyll calibration scale factors */ + { + double tmp[3]; + + a1logd(p->log, 2, "smcube_white_calib: Got raw RGB %d %d %d\n", + wrgb[0][RCH],wrgb[1][GCH],wrgb[2][BCH]); + + /* Sanity check raw values */ + if (wrgb[0][RCH] < (normal[0]/2) || wrgb[0][RCH] > (3 * normal[0]/2) + || wrgb[1][GCH] < (normal[1]/2) || wrgb[1][GCH] > (3 * normal[1]/2) + || wrgb[2][BCH] < (normal[2]/2) || wrgb[2][BCH] > (3 * normal[2]/2)) { + return smcube_interp_code((inst *)p, SMCUBE_WHITE_CALIB_ERR); + } + + /* Add black offset into cwref */ + for (i = 0; i < 3; i++) + tmp[i] = cwref[i] * (1.0 - p->soff[i]) + p->soff[i]; + + p->sscale[0] = tmp[0]/(double)wrgb[0][RCH]; + p->sscale[1] = tmp[1]/(double)wrgb[1][GCH]; + p->sscale[2] = tmp[2]/(double)wrgb[2][BCH]; + + if ((ev = smcube_get_cal_temp(p, 78, &p->ctemp)) != inst_ok) + return ev; + + a1logd(p->log, 2, "smcube_fact_white_calib: Argyll cal = %e %e %e at temp %f\n", + p->sscale[0], p->sscale[1], p->sscale[2], p->ctemp); + } + + a1logd(p->log, 2, "smcube_fact_white_calib: done\n"); + + return inst_ok; +} + +/* Apply temperature compensation to the raw sensor readings */ +static void temp_comp_raw(smcube *p, double *rgb, double tval) { + int j; + double tchange = tval - p->ctemp; + + for (j = 0; j < 3; j++) { + rgb[j] *= (1.0 + tchange * tempc[j]); + } +} + +/* -------------------------------------------------------------- */ +/* Argyll calibrated measurement support */ + +static inst_code +smcube_black_calib(smcube *p, int ctype) { + inst_code ev = inst_ok; + int i, j; + int wrgb[3][4]; + double rgb[3]; + double tval; + + a1logd(p->log, 2, "smcube_black_calib: type %s\n",ctype == 0 ? "trap" : "gloss"); + + /* Meaure the R, G * B */ + for (i = 0; i < 3; i++) { + if ((ev = smcube_meas_wrgb(p, i + 1, wrgb[i])) != inst_ok) { + return ev; + } + } + rgb[0] = (double)wrgb[0][RCH]; + rgb[1] = (double)wrgb[1][GCH]; + rgb[2] = (double)wrgb[2][BCH]; + + if ((ev = smcube_get_temp(p, &tval)) != inst_ok) { + return ev; + } + temp_comp_raw(p, rgb, tval); + + if (!p->white_valid) { + return smcube_interp_code((inst *)p, SMCUBE_INT_WHITE_CALIB); + } + + /* Black */ + if (ctype == 0) { + + for (i = 0; i < 3; i++) { + rgb[i] = p->sscale[i] * rgb[i]; + if (rgb[i] < 0.0) + rgb[i] = 0.0; + } + + a1logd(p->log, 2, "smcube_black_calib: soff = %f %f %f, default %f %f %f\n", + rgb[0], rgb[1], rgb[2], dsoff[0], dsoff[1], dsoff[2]); + + /* Sanity check values */ + for (i = 0; i < 3; i++) { + if (rgb[i] < 0.5 * (dsoff[i]) + || rgb[i] > 2.0 * (dsoff[i])) { + a1logd(p->log, 1, "smcube_black_calib: rgb[%d] %f out of range %f .. %f\n", + i, rgb[i], 0.5 * dsoff[i], 2.0 * dsoff[i]); + break; + } + } + + if (i < 3) { + return smcube_interp_code((inst *)p, SMCUBE_BLACK_CALIB_ERR); + } + + for (i = 0; i < 3; i++) + p->soff[i] = rgb[i]; + + /* Gloss */ + } else { + if (!p->dark_valid) { + return smcube_interp_code((inst *)p, SMCUBE_INT_BLACK_CALIB); + } + + /* Scale to 100% white reference */ + for (i = 0; i < 3; i++) { + rgb[i] = p->sscale[i] * rgb[i]; + } + + /* Remove the black offset */ + for (i = 0; i < 3; i++) { + rgb[i] = (rgb[i] - p->soff[i])/(1.0 - p->soff[i]); + if (rgb[i] < 0.0) + rgb[i] = 0.0; + } + + /* Compute the gloss offset */ + for (i = 0; i < 3; i++) { + rgb[i] = rgb[i] - glref[0]; + if (rgb[i] < 0.0) + rgb[i] = 0.0; + } + a1logd(p->log, 2, "smcube_gloss_calib: goff = %f %f %f, default %f %f %f\n", + rgb[0], rgb[1], rgb[2], dgoff[0], dgoff[1], dgoff[2]); + + /* Sanity check values */ + for (i = 0; i < 3; i++) { + if (rgb[i] < 0.5 * dgoff[i] + || rgb[i] > 2.0 * dgoff[i]) { + a1logd(p->log, 1, "smcube_gloss_calib: rgb[%d] %f out of range %f .. %f\n", + i, rgb[i], 0.5 * dgoff[i], 2.0 * dgoff[i]); + break; + } + } + + if (i < 3) { + return smcube_interp_code((inst *)p, SMCUBE_GLOSS_CALIB_ERR); + } + + for (i = 0; i < 3; i++) + p->goff[i] = rgb[i]; + } + + a1logd(p->log, 2, "smcube_black_calib: done\n"); + + return inst_ok; +} + +static inst_code +smcube_measure(smcube *p, double *XYZ) { + inst_code ev = inst_ok; + int i, j; + int wrgb[3][4]; + double rgb[3]; + double tval; + + a1logd(p->log, 2, "smcube_measure:\n"); + + /* Meaure the R, G * B */ + for (i = 0; i < 3; i++) { + if ((ev = smcube_meas_wrgb(p, i + 1, wrgb[i])) != inst_ok) { + return ev; + } + } + rgb[0] = (double)wrgb[0][RCH]; + rgb[1] = (double)wrgb[1][GCH]; + rgb[2] = (double)wrgb[2][BCH]; + + a1logd(p->log, 2, "smcube_measure: Raw RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]); + + if ((ev = smcube_get_temp(p, &tval)) != inst_ok) { + return ev; + } + temp_comp_raw(p, rgb, tval); + + a1logd(p->log, 2, "smcube_measure: Temp comp. RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]); + + if (!p->white_valid) { + return smcube_interp_code((inst *)p, SMCUBE_INT_WHITE_CALIB); + } + + /* Scale it to white */ + for (i = 0; i < 3; i++) + rgb[i] *= p->sscale[i]; + + a1logd(p->log, 2, "smcube_measure: Scaled RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]); + + if (!p->dark_valid) { + return smcube_interp_code((inst *)p, SMCUBE_INT_BLACK_CALIB); + } + + /* Remove the black offset */ + for (i = 0; i < 3; i++) { + rgb[i] = (rgb[i] - p->soff[i])/(1.0 - p->soff[i]); + if (rgb[i] < 0.0) + rgb[i] = 0.0; + } + a1logd(p->log, 2, "smcube_measure: Black offset RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]); + + /* If gloss mode */ + if (p->icx == 1) { + for (i = 0; i < 3; i++) { + rgb[i] = (rgb[i] - p->goff[i])/(1.0 - p->goff[i]); + if (rgb[i] < 0.0) + rgb[i] = 0.0; + } + a1logd(p->log, 2, "smcube_measure: Gloss comp. RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]); + } + + a1logd(p->log, 2, "smcube_measure: RGB reflectance %f %f %f\n",rgb[0],rgb[1],rgb[2]); + +#ifdef NEVER +/* Adjust for CC white target */ +{ + double targ[3] = { 0.916179, 0.906579, 0.866163 }; + + printf("white ref was = %f %f %f\n",cwref[0],cwref[1],cwref[2]); + for (i = 0; i < 3; i++) { + cwref[i] *= pow(targ[i]/rgb[i], 0.7); + } + printf("adjusted white ref = %f %f %f\n",cwref[0],cwref[1],cwref[2]); +} +#endif + + cube_rgb2XYZ(XYZ, rgb); + + a1logd(p->log, 2, "smcube_measure: done\n"); + + return inst_ok; +} + +/* ---------------------------- */ + +/* Convert RGB to XYZ using calibration table */ +static void cube_rgb2XYZ(double *xyz, double *irgb) { + int e; + double rgb[3]; + int ix[3]; /* Coordinate of cell */ + double co[3]; /* Coordinate offset with the grid cell */ + int si[3]; /* co[] Sort index, [0] = smalest */ + + /* Clip and apply rgb power */ + for (e = 0; e < 3; e++) { + rgb[e] = irgb[e]; + if (rgb[e] < 0.0) + rgb[e] = 0.0; + if (rgb[e] > 1.0) + rgb[e] = 1.0; + rgb[e] = pow(rgb[e], clut.dpow); + } + + /* We are using tetrahedral interpolation. */ + + /* Compute base index into grid and coordinate offsets */ + { + double res_1 = clut.res-1; + int res_2 = clut.res-2; + int e; + + for (e = 0; e < 3; e++) { + unsigned int x; + double val; + val = rgb[e] * res_1; + if (val < 0.0) { + val = 0.0; + } else if (val > res_1) { + val = res_1; + } + x = (unsigned int)floor(val); /* Grid coordinate */ + if (x > res_2) + x = res_2; + co[e] = val - (double)x; /* 1.0 - weight */ + ix[e] = x; + } + } + /* Do insertion sort on coordinates, smallest to largest. */ + { + int e, f, vf; + double v; + for (e = 0; e < 3; e++) + si[e] = e; /* Initial unsorted indexes */ + + for (e = 1; e < 3; e++) { + f = e; + v = co[si[f]]; + vf = f; + while (f > 0 && co[si[f-1]] > v) { + si[f] = si[f-1]; + f--; + } + si[f] = vf; + } + } + /* Now compute the weightings, simplex vertices and output values */ + { + int e, f; + double w; /* Current vertex weight */ + + w = 1.0 - co[si[3-1]]; /* Vertex at base of cell */ + for (f = 0; f < 3; f++) + xyz[f] = w * clut.table[ix[0]][ix[1]][ix[2]][f]; + + for (e = 3-1; e > 0; e--) { /* Middle verticies */ + w = co[si[e]] - co[si[e-1]]; + ix[si[e]]++; + for (f = 0; f < 3; f++) + xyz[f] += w * clut.table[ix[0]][ix[1]][ix[2]][f]; + } + + w = co[si[0]]; + ix[si[0]]++; /* Far corner from base of cell */ + for (f = 0; f < 3; f++) + xyz[f] += w * clut.table[ix[0]][ix[1]][ix[2]][f]; + } + + if (clut.islab) + icmLab2XYZ(&icmD50_100, xyz, xyz); + else + icmScale3(xyz, xyz, 100.0); /* ??? */ +} + +/* =============================================================================== */ +/* Calibration info save/restore */ + +/* The cube doesn't have an easily accessible serial number :-( */ +/* So if you have more than one, you'll be sharing the same calibration !! */ + +int smcube_save_calibration(smcube *p) { + int ev = SMCUBE_OK; + int i; + char fname[100]; /* Name */ + calf x; + int argyllversion = ARGYLL_VERSION; + int valid; + int ss; + + snprintf(fname, 99, ".smcube.cal"); + + if (calf_open(&x, p->log, fname, 1)) { + x.ef = 2; + goto done; + } + + ss = sizeof(smcube); + + /* Some file identification */ + calf_wints(&x, &argyllversion, 1); + calf_wints(&x, &ss, 1); + + /* Save all the calibrations */ + calf_wints(&x, &p->white_valid, 1); + calf_wtime_ts(&x, &p->wdate, 1); + calf_wdoubles(&x, p->sscale, 3); + calf_wdoubles(&x, &p->ctemp, 1); + + /* Only save dark cal if it is not the fallback default */ + valid = p->dark_valid && !p->dark_default; + calf_wints(&x, &valid, 1); + calf_wtime_ts(&x, &p->ddate, 1); + calf_wdoubles(&x, p->soff, 3); + + /* Only save gloss cal if it is not the fallback default */ + valid = p->gloss_valid && !p->gloss_default; + calf_wints(&x, &valid, 1); + calf_wtime_ts(&x, &p->gdate, 1); + calf_wdoubles(&x, p->goff, 3); + + a1logd(p->log,3,"nbytes = %d, Checkum = 0x%x\n",x.nbytes,x.chsum); + calf_wints(&x, (int *)(&x.chsum), 1); + + if (calf_done(&x)) + x.ef = 3; + + done:; + if (x.ef != 0) { + a1logd(p->log,2,"Writing calibration file failed with %d\n",x.ef); + ev = SMCUBE_INT_CAL_SAVE; + } else { + a1logd(p->log,2,"Writing calibration file succeeded\n"); + } + + return ev; +} + +/* Restore the all modes calibration from the local system */ +int smcube_restore_calibration(smcube *p) { + int ev = SMCUBE_OK; + int i, j; + char fname[100]; /* Name */ + calf x; + int argyllversion; + int valid; + int ss, nbytes, chsum1, chsum2; + + snprintf(fname, 99, ".smcube.cal"); + + if (calf_open(&x, p->log, fname, 0)) { + x.ef = 2; + goto done; + } + + /* Last modified time */ + p->lo_secs = x.lo_secs; + + /* Do a dumy read to check the checksum, then a real read */ + for (x.rd = 0; x.rd < 2; x.rd++) { + calf_rewind(&x); + + /* Check the file identification */ + calf_rints2(&x, &argyllversion, 1); + calf_rints2(&x, &ss, 1); + + if (x.ef != 0 + || argyllversion != ARGYLL_VERSION + || ss != (sizeof(smcube))) { + a1logd(p->log,2,"Identification didn't verify\n"); + if (x.ef == 0) + x.ef = 4; + goto done; + } + + /* Read all the calibrations */ + calf_rints(&x, &p->white_valid, 1); + calf_rtime_ts(&x, &p->wdate, 1); + calf_rdoubles(&x, p->sscale, 3); + calf_rdoubles(&x, &p->ctemp, 1); + + calf_rints(&x, &valid, 1); + calf_rtime_ts(&x, &p->ddate, 1); + calf_rdoubles(&x, p->soff, 3); + if (x.rd > 0) { + if (valid) { + p->dark_default = 0; + } else { + /* Use fallback default black offset */ + p->soff[0] = dsoff[0]; + p->soff[1] = dsoff[1]; + p->soff[2] = dsoff[2]; + p->dark_valid = 1; + p->dark_default = 1; + } + } + + calf_rints(&x, &valid, 1); + calf_rtime_ts(&x, &p->gdate, 1); + calf_rdoubles(&x, p->goff, 3); + if (x.rd > 0) { + if (valid) { + p->gloss_default = 0; + } else { + /* Use fallback default gloss offset */ + p->goff[0] = dgoff[0]; + p->goff[1] = dgoff[1]; + p->goff[2] = dgoff[2]; + p->gloss_valid = 1; + p->gloss_default = 1; + } + } + + /* Check the checksum */ + chsum1 = x.chsum; + nbytes = x.nbytes; + calf_rints2(&x, &chsum2, 1); + + if (x.ef != 0 + || chsum1 != chsum2) { + a1logd(p->log,2,"Checksum didn't verify, bytes %d, got 0x%x, expected 0x%x\n",nbytes,chsum1, chsum2); + if (x.ef == 0) + x.ef = 5; + goto done; + } + } + + a1logd(p->log,5,"smcube_restore_calibration done\n"); + done:; + + if (calf_done(&x)) + x.ef = 3; + + if (x.ef != 0) { + a1logd(p->log,2,"Reading calibration file failed with %d\n",x.ef); + ev = SMCUBE_INT_CAL_RESTORE; + } + + return ev; +} + +int smcube_touch_calibration(smcube *p) { + int ev = SMCUBE_OK; + char fname[100]; /* Name */ + int rv; + + snprintf(fname, 99, ".smcube.cal"); + + if (calf_touch(p->log, fname)) { + a1logd(p->log,2,"Touching calibration file time failed with\n"); + return SMCUBE_INT_CAL_TOUCH; + } + + return SMCUBE_OK; +} + + diff --git a/spectro/smcube.h b/spectro/smcube.h new file mode 100755 index 0000000..7283635 --- /dev/null +++ b/spectro/smcube.h @@ -0,0 +1,119 @@ +#ifndef SMCUBE_H + +/* + * Argyll Color Correction System + * + * JETI smcube related defines + * + * Author: Graeme W. Gill + * Date: 13/3/2013 + * + * Copyright 2001 - 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. + * + * Based on DTP02.h + */ + +/* + If you make use of the instrument driver code here, please note + that it is the author(s) of the code who take responsibility + for its operation. Any problems or queries regarding driving + instruments with the Argyll drivers, should be directed to + the Argyll's author(s), and not to any other party. + + If there is some instrument feature or function that you + would like supported here, it is recommended that you + contact Argyll's author(s) first, rather than attempt to + modify the software yourself, if you don't have firm knowledge + of the instrument communicate protocols. There is a chance + that an instrument could be damaged by an incautious command + sequence, and the instrument companies generally cannot and + will not support developers that they have not qualified + and agreed to support. + */ + +#include "inst.h" + +/* Fake Error codes */ +#define SMCUBE_INTERNAL_ERROR 0xff01 /* Internal software error */ +#define SMCUBE_TIMEOUT 0xff02 /* Communication timeout */ +#define SMCUBE_COMS_FAIL 0xff03 /* Communication failure */ +#define SMCUBE_UNKNOWN_MODEL 0xff04 /* Not a SwatchMate Cube */ +#define SMCUBE_DATA_PARSE_ERROR 0xff05 /* Read data parsing error */ + + +/* Real instrument error code */ +#define SMCUBE_OK 0 + +/* Internal software errors */ +#define SMCUBE_INT_THREADFAILED 0x1000 +#define SMCUBE_INT_ILL_WRITE 0x1001 /* Write to factor calibration */ +#define SMCUBE_INT_WHITE_CALIB 0x1002 /* No white calibration */ +#define SMCUBE_INT_BLACK_CALIB 0x1003 /* No black calibration */ +#define SMCUBE_INT_GLOSS_CALIB 0x1004 /* No gloss calibration */ +#define SMCUBE_INT_CAL_SAVE 0x1005 /* Saving calibration to file failed */ +#define SMCUBE_INT_CAL_RESTORE 0x1006 /* Restoring calibration to file failed */ +#define SMCUBE_INT_CAL_TOUCH 0x1007 /* Touching calibration to file failed */ + +/* Other errors */ +#define SMCUBE_WHITE_CALIB_ERR 0x2000 /* White calibration isn't reasonable */ +#define SMCUBE_BLACK_CALIB_ERR 0x2001 /* Black calibration isn't reasonable */ +#define SMCUBE_GLOSS_CALIB_ERR 0x2002 /* Gloss calibration isn't reasonable */ + +/* SMCUBE communication object */ +struct _smcube { + INST_OBJ_BASE + + int bt; /* Bluetooth coms rather than USB/serial */ + + amutex lock; /* Command lock */ + + int version; /* Cube version ? */ + + inst_mode mode; /* Currently instrument mode */ + + int icx; /* Internal calibration index, 0 = Matt, 1 = Gloss, 2 = Factory */ + disptech dtech; /* Display technology enum (not used) */ + + inst_opt_type trig; /* Reading trigger mode */ + + /* Argyll Calibration */ + int white_valid; /* idark calibration factors valid */ + time_t wdate; /* Date/time of last white calibration */ + double sscale[3]; /* Sensor RGB white scale values to 0.0 - 1.0 range */ + double ctemp; /* Calibration temperature */ + + int dark_valid; /* dark calibration factors valid */ + int dark_default; /* dark calibration factors are from default */ + time_t ddate; /* Date/time of last dark dark calibration */ + double soff[3]; /* Sensor RGB dark offset values */ + + int gloss_valid; /* gloss calibration factors valid */ + int gloss_default; /* gloss calibration factors are from default */ + time_t gdate; /* Date/time of last gloss calibration */ + double goff[3]; /* Sensor gloss RGB offset values */ + + int noinitcalib; /* Disable initial calibration if not essential */ + int lo_secs; /* Seconds since last opened (from calibration file mod time) */ + int want_wcalib; /* Want White Calibration at start */ + + /* Other state */ + athread *th; /* Diffuser position monitoring thread */ + volatile int th_term; /* nz to terminate thread */ + volatile int th_termed; /* nz when thread terminated */ + + volatile int switch_count; /* Incremented in thread */ + volatile int hide_switch; /* Set to supress switch event during read */ + double XYZ[3]; /* Button triggered XYZ in factory mode */ + + }; typedef struct _smcube smcube; + +/* Constructor */ +extern smcube *new_smcube(icoms *icom, instType itype); + + +#define SMCUBE_H +#endif /* SMCUBE_H */ diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c index 2465842..c9e570c 100644..100755 --- a/spectro/spec2cie.c +++ b/spectro/spec2cie.c @@ -94,7 +94,7 @@ usage (void) 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\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"); @@ -116,6 +116,7 @@ main(int argc, char *argv[]) cgats *ocg; /* output cgats structure */ cgats_set_elem *elems; + 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 ? */ icColorSpaceSignature devspace = icmSigDefaultData; /* The device colorspace */ @@ -127,13 +128,15 @@ main(int argc, char *argv[]) char* illum_str = "D50"; icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */ - icxIllumeType illum = icxIT_D50; /* Spectral defaults */ + icxIllumeType illum = icxIT_none; /* Spectral defaults */ xspect cust_illum; /* Custom CIE illumination spectrum */ icxIllumeType inst_illum = icxIT_none; /* Spectral defaults */ xspect inst_cust_illum; /* Custom actual instrument illumination spectrum */ - icxObserverType observ = icxOT_CIE_1931_2; + icxObserverType observ = icxOT_none; + xspect cust_observ[3]; /* Custom observer CMF's */ int npat; /* Number of patches */ + int dti; /* Device Type index */ char *kw; int i, j, jj, k; @@ -304,8 +307,11 @@ main(int argc, char *argv[]) else if (strcmp (na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */ observ = icxOT_Shaw_Fairchild_2; } - else - usage (); + else { /* Assume it's a filename */ + observ = icxOT_custom; + if (read_cmf (cust_observ, na) != 0) + usage (); + } } else @@ -364,15 +370,34 @@ main(int argc, char *argv[]) } } - /* Figure out what sort of device it is */ + 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 */ + if (illum == icxIT_none) + illum = icxIT_D50; + + if (observ = icxOT_none) + observ = icxOT_CIE_1931_2; + /* Figure out what sort of device it is */ { int ti; + char *tos; - if ((ti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0) - error ("Input file doesn't contain keyword DEVICE_CLASS"); - - if (strcmp (icg->t[0].kdata[ti], "DISPLAY") == 0) { + if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) { isdisp = 1; } @@ -384,26 +409,31 @@ main(int argc, char *argv[]) isdnormed = 1; } - if (isdisp && fwacomp) { - error ("FWA compensation cannot be used for DISPLAY devices"); - } - if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0) error("Input file doesn't contain keyword COLOR_REP"); - if (strncmp(icg->t[0].kdata[ti],"CMYK_",5) == 0) + if ((tos = strchr(icg->t[0].kdata[ti], '_')) == NULL) + tos = icg->t[0].kdata[ti]; + + if (strncmp(icg->t[0].kdata[ti],"CMYK_",5) == 0 + || strncmp(tos,"_CMYK",5) == 0) { devspace = icSigCmykData; - else if (strncmp(icg->t[0].kdata[ti],"CMY_",4) == 0) + } else if (strncmp(icg->t[0].kdata[ti],"CMY_",4) == 0 + || strncmp(tos,"_CMY",4) == 0) { devspace = icSigCmyData; - else if (strncmp(icg->t[0].kdata[ti],"RGB_",4) == 0) + } else if (strncmp(icg->t[0].kdata[ti],"RGB_",4) == 0 + || strncmp(tos,"_RGB",4) == 0) { devspace = icSigRgbData; - else if (strncmp(icg->t[0].kdata[ti],"iRGB_",4) == 0) { + } else if (strncmp(icg->t[0].kdata[ti],"iRGB_",4) == 0 + || strncmp(tos,"_iRGB",4) == 0) { devspace = icSigRgbData; isInverted = 1; - } else if (strncmp(icg->t[0].kdata[ti],"K_",2) == 0) { + } else if (strncmp(icg->t[0].kdata[ti],"K_",2) == 0 + || strncmp(tos,"_K",2) == 0) { devspace = icSigGrayData; isAdditive = 0; - } else if (strncmp(icg->t[0].kdata[ti],"W_",2) == 0) { + } else if (strncmp(icg->t[0].kdata[ti],"W_",2) == 0 + || strncmp(tos,"_W",2) == 0) { devspace = icSigGrayData; isAdditive = 1; } else @@ -415,12 +445,12 @@ main(int argc, char *argv[]) if ((ci = icg->find_field(icg, 0, "GRAY_W")) < 0) error("Input file doesn't contain field GRAY_W"); if (icg->t[0].ftype[ci] != r_t) - error("Field GRAY_W is wrong type - corrupted file ?"); + error("Field GRAY_W is wrong type - expect float"); } else { if ((ci = icg->find_field(icg, 0, "GRAY_K")) < 0) error("Input file doesn't contain field GRAY_K"); if (icg->t[0].ftype[ci] != r_t) - error("Field GRAY_K is wrong type - corrupted file ?"); + error("Field GRAY_K is wrong type - expect float"); } mi = yi = ki = ci; @@ -429,15 +459,15 @@ main(int argc, char *argv[]) if ((ci = icg->find_field(icg, 0, "RGB_R")) < 0) error("Input file doesn't contain field RGB_R"); if (icg->t[0].ftype[ci] != r_t) - error("Field RGB_R is wrong type - corrupted file ?"); + error("Field RGB_R is wrong type - expect float"); if ((mi = icg->find_field(icg, 0, "RGB_G")) < 0) error("Input file doesn't contain field RGB_G"); if (icg->t[0].ftype[mi] != r_t) - error("Field RGB_G is wrong type - corrupted file ?"); + error("Field RGB_G is wrong type - expect float"); if ((yi = icg->find_field(icg, 0, "RGB_B")) < 0) error("Input file doesn't contain field RGB_B"); if (icg->t[0].ftype[yi] != r_t) - error("Field RGB_B is wrong type - corrupted file ?"); + error("Field RGB_B is wrong type - expect float"); ki = yi; } else if (devspace == icSigCmyData) { @@ -445,15 +475,15 @@ main(int argc, char *argv[]) if ((ci = icg->find_field(icg, 0, "CMY_C")) < 0) error("Input file doesn't contain field CMY_C"); if (icg->t[0].ftype[ci] != r_t) - error("Field CMY_C is wrong type - corrupted file ?"); + error("Field CMY_C is wrong type - expect float"); if ((mi = icg->find_field(icg, 0, "CMY_M")) < 0) error("Input file doesn't contain field CMY_M"); if (icg->t[0].ftype[mi] != r_t) - error("Field CMY_M is wrong type - corrupted file ?"); + error("Field CMY_M is wrong type - expect float"); if ((yi = icg->find_field(icg, 0, "CMY_Y")) < 0) error("Input file doesn't contain field CMY_Y"); if (icg->t[0].ftype[yi] != r_t) - error("Field CMY_Y is wrong type - corrupted file ?"); + error("Field CMY_Y is wrong type - expect float"); ki = yi; } else { /* Assume CMYK */ @@ -461,19 +491,19 @@ main(int argc, char *argv[]) if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0) error("Input file doesn't contain field CMYK_C"); if (icg->t[0].ftype[ci] != r_t) - error("Field CMYK_C is wrong type - corrupted file ?",icg->t[0].ftype[ci],r_t); + error("Field CMYK_C is wrong type - expect float",icg->t[0].ftype[ci],r_t); if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0) error("Input file doesn't contain field CMYK_M"); if (icg->t[0].ftype[mi] != r_t) - error("Field CMYK_M is wrong type - corrupted file ?"); + error("Field CMYK_M is wrong type - expect float"); if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0) error("Input file doesn't contain field CMYK_Y"); if (icg->t[0].ftype[yi] != r_t) - error("Field CMYK_Y is wrong type - corrupted file ?"); + error("Field CMYK_Y is wrong type - expect float"); if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0) error("Input file doesn't contain field CMYK_K"); if (icg->t[0].ftype[ki] != r_t) - error("Field CMYK_K is wrong type - corrupted file ?"); + error("Field CMYK_K is wrong type - expect float"); } } @@ -530,10 +560,13 @@ main(int argc, char *argv[]) if ((spi[j] = icg->find_field (icg, 0, buf)) < 0) error ("Input file doesn't contain field %s", buf); + + if (icg->t[0].ftype[spi[j]] != r_t) + error("Field %s is wrong type - expect float",buf); } - if (isdisp) { - illum = icxIT_none; /* Displays are assumed to be self luminous */ + if (isemis) { + illum = icxIT_none; } @@ -585,7 +618,7 @@ main(int argc, char *argv[]) /* Create a spectral conversion object */ if ((sp2cie = new_xsp2cie (illum, illum == icxIT_none ? NULL : &cust_illum, - observ, NULL, icSigXYZData, icxClamp)) == NULL) + observ, cust_observ, icSigXYZData, icxClamp)) == NULL) { error ("Creation of spectral conversion object failed"); } diff --git a/spectro/specbos.c b/spectro/specbos.c index 0d5bc5b..e819c06 100644..100755 --- a/spectro/specbos.c +++ b/spectro/specbos.c @@ -484,7 +484,7 @@ specbos_init_inst(inst *pp) { return ev; } if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */ - 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); @@ -695,13 +695,46 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */ /* Trigger a measurement */ /* (Note that ESC will abort it) */ - if ((ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0)) != SPECBOS_OK) { + ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0); + + // Test out bug workaround + // if (!p->badCal) ec = SPECBOS_EXCEED_CAL_WL; + + /* If the specbos has been calibrated by a 3rd party, its calibrated range */ + /* may be out of sync with its claimed range. Reduce the range and retry. */ + if (ec == SPECBOS_EXCEED_CAL_WL && !p->badCal) { + char mes[100]; + inst_code ev = inst_ok; + + a1logd(p->log, 1, " Got SPECBOS_EXCEED_CAL_WL error (Faulty 3rd party Calibration ?)\n"); + a1logd(p->log, 1, " Trying workaround by restricting range to 380-780nm\n"); + + if (p->wl_short < 380.0) + p->wl_short = 380.0; + if (p->wl_long > 780.0) + p->wl_long = 780.0; + + p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5); + + /* 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) { + 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 (ec != SPECBOS_OK) { amutex_unlock(p->lock); return specbos_interp_code((inst *)p, ec); } - if (p->noXYZ) { /* Will fail, so assume it failed */ + if (p->noXYZ) { /* "*fetch:XYZ" will fail, so assume it failed rather than trying it */ ec = SPECBOS_COMMAND; } else { /* Read the XYZ */ @@ -894,7 +927,7 @@ double *ref_rate if ((cp = strchr(buf, 'c')) == NULL) cp = buf; if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) { - a1logd(p->log, 1, "specbos_read_refrate rate: failed to parse string '%s'\n",icoms_fix(buf)); + 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; } @@ -1056,7 +1089,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ inst_code ev = inst_ok; - if (*calc != inst_calc_emis_80pc) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_80pc) { *calc = inst_calc_emis_80pc; return inst_cal_setup; } @@ -1788,7 +1821,7 @@ extern specbos *new_specbos(icoms *icom, instType itype) { p->del = specbos_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; if (p->itype == instSpecbos1201) p->model = 1201; diff --git a/spectro/specbos.h b/spectro/specbos.h index 86e7405..e926c42 100644..100755 --- a/spectro/specbos.h +++ b/spectro/specbos.h @@ -129,6 +129,7 @@ struct _specbos { /* 1211 */ 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 */ inst_mode mode; /* Currently instrument mode */ diff --git a/spectro/spotread.c b/spectro/spotread.c index 7689986..baf1c76 100644..100755 --- a/spectro/spotread.c +++ b/spectro/spotread.c @@ -333,7 +333,7 @@ usage(char *diag, ...) { fprintf(stderr," -h Display LCh instead of Lab\n"); fprintf(stderr," -V Show running average and std. devation from ref.\n"); #ifndef SALONEINSTLIB - fprintf(stderr," -T Display correlated color temperatures and CRI\n"); + fprintf(stderr," -T Display correlated color temperatures, CRI and TLCI\n"); #endif /* !SALONEINSTLIB */ // fprintf(stderr," -K type Run instrument calibration first\n"); fprintf(stderr," -N Disable auto calibration of instrument\n"); @@ -948,24 +948,6 @@ int main(int argc, char *argv[]) { refrmode = -1; } } - /* Set display type */ - if (dtype != 0) { - if (cap2 & inst2_disptype) { - int ix; - if ((ix = inst_get_disptype_index(it, dtype, 0)) < 0) { - it->del(it); - usage("Failed to locate display type matching '%c'",dtype); - } - - if ((rv = it->set_disptype(it, ix)) != inst_ok) { - printf("Setting display type ix %d not supported by instrument\n",ix); - it->del(it); - return -1; - } - } else - printf("Display type ignored - instrument doesn't support display type selection\n"); - } - } else { if (!IMODETST(cap, inst_mode_ref_spot) || it->check_mode(it, inst_mode_ref_spot) != inst_ok) { @@ -976,6 +958,24 @@ int main(int argc, char *argv[]) { } } + /* Set displaytype or calibration mode */ + if (dtype != 0) { + if (cap2 & inst2_disptype) { + int ix; + if ((ix = inst_get_disptype_index(it, dtype, 0)) < 0) { + it->del(it); + usage("Failed to locate display type matching '%c'",dtype); + } + + if ((rv = it->set_disptype(it, ix)) != inst_ok) { + printf("Setting display type ix %d not supported by instrument\n",ix); + it->del(it); + return -1; + } + } else + printf("Display/calibration type ignored - instrument doesn't support it\n"); + } + /* If we have non-standard observer we need spectral or CCSS */ if (obType != icxOT_default && !IMODETST(cap, inst_mode_spectral) && !(cap2 & inst2_ccss)) { printf("Non standard observer needs spectral information or CCSS capability\n"); @@ -1604,7 +1604,7 @@ int main(int argc, char *argv[]) { } #ifdef DEBUG - printf("read_sample returned '%s' (%s)\n", + printf("\nread_sample returned '%s' (%s)\n", it->inst_interp_error(it, rv), it->interp_error(it, rv)); #endif /* DEBUG */ @@ -1778,9 +1778,21 @@ int main(int argc, char *argv[]) { if (ch == 'S' || ch == 's') { /* Save last spectral into file */ if (sp.spec_n > 0) { char buf[500]; + xspect tsp; + + if (val.sp.spec_n <= 0) + error("Instrument didn't return spectral data"); + + tsp = val.sp; /* Temp. save spectral reading */ + + /* Compute FWA corrected spectrum */ + if (dofwa != 0) { + sp2cief[fidx]->sconvert(sp2cief[fidx], &tsp, NULL, &tsp); + } + printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout); if (getns(buf, 500) != NULL && strlen(buf) > 0) { - if(write_xspect(buf, &sp)) + if(write_xspect(buf, &tsp)) printf("\nWriting file '%s' failed\n",buf); else printf("\nWriting file '%s' succeeded\n",buf); @@ -2020,22 +2032,27 @@ int main(int argc, char *argv[]) { double yy[XSPECT_MAX_BANDS]; double yr[XSPECT_MAX_BANDS]; double xmin, xmax, ymin, ymax; + xspect trsp = rsp; xspect *ss; /* Spectrum range to use */ int nn; - if (rsp.spec_n > 0) { + if (dofwa != 0) { + sp2cief[fidx]->sconvert(sp2cief[fidx], &trsp, NULL, &tsp); + } + + if (trsp.spec_n > 0) { if ((tsp.spec_wl_long - tsp.spec_wl_short) > - (rsp.spec_wl_long - rsp.spec_wl_short)) + (trsp.spec_wl_long - trsp.spec_wl_short)) ss = &tsp; else - ss = &rsp; + ss = &trsp; } else ss = &tsp; - if (tsp.spec_n > rsp.spec_n) + if (tsp.spec_n > trsp.spec_n) nn = tsp.spec_n; else - nn = rsp.spec_n; + nn = trsp.spec_n; if (nn > XSPECT_MAX_BANDS) error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,nn); @@ -2050,7 +2067,7 @@ int main(int argc, char *argv[]) { yy[j] = value_xspect(&tsp, xx[j]); if (rLab[0] >= -1.0) { /* If there is a reference */ - yr[j] = value_xspect(&rsp, xx[j]); + yr[j] = value_xspect(&trsp, xx[j]); } } @@ -2317,9 +2334,17 @@ int main(int argc, char *argv[]) { #ifndef SALONEINSTLIB if (val.sp.spec_n > 0 && (ambient || doCCT)) { int invalid = 0; + double RR[14]; double cri; - cri = icx_CIE1995_CRI(&invalid, &sp); - printf(" Color Rendering Index (Ra) = %.1f%s\n",cri,invalid ? " (Invalid)" : ""); + cri = icx_CIE1995_CRI(&invalid, RR, &sp); + printf(" Color Rendering Index (Ra) = %.1f [ R9 = %.1f ]%s\n", + cri, RR[9-1], invalid ? " (Invalid)" : ""); + } + if (val.sp.spec_n > 0 && (ambient || doCCT)) { + int invalid = 0; + double tlci; + tlci = icx_EBU2012_TLCI(&invalid, &sp); + printf(" Television Lighting Consistency Index 2012 (Qa) = %.1f%s\n",tlci,invalid ? " (Invalid)" : ""); } #endif diff --git a/spectro/spyd2.c b/spectro/spyd2.c index 72c0b21..b546f6b 100644..100755 --- a/spectro/spyd2.c +++ b/spectro/spyd2.c @@ -925,7 +925,7 @@ spyd2_GetReading_ll( /* hence the transitions-1 counted. */ int *map; - int nat[8] = { 0,1,2,3,4,5,6,7 }; /* Natural order */ +// int nat[8] = { 0,1,2,3,4,5,6,7 }; /* Natural order */ int map3[8] = { 0,0,1,2,5,6,7,4 }; /* Map Sp3 sensors into Spyder 2 order */ int map4[8] = { 0,0,1,2,5,6,7,4 }; /* Map Sp4 sensors into Spyder 2 order */ int map5[8] = { 1,1,0,5,2,7,6,4 }; /* Map Sp5 sensors into Spyder 2 order */ @@ -1729,8 +1729,15 @@ spyd2_GetReading( /* Accumulate it for weighted average */ for (k = 0; k < 8; k++) { if (sensv[k] != 0.0) { /* Skip value where we didn't get any transitions */ +#ifndef NEVER + /* Accumulate it for weighted average */ a_sensv[k] += sensv[k] * itime; a_w[k] += itime; +#else + /* Just use the last measurement */ + a_sensv[k] = sensv[k] * itime; + a_w[k] = itime; +#endif } } @@ -1767,6 +1774,7 @@ spyd2_GetReading( } } + /* hwver == 5 hasn't been tested... */ if (p->hwver == 5) { double gainscale = 1.0; unsigned int v381; @@ -1781,7 +1789,7 @@ spyd2_GetReading( for (j = 0; j < 3; j++) { XYZ[j] = p->cal_A[p->icx & 1][j][0]; /* First entry is a constant */ for (k = 1; k < 8; k++) - XYZ[j] += a_sensv[k] * p->cal_A[p->icx & 1][j][k+2] * gainscale; + XYZ[j] += a_sensv[k] * p->cal_A[p->icx & 1][j][k+1] * gainscale; } } else { @@ -3268,7 +3276,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if ((*calt & inst_calt_ref_freq) && p->refrmode != 0) { - if (*calc != inst_calc_emis_80pc) { + if ((*calc & inst_calc_cond_mask) != inst_calc_emis_80pc) { *calc = inst_calc_emis_80pc; return inst_cal_setup; } @@ -3664,83 +3672,8 @@ static inst_disptypesel spyd4_disptypesel[8] = { 0, "f", "LCD, CCFL Backlight", - disptech_lcd_ccfl, - 0, - (1 << 1) | 1 - }, - { - inst_dtflags_none, /* flags */ - 0, - "L", - "Wide Gamut LCD, CCFL Backlight", - 0, - disptech_lcd_ccfl_wg, - (2 << 1) | 1 - }, - { - inst_dtflags_none, /* flags */ - 0, - "e", - "LCD, White LED Backlight", - disptech_lcd_wled, - 0, - (3 << 1) | 1 - }, - { - inst_dtflags_none, /* flags */ - 0, - "B", - "Wide Gamut LCD, RGB LED Backlight", - 0, - disptech_lcd_rgbled, - (4 << 1) | 1 - }, - { - inst_dtflags_none, /* flags */ - 0, - "x", - "LCD, CCFL Backlight (Laptop ?)", 0, disptech_lcd_ccfl, - (5 << 1) | 1 - }, - { - inst_dtflags_end, - 0, - "", - "", - 0, - disptech_none, - 0 - } -}; - -static inst_disptypesel spyd5_disptypesel[8] = { - { - inst_dtflags_default, - 1, - "nl", - "Generic Non-Refresh Display", - 0, - disptech_lcd, - 1 - }, - { - inst_dtflags_none, /* flags */ - 2, /* cbid */ - "rc", /* sel */ - "Generic Refresh Display", /* desc */ - 1, /* refr */ - disptech_crt, /* disptype */ - 1 /* ix = hw bit + spec table << 1 */ - }, - { - inst_dtflags_none, /* flags */ - 0, - "f", - "LCD, CCFL Backlight", - disptech_lcd_ccfl, - 0, (1 << 1) | 1 }, { @@ -3757,8 +3690,8 @@ static inst_disptypesel spyd5_disptypesel[8] = { 0, "e", "LCD, White LED Backlight", - disptech_lcd_wled, 0, + disptech_lcd_wled, (3 << 1) | 1 }, { @@ -3799,6 +3732,7 @@ static void set_base_disptype_list(spyd2 *p) { } else { /* spyd4_nocals == 6 or 7, Spyder 4 or 5. */ /* Spyder 5 has exactly the same list as the Spyder 4, with an extra */ /* entry at the end that is the same as the first (flat spectrum). */ + /* So use the spyder 4 list */ p->_dtlist = spyd4_disptypesel; } } else if (p->itype == instSpyder3) { @@ -3819,7 +3753,7 @@ int recreate /* nz to re-check for new ccmx & ccss files */ spyd2 *p = (spyd2 *)pp; inst_code rv = inst_ok; - /* Create/Re-create a current list of abailable display types */ + /* Create/Re-create a current list of available display types */ if (p->dtlist == NULL || recreate) { if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist, p->_dtlist, p->hwver >= 7 ? 1 : 0 /* doccss*/, 1 /* doccmx */)) != inst_ok) @@ -3838,7 +3772,6 @@ int recreate /* nz to re-check for new ccmx & ccss files */ /* Given a display type entry, setup for that type */ static inst_code set_disp_type(spyd2 *p, inst_disptypesel *dentry) { inst_code ev; - int refrmode; p->icx = dentry->ix; p->dtech = dentry->dtech; @@ -3969,8 +3902,9 @@ int *cbid) { spyd2 *p = (spyd2 *)pp; if (dtech != NULL) *dtech = p->dtech; - if (refrmode != NULL) + if (refrmode != NULL) { *refrmode = p->refrmode; + } if (cbid != NULL) *cbid = p->cbid; return inst_ok; @@ -4142,7 +4076,7 @@ extern spyd2 *new_spyd2(icoms *icom, instType itype) { p->del = spyd2_del; p->icom = icom; - p->itype = icom->itype; + p->itype = itype; /* Load manufacturers Spyder4 calibrations */ if (itype == instSpyder4 diff --git a/spectro/spyd2.h b/spectro/spyd2.h index 923234f..923234f 100644..100755 --- a/spectro/spyd2.h +++ b/spectro/spyd2.h diff --git a/spectro/ss.c b/spectro/ss.c index e01dd7a..90720ca 100644..100755 --- a/spectro/ss.c +++ b/spectro/ss.c @@ -1411,7 +1411,8 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ if (p->noinitcalib == 0) { /* Make sure we're in a condition to do the calibration */ - if (p->itype == instSpectrolino && *calc != inst_calc_man_ref_white) { + if (p->itype == instSpectrolino + && (*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) { *calc = inst_calc_man_ref_white; a1logd(p->log, 3, "ss cal need cond. inst_calc_man_ref_white and haven't got it\n"); return inst_cal_setup; @@ -1519,7 +1520,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ a1logd(p->log, 3, "ss cal need trans, spectrolino\n"); /* Make sure we're in a condition to do the calibration */ - if (*calc != inst_calc_man_trans_white) { + if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_white) { *calc = inst_calc_man_trans_white; a1logd(p->log, 3, "ss cal need cond. inst_calc_man_trans_white and haven't got it\n"); return inst_cal_setup; @@ -2074,7 +2075,7 @@ extern ss *new_ss(icoms *icom, instType itype) { /* Init state */ p->icom = icom; - p->itype = icom->itype; + p->itype = itype; p->cap = inst_mode_none; /* Unknown until initialised */ p->mode = inst_mode_none; /* Not in a known mode yet */ p->nextmode = inst_mode_none; /* Not in a known mode yet */ diff --git a/spectro/ss.h b/spectro/ss.h index bff0846..bff0846 100644..100755 --- a/spectro/ss.h +++ b/spectro/ss.h diff --git a/spectro/ss_imp.c b/spectro/ss_imp.c index 6f184b3..6f184b3 100644..100755 --- a/spectro/ss_imp.c +++ b/spectro/ss_imp.c diff --git a/spectro/ss_imp.h b/spectro/ss_imp.h index c298e80..c298e80 100644..100755 --- a/spectro/ss_imp.h +++ b/spectro/ss_imp.h diff --git a/spectro/strange.cal b/spectro/strange.cal new file mode 100755 index 0000000..06725b0 --- /dev/null +++ b/spectro/strange.cal @@ -0,0 +1,272 @@ +CAL + +DESCRIPTOR "Argyll Device Calibration Curves" +ORIGINATOR "Argyll synthcal" +CREATED "Tue Aug 18 00:14:21 2015" +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..75d18be 100644..100755 --- a/spectro/synthcal.c +++ b/spectro/synthcal.c diff --git a/spectro/synthread.c b/spectro/synthread.c index 3a23c31..3a23c31 100644..100755 --- a/spectro/synthread.c +++ b/spectro/synthread.c diff --git a/spectro/usbio.c b/spectro/usbio.c index 508b357..668544a 100644..100755 --- a/spectro/usbio.c +++ b/spectro/usbio.c @@ -369,12 +369,14 @@ int nwch, /* if > 0, number of characters to write */ double tout) { int len, wbytes; - long toc, i, top; /* Timout count, counter, timeout period */ + long ttop, top; /* Total timeout period, timeout period */ + unsigned int stime, etime; /* Start and end times of USB operation */ int ep = p->wr_ep; /* End point */ icom_usb_trantype type; /* bulk or interrupt */ int retrv = ICOM_OK; - a1logd(p->log, 8, "\nicoms_usb_ser_write: writing '%s'\n",icoms_fix(wbuf)); + a1logd(p->log, 8, "\nicoms_usb_ser_write: writing '%s'\n", + nwch > 0 ? icoms_tohex((unsigned char *)wbuf, nwch) : icoms_fix(wbuf)); if (!p->is_open) { a1loge(p->log, ICOM_SYS, "icoms_usb_ser_write: device is not open\n"); @@ -401,36 +403,39 @@ double tout) len = nwch; else len = strlen(wbuf); - tout *= 1000.0; /* Timout in msec */ - top = (int)(tout + 0.5); /* Timeout period in msecs */ - toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */ - if (toc < 1) - toc = 1; + ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ + + a1logd(p->log, 8, "\nicoms_usb_ser_write: ep 0x%x, bytes %d, ttop %d, quant %d\n", p->rd_ep, len, ttop, p->rd_qa); + + etime = stime = msec_time(); /* Until data is all written, we time out, or the user aborts */ - for (i = toc; i > 0 && len > 0;) { + for (top = ttop; top > 0 && len > 0;) { int c, rv; - a1logd(p->log, 8, "icoms_usb_ser_write: attempting to write %d bytes to usb top = %d, i = %d\n",len,top,i); + a1logd(p->log, 8, "icoms_usb_ser_write: attempting to write %d bytes to usb top = %d\n",len,top); rv = icoms_usb_transaction(p, NULL, &wbytes, type, (unsigned char)ep, (unsigned char *)wbuf, len, top); + etime = msec_time(); if (rv != ICOM_OK) { if (rv != ICOM_TO) { retrv |= rv; break; } - i--; /* timeout */ } else { /* Account for bytes written */ a1logd(p->log, 8, "icoms_usb_ser_write: wrote %d bytes\n",wbytes); - i = toc; wbuf += wbytes; len -= wbytes; } + top = ttop - (etime - stime); /* Remaining time */ } - if (i <= 0) /* Must have timed out */ + + if (top <= 0) { /* Must have timed out */ + a1logd(p->log, 8, "icoms_usb_ser_write: timeout, took %d msec out of %d\n",etime - stime,ttop); retrv |= ICOM_TO; + } - a1logd(p->log, 8, "icoms_usb_ser_write: returning ICOM err 0x%x\n",retrv); + a1logd(p->log, 8, "icoms_usb_ser_write: took %d msec, returning ICOM err 0x%x\n",etime - stime,retrv); return retrv; } @@ -447,7 +452,7 @@ char *rbuf, /* Buffer to store characters read */ int bsize, /* Buffer size */ int *pbread, /* Bytes read (not including forced '\000') */ char *tc, /* Terminating characers, NULL for none or char count mode */ -int ntc, /* Number of terminating characters or char count needed, if 0 use bsize */ +int ntc, /* Number of terminating characters or char count needed */ double tout) /* Time out in seconds */ { int j, rbytes; @@ -504,12 +509,11 @@ double tout) /* Time out in seconds */ bsize -= 1; /* Allow space for null */ bsize -= p->ms_bytes; /* Allow space for modem status bytes */ - /* Until data is all read, we time out, or the user aborts */ - etime = stime = msec_time(); - top = ttop; j = (tc == NULL && ntc <= 0) ? -1 : 0; + etime = stime = msec_time(); - for (nreads = 0; top > 0 && bsize > 0 && j < ntc ;) { + /* Until data is all read, we time out, or the user aborts */ + for (top = ttop, nreads = 0; top > 0 && bsize > 0 && j < ntc ;) { int c, rv; int rsize = bsize; @@ -571,7 +575,6 @@ double tout) /* Time out in seconds */ retrv |= rv; break; } - top = ttop - (etime - stime); /* Remaining time */ } @@ -583,12 +586,12 @@ double tout) /* Time out in seconds */ /* If ran out of time and not completed */ a1logd(p->log, 8, "icoms_usb_ser_read: took %d msec\n",etime - stime); if (top <= 0 && bsize > 0 && j < ntc) { - a1logd(p->log, 8, "icoms_usb_ser_read: read ran out of time\n"); - a1logd(p->log, 8, "ttop %d, etime - stime %d\n",ttop,etime - stime); + a1logd(p->log, 8, "icoms_usb_ser_read: timeout, took %d msec out of %d\n",etime - stime,ttop); retrv |= ICOM_TO; } - a1logd(p->log, 8, "icoms_usb_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),retrv); + a1logd(p->log, 8, "icoms_usb_ser_read: took %d msec, returning '%s' ICOM err 0x%x\n", + etime - stime, tc == NULL && ntc > 0 ? icoms_tohex((unsigned char*)rrbuf, rbuf - rrbuf) : icoms_fix(rrbuf), retrv); return retrv; } diff --git a/spectro/usbio.h b/spectro/usbio.h index 578bd83..578bd83 100644..100755 --- a/spectro/usbio.h +++ b/spectro/usbio.h diff --git a/spectro/usbio_bsd.c b/spectro/usbio_bsd.c index 0af13a1..0af13a1 100644..100755 --- a/spectro/usbio_bsd.c +++ b/spectro/usbio_bsd.c diff --git a/spectro/usbio_lx.c b/spectro/usbio_lx.c index 7cc37e6..cb9ec59 100644..100755 --- a/spectro/usbio_lx.c +++ b/spectro/usbio_lx.c @@ -606,7 +606,7 @@ static int cancel_req(icoms *p, usbio_req *req, int thisurb) { int ev; // ~~99 can we skip done, errored or cancelled urbs ? // Does it matter if there is a race between cancellers ? */ - a1logd(p->log, 7, "cancel_req %d\n",i); + a1logd(p->log, 8, "cancel_req %d\n",i); ev = ioctl(p->usbd->fd, USBDEVFS_DISCARDURB, &req->urbs[i].urb); if (ev != 0 && ev != EINVAL) { /* Hmmm */ @@ -627,7 +627,7 @@ static void *urb_reaper(void *context) { int rv; struct pollfd pa[2]; /* Poll array to monitor urb result or shutdown */ - a1logd(p->log, 6, "urb_reaper: reap starting\n"); + a1logd(p->log, 8, "urb_reaper: reap starting\n"); /* Wait for a URB, and signal the requester */ for (;;) { @@ -668,7 +668,7 @@ static void *urb_reaper(void *context) { /* Hmm. poll returned without event from fd. */ if (pa[0].revents == 0) { - a1logd(p->log, 6, "urb_reaper: poll returned events %d %d - ignoring\n", + a1logd(p->log, 8, "urb_reaper: poll returned events %d %d - ignoring\n", pa[0].revents,pa[1].revents); continue; } @@ -677,15 +677,15 @@ static void *urb_reaper(void *context) { rv = ioctl(p->usbd->fd, USBDEVFS_REAPURBNDELAY, &out); if (rv == EAGAIN) { - a1logd(p->log, 2, "urb_reaper: reap returned EAGAIN - ignored\n"); + a1logd(p->log, 8, "urb_reaper: reap returned EAGAIN - ignored\n"); continue; } if (rv < 0) { - a1logd(p->log, 2, "urb_reaper: reap failed with %d\n",rv); + a1logd(p->log, 8, "urb_reaper: reap failed with %d\n",rv); if (errc++ < 5) { continue; } - a1logd(p->log, 2, "urb_reaper: reap failed too many times - shutting down\n"); + a1logd(p->log, 8, "urb_reaper: reap failed too many times - shutting down\n"); p->usbd->shutdown = 1; break; } @@ -693,7 +693,7 @@ static void *urb_reaper(void *context) { errc = 0; if (out == NULL) { - a1logd(p->log, 2, "urb_reaper: reap returned NULL URB - ignored\n"); + a1logd(p->log, 8, "urb_reaper: reap returned NULL URB - ignored\n"); continue; } @@ -710,7 +710,7 @@ static void *urb_reaper(void *context) { if (req->nourbs > 0 && !req->cancelled && ((out->actual_length < out->buffer_length) || (out->status < 0 && out->status != -ECONNRESET))) { - a1logd(p->log, 6, "urb_reaper: reaper canceling failed or done urb's\n",rv); + a1logd(p->log, 8, "urb_reaper: reaper canceling failed or done urb's\n",rv); if (cancel_req(p, req, iurb->urbno) != ICOM_OK) { pthread_mutex_unlock(&req->lock); /* Is this fatal ? Assume so for the moment ... */ @@ -749,7 +749,7 @@ static void *urb_reaper(void *context) { req = req->next; } pthread_mutex_unlock(&p->usbd->lock); - a1logd(p->log, 1, "urb_reaper: cleared requests\n"); + a1logd(p->log, 8, "urb_reaper: cleared requests\n"); } p->usbd->running = 0; @@ -834,7 +834,7 @@ static int icoms_usb_transaction( bp += req.urbs[i].urb.buffer_length; req.urbs[i].urb.status = -EINPROGRESS; } -a1logd(p->log, 8, "icoms_usb_transaction: reset req %p nourbs to %d\n",&req,req.nourbs); + a1logd(p->log, 8, "icoms_usb_transaction: reset req %p nourbs to %d\n",&req,req.nourbs); /* Add our request to the req list so that it can be cancelled on reap failure */ pthread_mutex_lock(&p->usbd->lock); diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c index 8eb791f..8daac0d 100644..100755 --- a/spectro/usbio_nt.c +++ b/spectro/usbio_nt.c @@ -316,7 +316,7 @@ icompaths *p sprintf(pname,"%s (%s)", dpath + 4, inst_name(itype)); if ((usbd->dpath = strdup(dpath)) == NULL) { - a1loge(p->log, ICOM_SYS, "usb_check_and_add: strdup path failed!\n"); + a1loge(p->log, ICOM_SYS, "usb_get_paths: strdup path failed!\n"); free(usbd); return ICOM_SYS; } diff --git a/spectro/usbio_ox.c b/spectro/usbio_ox.c index 312c355..d3da59a 100644..100755 --- a/spectro/usbio_ox.c +++ b/spectro/usbio_ox.c @@ -91,18 +91,18 @@ icompaths *p CFRelease(lidpref); } - a1logd(p->log, 6, "usb_check_and_add: checking vid 0x%04x, pid 0x%04x, lid 0x%x\n",vid,pid,lid); + a1logd(p->log, 6, "usb_get_paths: checking vid 0x%04x, pid 0x%04x, lid 0x%x\n",vid,pid,lid); /* Do a preliminary match */ if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) { - a1logd(p->log, 6 , "usb_check_and_add: 0x%04x 0x%04x not reconized\n",vid,pid); + a1logd(p->log, 6 , "usb_get_paths: 0x%04x 0x%04x not reconized\n",vid,pid); IOObjectRelease(ioob); /* Release found object */ continue; } /* Allocate an idevice so that we can fill in the end point information */ if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) { - a1loge(p->log, ICOM_SYS, "icoms: calloc failed!\n"); + a1loge(p->log, ICOM_SYS, "usb_get_paths: calloc failed!\n"); return ICOM_SYS; } @@ -115,7 +115,7 @@ icompaths *p kIORegistryIterateRecursively, &it1)) != KERN_SUCCESS) { IOObjectRelease(ioob); IOObjectRelease(mit); - a1loge(p->log, kstat, "usb_check_and_add: IORegistryEntryCreateIterator() with %d\n",kstat); + a1loge(p->log, kstat, "usb_get_paths: IORegistryEntryCreateIterator() with %d\n",kstat); return ICOM_SYS; } usbd->nifce = 0; @@ -162,7 +162,7 @@ icompaths *p && p->paths[i]->pid == pid && p->paths[i]->hidd != NULL && p->paths[i]->hidd->lid == lid) { - a1logd(p->log, 1, "usb_check_and_add: Ignoring device because it is already in list as HID\n"); + a1logd(p->log, 1, "usb_get_paths: Ignoring device because it is already in list as HID\n"); break; } } @@ -172,7 +172,7 @@ icompaths *p } else { - a1logd(p->log, 1, "usb_check_and_add: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid); + a1logd(p->log, 1, "usb_get_paths: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid); usbd->lid = lid; usbd->ioob = ioob; diff --git a/spectro/vinflate.c b/spectro/vinflate.c index 847fa28..847fa28 100644..100755 --- a/spectro/vinflate.c +++ b/spectro/vinflate.c diff --git a/spectro/webwin.c b/spectro/webwin.c index e00fd9b..e13981a 100644..100755 --- a/spectro/webwin.c +++ b/spectro/webwin.c @@ -16,18 +16,6 @@ #include <stdio.h> #include <string.h> -#ifdef NT -# include <winsock2.h> -#endif -#ifdef UNIX -# include <sys/types.h> -# include <ifaddrs.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# if defined(__FreeBSD__) || defined(__OpenBSD__) -# include <sys/socket.h> -# endif /* __FreeBSD__ */ -#endif #include "copyright.h" #include "aconfig.h" #include "icc.h" @@ -263,9 +251,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */ return 0; } -/* Set/unset the blackground color flag */ +/* Set/unset the full screen black flag */ /* Return nz on error */ -static int webwin_set_bg(dispwin *p, int blackbg) { +static int webwin_set_fc(dispwin *p, int fullscreen) { return 1; /* Setting black BG not supported */ } @@ -319,7 +307,7 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ) { @@ -344,7 +332,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->nowin = nowin; p->native = native; p->out_tvenc = out_tvenc; - p->blackbg = blackbg; + p->fullscreen = fullscreen; p->ddebug = ddebug; p->get_ramdac = webwin_get_ramdac; p->set_ramdac = webwin_set_ramdac; @@ -352,7 +340,7 @@ int ddebug /* >0 to print debug statements to stderr */ p->uninstall_profile = webwin_uninstall_profile; p->get_profile = webwin_get_profile; p->set_color = webwin_set_color; - p->set_bg = webwin_set_bg; + p->set_fc = webwin_set_fc; p->set_update_delay = dispwin_set_update_delay; p->set_settling_delay = dispwin_set_settling_delay; p->enable_update_delay = dispwin_enable_update_delay; diff --git a/spectro/webwin.h b/spectro/webwin.h index 59b1d22..1f4412a 100644..100755 --- a/spectro/webwin.h +++ b/spectro/webwin.h @@ -29,7 +29,7 @@ int native, /* X0 = use current per channel calibration curve */ int *noramdac, /* Return nz if no ramdac access. native is set to X0 */ int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */ int out_tvenc, /* 1 = use RGB Video Level encoding */ -int blackbg, /* NZ if whole screen should be filled with black */ +int fullscreen, /* NZ if whole screen should be filled with black */ int verb, /* NZ for verbose prompts */ int ddebug /* >0 to print debug statements to stderr */ ); diff --git a/spectro/xdg_bds.c b/spectro/xdg_bds.c index c1805ed..c1805ed 100644..100755 --- a/spectro/xdg_bds.c +++ b/spectro/xdg_bds.c diff --git a/spectro/xdg_bds.h b/spectro/xdg_bds.h index 5c29790..5c29790 100644..100755 --- a/spectro/xdg_bds.h +++ b/spectro/xdg_bds.h |