From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- spectro/hcfr.c | 878 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100644 spectro/hcfr.c (limited to 'spectro/hcfr.c') diff --git a/spectro/hcfr.c b/spectro/hcfr.c new file mode 100644 index 0000000..9ec6be9 --- /dev/null +++ b/spectro/hcfr.c @@ -0,0 +1,878 @@ + +/* + * Argyll Color Correction System + * + * HCFR Association HCFR sensor related functions + * + * Author: Graeme W. Gill + * Date: 20/1/2007 + * + * Copyright 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. + */ + +/* + 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 +#include +#include +#include +#include +#include +#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 "hcfr.h" + +static inst_code hcfr_interp_code(inst *pp, int ec); + +#define MAX_MES_SIZE 500 /* Maximum normal message reply size */ +#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */ + +/* ==================================================================== */ + +/* Interpret an icoms error into a HCFR error */ +static int icoms2hcfr_err(int se) { + if (se != ICOM_OK) + return HCFR_COMS_FAIL; + return HCFR_OK; +} + +/* Do a standard command/response echange with the hcfr */ +/* Return the dtp error code */ +static inst_code +hcfr_command( + hcfr *p, + char *in, /* In string */ + char *out, /* Out string */ + int bsize, /* Out buffer size */ + double to /* Timeout in seconds */ +) { + int rv, se; + + if ((se = p->icom->write_read(p->icom, in, out, bsize, '\n', 1, to)) != 0) { + int ec; + a1logd(p->log, 1, "hcfr_command: serial i/o failure on write_read '%s'\n",icoms_fix(in)); + return hcfr_interp_code((inst *)p, icoms2hcfr_err(se)); + } + a1logd(p->log, 4, "hcfr_command: command '%s' returned '%s', value 0x%x\n", + icoms_fix(in), icoms_fix(out),HCFR_OK); + return hcfr_interp_code((inst *)p, HCFR_OK); +} + +/* Do a break to check coms is working */ +inst_code +hcfr_break( + hcfr *p +) { + int rwbytes; /* Data bytes read or written */ + int se, rv = inst_ok; + + se = p->icom->usb_control(p->icom, + IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_CLASS | IUSB_REQ_RECIP_INTERFACE, + 0x22, 0, 0, NULL, 0, 1.0); + + rv = hcfr_interp_code((inst *)p, icoms2hcfr_err(se)); + + a1logd(p->log, 4, "hcfr_break: done, ICOM err 0x%x\n",se); + + return rv; +} + +/* Flush an pending messages from the device */ +inst_code +hcfr_flush( + hcfr *p +) { + icoms *c = p->icom; + char buf[MAX_MES_SIZE]; + inst_code ev = inst_ok; + int rv; + + for (rv = ICOM_OK;;) { + rv = c->read(c, buf, MAX_MES_SIZE, '\000', 100000, 0.05); + if (rv != ICOM_OK) + break; /* Expect timeout with nothing to read */ + } + a1logd(p->log, 5, "hcfr_flush: done\n"); + + return inst_ok; +} + +/* Get and check the firmware version */ +inst_code +hcfr_get_check_version( + hcfr *p, + int *pmaj, + int *pmin +) { + char ibuf[2]; + char buf[MAX_MES_SIZE]; + inst_code ev = inst_ok; + int maj, min; + + a1logd(p->log, 4, "hcfr_get_check_version: called\n"); + + if (p->gotcoms == 0) + return inst_internal_error; + + ibuf[0] = HCFR_GET_VERS; + ibuf[1] = 0x00; + + if ((ev = hcfr_command(p, ibuf, buf, MAX_MES_SIZE, 1.0)) != inst_ok) + return ev; + + if (strlen(buf) < 6) { + a1logd(p->log, 1, "hcfr_get_check_version: version string too short\n"); + return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE); + } + + if (sscanf(buf, "v%d.%d", &maj,&min) != 2) { + a1logd(p->log, 1, "hcfr_get_check_version: version string doesn't match format\n"); + return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE); + } + + if (maj != HCFR_FIRMWARE_MAJOR_VERSION || min < HCFR_FIRMWARE_MINOR_VERSION) { + a1logd(p->log, 1, "hcfr_get_check_version: version string out of range\n"); + return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE); + } + + a1logd(p->log, 4, "hcfr_get_check_version: got firmare version %d.%d\n",maj,min); + if (pmaj != NULL) + *pmaj = maj; + if (pmin != NULL) + *pmin = min; + + return inst_ok; +} + +/* Get a raw measurement value */ +inst_code +hcfr_get_rgb( + hcfr *p, + double rgb[3] /* return value */ +) { + char ibuf[2]; + char buf[MAX_MES_SIZE], *bp; + char vbuf[4]; + inst_code ev = inst_ok; + double mul, div; + double vals[8]; + int onesens = 0; + int i; + + a1logd(p->log, 3, "hcfr_get_rgb: called\n"); + + if (p->gotcoms == 0) + return inst_internal_error; + + ibuf[0] = HCFR_MEAS_RGB /* Read RGB */ + | HCFR_MEAS_SENS0 /* Use one sensors because it's faster */ +// | HCFR_MEAS_SENS1 + | HCFR_INTERLACE_0 +// | HCFR_FAST_MEASURE + ; + + ibuf[1] = 0x00; + + if ((ev = hcfr_command(p, ibuf, buf, MAX_MES_SIZE, 60.0)) != inst_ok) { + a1logd(p->log, 1, "hcfr_get_rgb: hcfr_command failed\n"); + return ev; + } + + if (strlen(buf) < 156) { + a1logd(p->log, 1, "hcfr_get_rgb: not enough bytes returned = expected %d, got %d\n",156,strlen(buf)); + return hcfr_interp_code((inst *)p, HCFR_BAD_READING); + } + + if (strncmp(buf, "RGB_1:", 6) == 0) + onesens = 1; + else if (strncmp(buf, "RGB_2:", 6) != 0) { + a1logd(p->log, 1, "hcfr_get_rgb: RGB_1 or RGB_2 not founde\n"); + return hcfr_interp_code((inst *)p, HCFR_BAD_READING); + } + + vbuf[3] = 0x00; + bp = buf + 6; + + strncpy(vbuf, bp, 3); div = (double)atoi(vbuf); bp += 3; + + strncpy(vbuf, bp, 3); mul = (double)atoi(vbuf); bp += 3; + + /* Compute all the possible values for 4 colors and 2 sensors */ + for (i = 0; i < 8; i++) { + unsigned int num, den; + + strncpy(vbuf, bp, 3); den = atoi(vbuf); bp += 3; + strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3; + strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3; + strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3; + + strncpy(vbuf, bp, 3); num = atoi(vbuf); bp += 3; + strncpy(vbuf, bp, 3); num = (num << 8) + atoi(vbuf); bp += 3; + + if (den == 0) /* Hmm. */ + vals[i] = -1.0; + else + vals[i] = 1e4 * (double)num * mul * div / (double)den; +// a1logd(p->log, 6,"vals[%d] = %f = num %d * mul %f * div %f / den %d\n", i, vals[i], num,mul,div,den); + } + if (onesens) { + rgb[0] = vals[0]; + rgb[1] = vals[1]; + rgb[2] = vals[2]; + } else { + rgb[0] = 0.5 * (vals[0] + vals[4]); + rgb[1] = 0.5 * (vals[1] + vals[5]); + rgb[2] = 0.5 * (vals[2] + vals[6]); + } + a1logd(p->log, 3, "hcfr_get_rgb: returning value %f %f %f\n",rgb[0],rgb[1],rgb[2]); + + return inst_ok; +} + +/* Compute the calibration matricies. */ +/* The basic calibration data is from my particular HCFR, measured */ +/* against one of my CRT and LCD displays, with the reference XYZ */ +/* derived from my i1pro. */ +inst_code +hcfr_comp_matrix( + hcfr *p +) { + double tmat[3][3]; + double xmat[3][3]; + double itmat[3][3]; + + /* CRT */ + + /* Red test patch, sensor then reference */ + tmat[0][0] = 71.71880890; + tmat[1][0] = 8.53740337; + tmat[2][0] = 3.08216218; + + xmat[0][0] = 21.988601; + xmat[1][0] = 12.131219; + xmat[2][0] = 1.312786; + + /* Green test patch, sensor then reference */ + tmat[0][1] = 6.26299108; + tmat[1][1] = 37.49843127; + tmat[2][1] = 15.91104086; + + xmat[0][1] = 13.677691; + xmat[1][1] = 28.870823; + xmat[2][1] = 5.636190; + + /* Blue test patch, sensor then reference */ + tmat[0][2] = 1.30620298; + tmat[1][2] = 4.62894673; + tmat[2][2] = 27.57654019; + + xmat[0][2] = 6.387302; + xmat[1][2] = 2.755360; + xmat[2][2] = 33.588242; + + /* Compute the inverse */ + if (icmInverse3x3(itmat, tmat)) + return hcfr_interp_code((inst *)p, HCFR_CALIB_CALC); + + /* Multiply by target values */ + icmMul3x3_2(p->crt, xmat, itmat); + + /* LCD */ + + /* Red test patch, sensor then reference */ + tmat[0][0] = 39.94356609; + tmat[1][0] = 11.59679928; + tmat[2][0] = 8.18430397; + + xmat[0][0] = 51.875052; + xmat[1][0] = 30.640815; + xmat[2][0] = 4.712397; + + /* Green test patch, sensor then reference */ + tmat[0][1] = 14.45920285; + tmat[1][1] = 33.82116329; + tmat[2][1] = 17.64558523; + + xmat[0][1] = 37.482638; + xmat[1][1] = 64.670821; + xmat[2][1] = 14.554874; + + /* Blue test patch, sensor then reference */ + tmat[0][2] = 8.29727493; + tmat[1][2] = 17.95182031; + tmat[2][2] = 38.20123872; + + xmat[0][2] = 25.098392; + xmat[1][2] = 23.719352; + xmat[2][2] = 108.134087; + + /* Compute the inverse */ + if (icmInverse3x3(itmat, tmat)) + return hcfr_interp_code((inst *)p, HCFR_CALIB_CALC); + + /* Multiply by target values */ + icmMul3x3_2(p->lcd, xmat, itmat); + + return inst_ok; +} + +/* ==================================================================== */ + +/* Establish communications with a HCFR */ +/* Return HCFR_COMS_FAIL on failure to establish communications */ +static inst_code +hcfr_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { + hcfr *p = (hcfr *) pp; + int rsize; + long etime; + int bi, i, se; + inst_code ev = inst_ok; + icomuflags usbflags = icomuf_no_open_clear | icomuf_detach; + +#if defined(__APPLE__) && defined(__i386__) + /* 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; +#endif + + a1logd(p->log, 2, "hcfr_init_coms: About to init USB\n"); + + if (p->icom->port_type(p->icom) != icomt_usb) { + a1logd(p->log, 1, "hcfr_init_coms: expect hcfr to be USB\n"); + return hcfr_interp_code((inst *)p, HCFR_UNKNOWN_MODEL); + } + + /* Set config, interface, "Serial" write & read end points */ + /* Note if we clear halt the interface hangs */ + if ((se = p->icom->set_usb_port(p->icom, 1, 0x03, 0x83, usbflags, 0, NULL)) != ICOM_OK) { + a1logd(p->log, 1, "hcfr_init_coms: set_usb_port failed ICOM err 0x%x\n",se); + return hcfr_interp_code((inst *)p, icoms2hcfr_err(se)); + } + + if ((ev = hcfr_break(p)) != inst_ok) { + a1logd(p->log, 1, "hcfr_init_coms: break failed\n"); + return ev; + } + p->gotcoms = 1; + + a1logd(p->log, 2, "hcfr_init_coms: inited coms OK\n"); + + return inst_ok; +} + +static inst_code set_default_disp_type(hcfr *p); + +/* Initialise the HCFR */ +/* return non-zero on an error, with dtp error code */ +static inst_code +hcfr_init_inst(inst *pp) { + hcfr *p = (hcfr *)pp; + static char buf[MAX_MES_SIZE]; + inst_code ev = inst_ok; + + a1logd(p->log, 2, "hcfr_init_inst: called\n"); + + if (p->gotcoms == 0) + return inst_internal_error; /* Must establish coms before calling init */ + +#ifndef NEVER /* Doesn't work with OSX ? */ +// hcfr_flush(p); +#endif + + if ((ev = hcfr_get_check_version(p, &p->maj, &p->min)) != inst_ok) { + a1logd(p->log, 1, "hcfr_init_inst: check_version failed\n"); + return ev; + } + + if ((ev = hcfr_comp_matrix(p)) != inst_ok) { + return ev; + } + + p->trig = inst_opt_trig_user; + + /* Setup the default display type */ + if ((ev = set_default_disp_type(p)) != inst_ok) { + return ev; + } + + p->inited = 1; + a1logd(p->log, 2, "hcfr_init_inst: instrument inited OK\n"); + + return inst_ok; +} + +/* Read a single sample */ +/* Return the dtp error code */ +static inst_code +hcfr_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 */ + hcfr *p = (hcfr *)pp; + inst_code ev; + double rgb[3]; + int user_trig = 0; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if (p->trig == inst_opt_trig_user) { + + if (p->uicallback == NULL) { + a1logd(p->log, 1, "hcfr: inst_opt_trig_user but no uicallback function set!\n"); + return inst_unsupported; + } + + for (;;) { + if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) { + if (ev == inst_user_abort) + return ev; /* Abort */ + if (ev == 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 + && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) + return ev; /* Abort */ + } + + if ((ev = hcfr_get_rgb(p, rgb)) != inst_ok) + return ev; + + if (p->ix == 0) { /* LCD */ + icmMulBy3x3(val->XYZ, p->lcd, rgb); + + } else if (p->ix == 1) { /* CRT */ + icmMulBy3x3(val->XYZ, p->crt, rgb); + + } else { /* Raw */ + val->XYZ[0] = rgb[0]; + val->XYZ[1] = rgb[1]; + val->XYZ[2] = rgb[2]; + } + + /* Apply the colorimeter correction matrix */ + icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ); + + /* This may not change anything since instrument may clamp */ + if (clamp) + icmClamp3(val->XYZ, val->XYZ); + + val->loc[0] = '\000'; + val->mtype = inst_mrt_emission; + val->XYZ_v = 1; /* These are absolute XYZ readings */ + val->sp.spec_n = 0; + val->duration = 0.0; + + if (user_trig) + return inst_user_trig; + return inst_ok; +} + +/* Insert a colorimetric correction matrix in the instrument XYZ readings */ +/* This is only valid for colorimetric instruments. */ +/* To remove the matrix, pass NULL for the filter filename */ +inst_code hcfr_col_cor_mat( +inst *pp, +double mtx[3][3] +) { + hcfr *p = (hcfr *)pp; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if (mtx == NULL) { + icmSetUnity3x3(p->ccmat); + } else { + if (p->cbid == 0) { + a1loge(p->log, 1, "hcfr: can't set col_cor_mat over non base display type\n"); + inst_wrong_setup; + } + icmCpy3x3(p->ccmat, mtx); + } + + return inst_ok; +} + +/* Error codes interpretation */ +static char * +hcfr_interp_error(inst *pp, int ec) { +// hcfr *p = (hcfr *)pp; + ec &= inst_imask; + switch (ec) { + case HCFR_INTERNAL_ERROR: + return "Internal software error"; + case HCFR_COMS_FAIL: + return "Communications failure"; + case HCFR_UNKNOWN_MODEL: + return "Not a HCFR or DTP52"; + case HCFR_DATA_PARSE_ERROR: + return "Data from DTP didn't parse as expected"; + + case HCFR_OK: + return "No device error"; + + case HCFR_BAD_READING: + return "Invalid reading"; + + case HCFR_BAD_FIRMWARE: + return "Bad firmware version"; + + case HCFR_CALIB_CALC: + return "Error computing calibration matrix"; + + default: + return "Unknown error code"; + } +} + + +/* Convert a machine specific error code into an abstract dtp code */ +static inst_code +hcfr_interp_code(inst *pp, int ec) { + hcfr *p = (hcfr *)pp; + + ec &= inst_imask; + switch (ec) { + + case HCFR_OK: + return inst_ok; + + case HCFR_CALIB_CALC: + return inst_internal_error | ec; + + case HCFR_COMS_FAIL: + return inst_coms_fail | ec; + + case HCFR_UNKNOWN_MODEL: + return inst_unknown_model | ec; + + case HCFR_DATA_PARSE_ERROR: + return inst_protocol_error | ec; + + case HCFR_BAD_READING: + return inst_misread | ec; + +// case HCFR_NEEDS_OFFSET_CAL: +// return inst_needs_cal | ec; + + case HCFR_BAD_FIRMWARE: + return inst_hardware_fail | ec; + } + return inst_other_error | ec; +} + +/* Destroy ourselves */ +static void +hcfr_del(inst *pp) { + hcfr *p = (hcfr *)pp; + if (p->icom != NULL) + p->icom->del(p->icom); + inst_del_disptype_list(p->dtlist, p->ndtlist); + free(p); +} + +/* Return the instrument mode capabilities */ +void hcfr_capabilities(inst *pp, +inst_mode *pcap1, +inst2_capability *pcap2, +inst3_capability *pcap3) { + hcfr *p = (hcfr *)pp; + inst_mode cap = 0; + inst2_capability cap2 = 0; + + cap |= inst_mode_emis_spot + | inst_mode_colorimeter + ; + + cap2 |= inst2_prog_trig + | inst2_user_trig + | inst2_disptype + | inst2_ccmx + ; + + if (pcap1 != NULL) + *pcap1 = cap; + if (pcap2 != NULL) + *pcap2 = cap2; + if (pcap3 != NULL) + *pcap3 = inst3_none; +} + +/* Check device measurement mode */ +inst_code hcfr_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; + + /* only display emission mode supported */ + if (!IMODETST(m, inst_mode_emis_spot)) { + return inst_unsupported; + } + + return inst_ok; +} + +/* Set device measurement mode */ +inst_code hcfr_set_mode(inst *pp, inst_mode m) { + inst_code ev; + + if ((ev = hcfr_check_mode(pp, m)) != inst_ok) + return ev; + + return inst_ok; +} + +inst_disptypesel hcfr_disptypesel[4] = { + { + inst_dtflags_default, + 0, + "l", + "LCD display", + 0, + 0 + }, + { + inst_dtflags_none, /* flags */ + 0, /* cbix */ + "c", /* sel */ + "CRT display", /* desc */ + 0, /* refr */ + 1 /* ix */ + }, + { + inst_dtflags_none, + 1, + "R", + "Raw Reading", + 0, + 2 + }, + { + inst_dtflags_end, + 0, + "", + "", + 0, + 0 + } +}; + +/* Get mode and option details */ +static inst_code hcfr_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 */ +) { + hcfr *p = (hcfr *)pp; + inst_code rv = inst_ok; + + /* Create/Re-create a current list of abailable display types */ + if (p->dtlist == NULL || recreate) { + if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist, + hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok) + return rv; + } + + if (pnsels != NULL) + *pnsels = p->ndtlist; + + if (psels != NULL) + *psels = p->dtlist; + + return inst_ok; +} + +/* Given a display type entry, setup for that type */ +static inst_code set_disp_type(hcfr *p, inst_disptypesel *dentry) { + + p->ix = dentry->ix; + p->refrmode = dentry->refr; + p->cbid = dentry->cbid; + + if (dentry->flags & inst_dtflags_ccmx) { + icmCpy3x3(p->ccmat, dentry->mat); + } else { + icmSetUnity3x3(p->ccmat); + } + + return inst_ok; +} + +/* Setup the default display type */ +static inst_code set_default_disp_type(hcfr *p) { + inst_code ev; + int i; + + if (p->dtlist == NULL) { + if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist, + hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok) + return ev; + } + + for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) { + if (p->dtlist[i].flags & inst_dtflags_default) + break; + } + if (p->dtlist[i].flags & inst_dtflags_end) { + a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n"); + return inst_internal_error; + } + if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) { + return ev; + } + + return inst_ok; +} + +/* Set the display type */ +static inst_code hcfr_set_disptype(inst *pp, int ix) { + hcfr *p = (hcfr *)pp; + inst_code ev; + inst_disptypesel *dentry; + + if (p->dtlist == NULL) { + if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist, + hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok) + return ev; + } + + if (ix < 0 || ix >= p->ndtlist) + return inst_unsupported; + + dentry = &p->dtlist[ix]; + + if ((ev = set_disp_type(p, dentry)) != inst_ok) { + return ev; + } + + return inst_ok; +} + +/* + * set or reset an optional mode + * + * Since there is no interaction with the instrument, + * was assume that all of these can be done before initialisation. + */ +static inst_code +hcfr_get_set_opt(inst *pp, inst_opt_type m, ...) { + hcfr *p = (hcfr *)pp; + inst_code ev = inst_ok; + + /* Record the trigger mode */ + if (m == inst_opt_trig_prog + || m == inst_opt_trig_user) { + p->trig = m; + return inst_ok; + } + + /* Get the display type information */ + if (m == inst_opt_get_dtinfo) { + va_list args; + int *refrmode, *cbid; + + va_start(args, m); + refrmode = va_arg(args, int *); + cbid = va_arg(args, int *); + va_end(args); + + if (refrmode != NULL) + *refrmode = p->refrmode; + if (cbid != NULL) + *cbid = p->cbid; + + return inst_ok; + } + + return inst_unsupported; +} + +/* Constructor */ +extern hcfr *new_hcfr(icoms *icom, instType itype) { + hcfr *p; + if ((p = (hcfr *)calloc(sizeof(hcfr),1)) == NULL) { + a1loge(icom->log, 1, "new_hcfr: malloc failed!\n"); + return NULL; + } + + p->log = new_a1log_d(icom->log); + + p->init_coms = hcfr_init_coms; + p->init_inst = hcfr_init_inst; + p->capabilities = hcfr_capabilities; + p->check_mode = hcfr_check_mode; + p->set_mode = hcfr_set_mode; + p->get_disptypesel = hcfr_get_disptypesel; + p->set_disptype = hcfr_set_disptype; + p->get_set_opt = hcfr_get_set_opt; + p->read_sample = hcfr_read_sample; + p->col_cor_mat = hcfr_col_cor_mat; + p->interp_error = hcfr_interp_error; + p->del = hcfr_del; + + p->icom = icom; + p->itype = icom->itype; + + icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */ + + return p; +} + + -- cgit v1.2.3