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/i1pro.c | 809 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 809 insertions(+) create mode 100644 spectro/i1pro.c (limited to 'spectro/i1pro.c') diff --git a/spectro/i1pro.c b/spectro/i1pro.c new file mode 100644 index 0000000..99dd61b --- /dev/null +++ b/spectro/i1pro.c @@ -0,0 +1,809 @@ + +/* + * Argyll Color Correction System + * + * Gretag i1Monitor & i1Pro related functions + * + * Author: Graeme W. Gill + * Date: 24/11/2006 + * + * Copyright 2006 - 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. + */ + +/* + TTBD + + + Should add extra filter compensation support. + + Should alias projector mode to display mode ?? + + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef SALONEINSTLIB +#include "copyright.h" +#include "aconfig.h" +#include "numlib.h" +#include "rspl.h" +#else /* SALONEINSTLIB */ +#include "sa_config.h" +#include "numsup.h" +#include "rspl1.h" +#endif /* SALONEINSTLIB */ +#include "xspect.h" +#include "insttypes.h" +#include "conv.h" +#include "icoms.h" +#include "i1pro.h" +#include "i1pro_imp.h" + +#define MAX_MES_SIZE 500 /* Maximum normal message reply size */ +#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */ + +/* Convert a machine specific error code into an abstract inst code */ +static inst_code i1pro_interp_code(i1pro *p, i1pro_code ec); + +/* ------------------------------------------------------------------------ */ + +/* Establish communications with a I1DISP */ +/* If it's a serial port, use the baud rate given, and timeout in to secs */ +/* Return DTP_COMS_FAIL on failure to establish communications */ +static inst_code +i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { + i1pro *p = (i1pro *) pp; + int rsize, se; + icomuflags usbflags = icomuf_none; +#ifdef __APPLE__ + /* If the X-Rite software has been installed, then there may */ + /* be a daemon process that has the device open. Kill that process off */ + /* so that we can open it here, before it re-spawns. */ + char *pnames[] = { +// "i1iSisDeviceService", + "i1ProDeviceService", + NULL + }; + int retries = 20; +#else /* !__APPLE__ */ + char **pnames = NULL; + int retries = 0; +#endif /* !__APPLE__ */ + + a1logd(p->log, 2, "i1pro_init_coms: called\n"); + + if (p->icom->port_type(p->icom) != icomt_usb) { + a1logd(p->log, 1, "i1pro_init_coms: wrong sort of coms!\n"); + return i1pro_interp_code(p, I1PRO_UNKNOWN_MODEL); + } + + a1logd(p->log, 2, "i1pro_init_coms: about to init USB\n"); + + /* Set config, interface, write end point, read end point, read quanta */ + /* ("serial" end points aren't used - the i1display uses USB control messages) */ + if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames)) + != ICOM_OK) { + a1logd(p->log, 1, "i1pro_init_coms: failed ICOM err 0x%x\n",se); + return i1pro_interp_code(p, icoms2i1pro_err(se)); + } + + a1logd(p->log, 2, "i1pro_init_coms: init coms has suceeded\n"); + + p->gotcoms = 1; + return inst_ok; +} + +static inst_code +i1pro_determine_capabilities(i1pro *p) { + + /* Set the base Monitor/Pro capabilities mask */ + p->cap = inst_mode_emis_spot + | inst_mode_emis_tele + | inst_mode_emis_strip /* Also likely to be light table reading */ + | inst_mode_trans_spot /* Support this manually using a light table */ + | inst_mode_trans_strip + | inst_mode_emis_nonadaptive + | inst_mode_colorimeter + | inst_mode_spectral + ; + + /* Set the Pro capabilities mask */ + if (p->itype == instI1Pro + || p->itype == instI1Pro2) { + p->cap |= inst_mode_ref_spot + | inst_mode_ref_strip + ; + } + + /* Set the Pro2 capabilities mask */ + if (p->itype == instI1Pro2) { + p->cap |= inst_mode_ref_uv + ; + } + + if (i1pro_imp_highres(p)) /* This is static */ + p->cap |= inst_mode_highres; + + if (i1pro_imp_ambient(p)) { /* This depends on the instrument */ + p->cap |= inst_mode_emis_ambient + | inst_mode_emis_ambient_flash + ; + } + + p->cap2 = inst2_prog_trig + | inst2_user_trig + | inst2_user_switch_trig + | inst2_bidi_scan + | inst2_has_scan_toll + | inst2_no_feedback + ; + + if (p->m != NULL) { + i1proimp *m = (i1proimp *)p->m; + i1pro_state *s = &m->ms[m->mmode]; + if (s->emiss) + p->cap2 |= inst2_emis_refr_meas; + } + + p->cap3 = inst3_none; + + return inst_ok; +} + +/* Initialise the I1PRO */ +/* return non-zero on an error, with inst error code */ +static inst_code +i1pro_init_inst(inst *pp) { + i1pro *p = (i1pro *)pp; + i1pro_code ev = I1PRO_OK; + + a1logd(p->log, 2, "i1pro_init_inst: called\n"); + + if (p->gotcoms == 0) + return i1pro_interp_code(p, I1PRO_INT_NO_COMS); /* Must establish coms before calling init */ + if ((ev = i1pro_imp_init(p)) != I1PRO_OK) { + a1logd(p->log, 1, "i1pro_init_inst: failed with 0x%x\n",ev); + return i1pro_interp_code(p, ev); + } + + p->inited = 1; + a1logd(p->log, 2, "i1pro_init_inst: instrument inited OK\n"); + + /* Now it's initied, we can get true capabilities */ + i1pro_determine_capabilities(p); + + return i1pro_interp_code(p, ev); +} + +static char *i1pro_get_serial_no(inst *pp) { + i1pro *p = (i1pro *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return i1pro_imp_get_serial_no(p); +} + +/* Read a set of strips */ +static inst_code +i1pro_read_strip( +inst *pp, +char *name, /* Strip name (7 chars) */ +int npatch, /* Number of patches in the pass */ +char *pname, /* Pass name (3 chars) */ +int sguide, /* Guide number */ +double pwid, /* Patch length in mm (DTP41) */ +double gwid, /* Gap length in mm (DTP41) */ +double twid, /* Trailer length in mm (DTP41T) */ +ipatch *vals) { /* Pointer to array of instrument patch values */ + i1pro *p = (i1pro *)pp; + i1pro_code rv; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + rv = i1pro_imp_measure(p, vals, npatch, 1); + + return i1pro_interp_code(p, rv); +} + +/* Read a single sample */ +static inst_code +i1pro_read_sample( +inst *pp, +char *name, /* Strip name (7 chars) */ +ipatch *val, /* Pointer to instrument patch value */ +instClamping clamp) { /* Clamp XYZ/Lab to be +ve */ + i1pro *p = (i1pro *)pp; + i1pro_code rv; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + rv = i1pro_imp_measure(p, val, 1, clamp); + + return i1pro_interp_code(p, rv); +} + +/* Read an emissive refresh rate */ +static inst_code +i1pro_read_refrate( +inst *pp, +double *ref_rate) { + i1pro *p = (i1pro *)pp; + i1pro_code rv; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + rv = i1pro_imp_meas_refrate(p, ref_rate); + + return i1pro_interp_code(p, rv); +} + +/* Return needed and available inst_cal_type's */ +static inst_code i1pro_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) { + i1pro *p = (i1pro *)pp; + i1pro_code rv; + + rv = i1pro_imp_get_n_a_cals(p, pn_cals, pa_cals); + return i1pro_interp_code(p, rv); +} + +/* Request an instrument calibration. */ +inst_code i1pro_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) */ +) { + i1pro *p = (i1pro *)pp; + i1pro_code rv; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + rv = i1pro_imp_calibrate(p, calt, calc, id); + return i1pro_interp_code(p, rv); +} + +/* Instrument specific error codes interpretation */ +static char * +i1pro_interp_error(inst *pp, i1pro_code ec) { +// i1pro *p = (i1pro *)pp; + ec &= inst_imask; + switch (ec) { + case I1PRO_INTERNAL_ERROR: + return "Internal software error"; + case I1PRO_COMS_FAIL: + return "Communications failure"; + case I1PRO_UNKNOWN_MODEL: + return "Not an i1 Pro"; + case I1PRO_DATA_PARSE_ERROR: + return "Data from i1 Display didn't parse as expected"; + + case I1PRO_USER_ABORT: + return "User abort"; + + case I1PRO_USER_TRIG: + return "User trigger"; + + case I1PRO_UNSUPPORTED: + return "Unsupported function"; + case I1PRO_CAL_SETUP: + return "Calibration retry with correct setup is needed"; + + case I1PRO_OK: + return "No device error"; + + case I1PRO_DATA_COUNT: + return "EEProm data count unexpectedly small"; + case I1PRO_DATA_BUFSIZE: + return "EEProm data buffer too small"; + case I1PRO_DATA_MAKE_KEY: + return "EEProm data creating key failed"; + case I1PRO_DATA_MEMORY: + return "EEProm memory alloc failure"; + case I1PRO_DATA_KEYNOTFOUND: + return "EEProm key value wasn't found"; + case I1PRO_DATA_WRONGTYPE: + return "EEProm key is the wrong type"; + case I1PRO_DATA_KEY_CORRUPT: + return "EEProm key table seems to be corrupted"; + case I1PRO_DATA_KEY_COUNT: + return "EEProm key table count is too big or small"; + case I1PRO_DATA_KEY_UNKNOWN: + return "EEProm unknown key type"; + case I1PRO_DATA_KEY_MEMRANGE: + return "EEProm key data is out of range of EEProm"; + case I1PRO_DATA_KEY_ENDMARK: + return "EEProm end section marker was missing"; + + case I1PRO_HW_HIGHPOWERFAIL: + return "Failed to switch to high power mode"; + case I1PRO_HW_EE_SIZE: + return "EEProm size is too small"; + case I1PRO_HW_EE_SHORTREAD: + return "Read less bytes for EEProm read than expected"; + case I1PRO_HW_EE_SHORTWRITE: + return "Wrote less bytes for EEProm write than expected"; + case I1PRO_HW_ME_SHORTREAD: + return "Read less bytes for measurement read than expected"; + case I1PRO_HW_ME_ODDREAD: + return "Read a number of bytes not a multiple of 256"; + case I1PRO_HW_SW_SHORTREAD: + return "Read less bytes for Switch read than expected"; + case I1PRO_HW_LED_SHORTWRITE: + return "Wrote fewer LED sequence bytes than expected"; + case I1PRO_HW_UNEX_SPECPARMS: + return "Instrument has unexpected spectral parameters"; + case I1PRO_HW_CALIBINFO: + return "Instrument calibration info is missing or corrupted"; + case I1PRO_WL_TOOLOW: + return "Wavelength calibration reading is too low"; + case I1PRO_WL_SHAPE: + return "Wavelength calibration reading shape is incorrect"; + case I1PRO_WL_ERR2BIG: + return "Wavelength calibration correction is excessive"; + + case I1PRO_RD_DARKREADINCONS: + return "Dark calibration reading is inconsistent"; + case I1PRO_RD_SENSORSATURATED: + return "Sensor is saturated"; + case I1PRO_RD_DARKNOTVALID: + return "Dark reading is not valid (too light)"; + case I1PRO_RD_NEEDS_CAL: + return "Mode needs calibration"; + case I1PRO_RD_WHITEREADINCONS: + return "White calibration reading is inconsistent"; + case I1PRO_RD_WHITEREFERROR: + return "White reference reading error"; + case I1PRO_RD_LIGHTTOOLOW: + return "Light level is too low"; + case I1PRO_RD_LIGHTTOOHIGH: + return "Light level is too high"; + case I1PRO_RD_SHORTMEAS: + return "Reading is too short"; + case I1PRO_RD_READINCONS: + return "Reading is inconsistent"; + case I1PRO_RD_TRANSWHITERANGE: + return "Transmission white reference is out of range"; + case I1PRO_RD_NOTENOUGHPATCHES: + return "Not enough patches"; + case I1PRO_RD_TOOMANYPATCHES: + return "Too many patches"; + case I1PRO_RD_NOTENOUGHSAMPLES: + return "Not enough samples per patch"; + case I1PRO_RD_NOFLASHES: + return "No flashes recognized"; + case I1PRO_RD_NOAMBB4FLASHES: + return "No ambient found before first flash"; + case I1PRO_RD_NOREFR_FOUND: + return "No refresh rate detected or failed to measure it"; + + case I1PRO_INT_NO_COMS: + return "Communications hasn't been established"; + case I1PRO_INT_EETOOBIG: + return "Read of EEProm is too big (> 65536)"; + case I1PRO_INT_ODDREADBUF: + return "Measurement read buffer is not a multiple of reading size"; + case I1PRO_INT_SMALLREADBUF: + return "Measurement read buffer is too small for initial measurement"; + case I1PRO_INT_INTTOOBIG: + return "Integration time is too big"; + case I1PRO_INT_INTTOOSMALL: + return "Integration time is too small"; + case I1PRO_INT_ILLEGALMODE: + return "Illegal measurement mode selected"; + case I1PRO_INT_ZEROMEASURES: + return "Number of measurements requested is zero"; + case I1PRO_INT_WRONGPATCHES: + return "Number of patches to match is wrong"; + case I1PRO_INT_MEASBUFFTOOSMALL: + return "Measurement exceeded read buffer"; + case I1PRO_INT_NOTIMPLEMENTED: + return "Support not implemented"; + case I1PRO_INT_NOTCALIBRATED: + return "Unexpectedely invalid calibration"; + case I1PRO_INT_NOINTERPDARK: + return "Need interpolated dark and don't have it"; + case I1PRO_INT_THREADFAILED: + return "Creation of thread failed"; + case I1PRO_INT_BUTTONTIMEOUT: + return "Button status read timed out"; + case I1PRO_INT_CIECONVFAIL: + return "Creating spectral to CIE converted failed"; + case I1PRO_INT_PREP_LOG_DATA: + return "Error in preparing log data"; + case I1PRO_INT_MALLOC: + return "Error in allocating memory"; + case I1PRO_INT_CREATE_EEPROM_STORE: + return "Error in creating EEProm store"; + case I1PRO_INT_SAVE_SUBT_MODE: + return "Can't save calibration if in subt mode"; + case I1PRO_INT_NO_CAL_TO_SAVE: + return "No calibration data to save"; + case I1PRO_INT_EEPROM_DATA_MISSING: + return "EEProm data is missing"; + case I1PRO_INT_NEW_RSPL_FAILED: + return "Creating RSPL object faild"; + case I1PRO_INT_CAL_SAVE: + return "Unable to save calibration to file"; + case I1PRO_INT_CAL_RESTORE: + return "Unable to restore calibration from file"; + case I1PRO_INT_CAL_TOUCH: + return "Unable to update calibration file modification time"; + case I1PRO_INT_ADARK_INVALID: + return "Adaptive dark calibration is invalid"; + case I1PRO_INT_NO_HIGH_GAIN: + return "Rev E mode doesn't have a high gain mode"; + case I1PRO_INT_ASSERT: + return "Assert fail"; + + default: + return "Unknown error code"; + } +} + + +/* Convert a machine specific error code into an abstract inst code */ +static inst_code +i1pro_interp_code(i1pro *p, i1pro_code ec) { + + ec &= inst_imask; + switch (ec) { + + case I1PRO_OK: + + return inst_ok; + + case I1PRO_COMS_FAIL: + return inst_coms_fail | ec; + + case I1PRO_UNKNOWN_MODEL: + return inst_unknown_model | ec; + + case I1PRO_DATA_PARSE_ERROR: + return inst_protocol_error | ec; + + case I1PRO_USER_ABORT: + return inst_user_abort; + + case I1PRO_USER_TRIG: + return inst_user_trig; + + case I1PRO_UNSUPPORTED: + return inst_unsupported | ec; + + case I1PRO_CAL_SETUP: + return inst_cal_setup | ec; + + case I1PRO_HW_HIGHPOWERFAIL: + case I1PRO_HW_EE_SHORTREAD: + case I1PRO_HW_ME_SHORTREAD: + case I1PRO_HW_ME_ODDREAD: + case I1PRO_HW_CALIBINFO: + return inst_hardware_fail | ec; + + case I1PRO_RD_DARKREADINCONS: + case I1PRO_RD_SENSORSATURATED: + case I1PRO_RD_DARKNOTVALID: + case I1PRO_RD_WHITEREADINCONS: + case I1PRO_RD_WHITEREFERROR: + case I1PRO_RD_LIGHTTOOLOW: + case I1PRO_RD_LIGHTTOOHIGH: + case I1PRO_RD_SHORTMEAS: + case I1PRO_RD_READINCONS: + case I1PRO_RD_TRANSWHITERANGE: + case I1PRO_RD_NOTENOUGHPATCHES: + case I1PRO_RD_TOOMANYPATCHES: + case I1PRO_RD_NOTENOUGHSAMPLES: + case I1PRO_RD_NOFLASHES: + case I1PRO_RD_NOAMBB4FLASHES: + case I1PRO_RD_NOREFR_FOUND: + return inst_misread | ec; + + case I1PRO_RD_NEEDS_CAL: + return inst_needs_cal | ec; + + case I1PRO_INT_NO_COMS: + case I1PRO_INT_EETOOBIG: + case I1PRO_INT_ODDREADBUF: + case I1PRO_INT_SMALLREADBUF: + case I1PRO_INT_INTTOOBIG: + case I1PRO_INT_INTTOOSMALL: + case I1PRO_INT_ILLEGALMODE: + case I1PRO_INT_ZEROMEASURES: + case I1PRO_INT_MEASBUFFTOOSMALL: + case I1PRO_INT_NOTIMPLEMENTED: + case I1PRO_INT_NOTCALIBRATED: + case I1PRO_INT_NOINTERPDARK: + case I1PRO_INT_THREADFAILED: + case I1PRO_INT_BUTTONTIMEOUT: + case I1PRO_INT_CIECONVFAIL: + case I1PRO_INT_PREP_LOG_DATA: + case I1PRO_INT_MALLOC: + case I1PRO_INT_CREATE_EEPROM_STORE: + case I1PRO_INT_SAVE_SUBT_MODE: + case I1PRO_INT_NO_CAL_TO_SAVE: + case I1PRO_INT_EEPROM_DATA_MISSING: + case I1PRO_INT_NEW_RSPL_FAILED: + case I1PRO_INT_CAL_SAVE: + case I1PRO_INT_CAL_RESTORE: + case I1PRO_INT_CAL_TOUCH: + case I1PRO_INT_ADARK_INVALID: + case I1PRO_INT_NO_HIGH_GAIN: + case I1PRO_INT_ASSERT: + return inst_internal_error | ec; + } + return inst_other_error | ec; +} + +/* Return the instrument capabilities */ +void i1pro_capabilities(inst *pp, +inst_mode *pcap1, +inst2_capability *pcap2, +inst3_capability *pcap3) { + i1pro *p = (i1pro *)pp; + + if (pcap1 != NULL) + *pcap1 = p->cap; + if (pcap2 != NULL) + *pcap2 = p->cap2; + if (pcap3 != NULL) + *pcap3 = p->cap3; +} + +/* Return the corresponding i1pro measurement mode, */ +/* or i1p_no_modes if invalid */ +static i1p_mode i1pro_convert_mode(i1pro *p, inst_mode m) { + i1p_mode mmode = 0; /* Instrument measurement mode */ + + /* Simple test */ + if (m & ~p->cap) { + return i1p_no_modes; + } + + if (IMODETST(m, inst_mode_ref_spot)) { + mmode = i1p_refl_spot; + } else if (IMODETST(m, inst_mode_ref_strip)) { + mmode = i1p_refl_scan; + } else if (IMODETST(m, inst_mode_trans_spot)) { + mmode = i1p_trans_spot; + } else if (IMODETST(m, inst_mode_trans_strip)) { + mmode = i1p_trans_scan; + } else if (IMODETST(m, inst_mode_emis_spot) + || IMODETST(m, inst_mode_emis_tele)) { + if (IMODETST(m, inst_mode_emis_nonadaptive)) + mmode = i1p_emiss_spot_na; + else + mmode = i1p_emiss_spot; + } else if (IMODETST(m, inst_mode_emis_strip)) { + mmode = i1p_emiss_scan; + } else if (IMODETST(m, inst_mode_emis_ambient) + && (p->cap & inst_mode_emis_ambient)) { + mmode = i1p_amb_spot; + } else if (IMODETST(m, inst_mode_emis_ambient_flash) + && (p->cap & inst_mode_emis_ambient_flash)) { + mmode = i1p_amb_flash; + } else { + return i1p_no_modes; + } + + return mmode; +} + +/* Check device measurement mode */ +inst_code i1pro_check_mode(inst *pp, inst_mode m) { + i1pro *p = (i1pro *)pp; + i1p_mode mmode = 0; /* Instrument measurement mode */ + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if (i1pro_convert_mode(p, m) == i1p_no_modes) + return inst_unsupported; + + return inst_ok; +} + +/* Set device measurement mode */ +inst_code i1pro_set_mode(inst *pp, inst_mode m) { + i1pro *p = (i1pro *)pp; + i1p_mode mmode; /* Instrument measurement mode */ + inst_code rv; + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + if ((mmode = i1pro_convert_mode(p, m)) == i1p_no_modes) + return inst_unsupported; + + if ((rv = i1pro_interp_code(p, i1pro_imp_set_mode(p, mmode, m))) != inst_ok) + return rv; + + i1pro_determine_capabilities(p); + + return inst_ok; +} + +/* + * 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 +i1pro_get_set_opt(inst *pp, inst_opt_type m, ...) +{ + i1pro *p = (i1pro *)pp; + + if (m == inst_opt_noinitcalib) { + va_list args; + int losecs = 0; + + va_start(args, m); + losecs = va_arg(args, int); + va_end(args); + + i1pro_set_noinitcalib(p, 1, losecs); + return inst_ok; + + } else if (m == inst_opt_initcalib) { + i1pro_set_noinitcalib(p, 0, 0); + 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) { + i1pro_set_trig(p, m); + return inst_ok; + } + + if (m == inst_opt_scan_toll) { + va_list args; + double toll_ratio = 1.0; + + va_start(args, m); + toll_ratio = va_arg(args, double); + va_end(args); + return i1pro_interp_code(p, i1pro_set_scan_toll(p, toll_ratio)); + } + + if (!p->gotcoms) + return inst_no_coms; + if (!p->inited) + return inst_no_init; + + /* Not sure if this can be set before init */ + if (m == inst_opt_highres) { + return i1pro_interp_code(p, i1pro_set_highres(p)); + } else if (m == inst_opt_stdres) { + return i1pro_interp_code(p, i1pro_set_stdres(p)); + } + + /* Return the filter */ + if (m == inst_stat_get_filter) { + i1proimp *imp = (i1proimp *)p->m; + inst_opt_filter *filt; + va_list args; + + va_start(args, m); + filt = va_arg(args, inst_opt_filter *); + va_end(args); + + *filt = inst_opt_filter_none; + + if (imp->physfilt == 0x82) + *filt = inst_opt_filter_UVCut; + + return inst_ok; + } + + /* Use default implementation of other inst_opt_type's */ + { + inst_code rv; + va_list args; + + va_start(args, m); + rv = inst_get_set_opt_def(pp, m, args); + va_end(args); + + return rv; + } +} + +/* Destroy ourselves */ +static void +i1pro_del(inst *pp) { + i1pro *p = (i1pro *)pp; + + del_i1proimp(p); + if (p->icom != NULL) + p->icom->del(p->icom); + free(p); +} + +/* Constructor */ +extern i1pro *new_i1pro(icoms *icom, instType itype) { + i1pro *p; + int rv; + if ((p = (i1pro *)calloc(sizeof(i1pro),1)) == NULL) { + a1loge(icom->log, 1, "new_i1pro: malloc failed!\n"); + return NULL; + } + + p->log = new_a1log_d(icom->log); + + /* Inst methods */ + p->init_coms = i1pro_init_coms; + p->init_inst = i1pro_init_inst; + p->capabilities = i1pro_capabilities; + p->get_serial_no = i1pro_get_serial_no; + p->check_mode = i1pro_check_mode; + p->set_mode = i1pro_set_mode; + p->get_set_opt = i1pro_get_set_opt; + p->read_strip = i1pro_read_strip; + p->read_sample = i1pro_read_sample; + p->read_refrate = i1pro_read_refrate; + p->get_n_a_cals = i1pro_get_n_a_cals; + p->calibrate = i1pro_calibrate; + p->interp_error = i1pro_interp_error; + p->del = i1pro_del; + + p->icom = icom; + p->itype = icom->itype; + + i1pro_determine_capabilities(p); + + if ((rv = add_i1proimp(p)) != I1PRO_OK) { + free(p); + a1loge(icom->log, 1, "new_i1pro: error %d creating i1proimp\n",rv); + return NULL; + } + + return p; +} + -- cgit v1.2.3