commit c75380c239b950eff540d9c8d4ede12c67d2d886 Author: Richard Hughes Date: Wed Nov 30 15:28:57 2011 +0000 Add an experimental ColorHug sensor driver diff --git a/libusb/55-Argyll.rules b/libusb/55-Argyll.rules index a3b3cd4..a047d26 100644 --- a/libusb/55-Argyll.rules +++ b/libusb/55-Argyll.rules @@ -46,6 +46,9 @@ ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0300", ENV{COLOR_MEASUREMENT_DEVICE} # Huey ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2005", ENV{COLOR_MEASUREMENT_DEVICE}="1" +# ColorHug +ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f8dA", ENV{COLOR_MEASUREMENT_DEVICE}="1" + # Let udev-acl and ConsoleKit manage these devices, if applicable TEST=="/lib/udev/udev-acl", TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1" diff --git a/spectro/colorhug.c b/spectro/colorhug.c new file mode 100644 index 0000000..90f1b7e --- /dev/null +++ b/spectro/colorhug.c @@ -0,0 +1,752 @@ +/* + * Argyll Color Correction System + * + * Hughski ColorHug related functions + * + * Author: Richard Hughes + * Date: 30/11/2011 + * + * Copyright 2006 - 2007, Graeme W. Gill + * Copyright 2011, Richard Hughes + * All rights reserved. + * + * (Based on huey.c) + * + * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :- + * see the License2.txt file for licencing details. + */ + +#include +#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 "icoms.h" +#include "conv.h" +#include "colorhug.h" + +static inst_code colorhug_interp_code(inst *pp, int ec); + +/* Interpret an icoms error into a ColorHug error */ +static int icoms2colorhug_err(int se) { + if (se & ICOM_USERM) { + se &= ICOM_USERM; + if (se == ICOM_USER) + return COLORHUG_USER_ABORT; + if (se == ICOM_TERM) + return COLORHUG_USER_TERM; + if (se == ICOM_TRIG) + return COLORHUG_USER_TRIG; + if (se == ICOM_CMND) + return COLORHUG_USER_CMND; + } + if (se != ICOM_OK) + return COLORHUG_COMS_FAIL; + return COLORHUG_OK; +} + +/* ColorHug commands that we care about */ +typedef enum { + ch_set_mult = 0x04, /* Set multiplier value */ + ch_set_integral = 0x06, /* Set integral time */ + ch_get_serial = 0x0b, /* Gets the serial number */ + ch_set_leds = 0x0e, /* Sets the LEDs */ + ch_take_reading = 0x23 /* Takes an XYZ reading */ +} ColorHugCmd; + +/* Diagnostic - return a description given the instruction code */ +static char *inst_desc(int cc) { + static char buf[40]; + switch(cc) { + case 0x04: + return "SetMultiplier"; + case 0x06: + return "SetIntegral"; + case 0x0b: + return "GetSerial"; + case 0x0e: + return "SetLeds"; + case 0x23: + return "TakeReadingXYZ"; + } + sprintf(buf,"Unknown %02x",cc); + return buf; +} + +/* Error codes interpretation */ +static char * +colorhug_interp_error(inst *pp, int ec) { + ec &= inst_imask; + switch (ec) { + case COLORHUG_INTERNAL_ERROR: + return "Internal software error"; + case COLORHUG_COMS_FAIL: + return "Communications failure"; + case COLORHUG_UNKNOWN_MODEL: + return "Not a known ColorHug Model"; + case COLORHUG_USER_ABORT: + return "User hit Abort key"; + case COLORHUG_USER_TERM: + return "User hit Terminate key"; + case COLORHUG_USER_TRIG: + return "User hit Trigger key"; + case COLORHUG_USER_CMND: + return "User hit a Command key"; + + case COLORHUG_OK: + return "OK"; + case COLORHUG_UNKNOWN_CMD: + return "Unknown connamd"; + case COLORHUG_WRONG_UNLOCK_CODE: + return "Wrong unlock code"; + case COLORHUG_NOT_IMPLEMENTED: + return "Not implemented"; + case COLORHUG_UNDERFLOW_SENSOR: + return "Sensor underflow"; + case COLORHUG_NO_SERIAL: + return "No serial"; + case COLORHUG_WATCHDOG: + return "Watchdog"; + case COLORHUG_INVALID_ADDRESS: + return "Invalid address"; + case COLORHUG_INVALID_LENGTH: + return "Invalid length"; + case COLORHUG_INVALID_CHECKSUM: + return "Invlid checksum"; + case COLORHUG_INVALID_VALUE: + return "Invalid value"; + case COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER: + return "Unknown command for bootloader"; + case COLORHUG_NO_CALIBRATION: + return "No calibration"; + case COLORHUG_OVERFLOW_MULTIPLY: + return "Multiply overflow"; + case COLORHUG_OVERFLOW_ADDITION: + return "Addition overflow"; + case COLORHUG_OVERFLOW_SENSOR: + return "Sensor overflow"; + case COLORHUG_OVERFLOW_STACK: + return "Stack overflow"; + + /* Internal errors */ + case COLORHUG_NO_COMS: + return "Communications hasn't been established"; + case COLORHUG_NOT_INITED: + return "Insrument hasn't been initialised"; + default: + return "Unknown error code"; + } +} + +/* Do a command/response exchange with the colorhug */ +static inst_code +colorhug_command(colorhug *p, + ColorHugCmd cmd, + unsigned char *in, uint in_size, + unsigned char *out, uint out_size, + double timeout) +{ + int i; + unsigned char buf[64]; + int wbytes; + int rbytes; + int se, ua = 0, rv = inst_ok; + int isdeb = 0; + + /* Turn off low level debug messages, and sumarise them here */ + isdeb = p->icom->debug; + if (isdeb <= 2) + p->icom->debug = 0; + + if (isdeb) { + fprintf(stderr,"colorhug: Sending cmd '%s' args '%s'\n", + inst_desc(cmd), icoms_tohex(in, in_size)); + } + + /* Send the command with any specified data */ + buf[0] = cmd; + if (in != NULL) + memcpy(buf + 1, in, in_size); + if (p->icom->is_hid) { + se = p->icom->hid_write(p->icom, buf, in_size + 1, &wbytes, timeout); + } else { + se = p->icom->usb_write(p->icom, 0x01, buf, in_size + 1, &wbytes, timeout); + } + if (se != 0) { + if (se & ICOM_USERM) { + ua = (se & ICOM_USERM); + } + if (se & ~ICOM_USERM) { + if (isdeb) + fprintf(stderr,"colorhug: Command send failed with ICOM err 0x%x\n", se); + p->icom->debug = isdeb; + return colorhug_interp_code((inst *)p, COLORHUG_COMS_FAIL); + } + } + rv = colorhug_interp_code((inst *)p, icoms2colorhug_err(ua)); + if (isdeb) + fprintf(stderr,"colorhug: ICOM err 0x%x\n",ua); + if (wbytes != in_size + 1) + rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_WR_LENGTH); + if (rv != inst_ok) { + p->icom->debug = isdeb; + return rv; + } + + /* Now fetch the response */ + if (isdeb) + fprintf(stderr,"colorhug: Reading response\n"); + + if (p->icom->is_hid) { + se = p->icom->hid_read(p->icom, buf, out_size + 2, &rbytes, timeout); + } else { + se = p->icom->usb_read(p->icom, 0x81, buf, out_size + 2, &rbytes, timeout); + } + + if (isdeb && rbytes >= 2) { + fprintf(stderr,"Recieved cmd '%s' error '%s' args '%s'\n", + inst_desc(buf[1]), + colorhug_interp_error((inst *) p, buf[0]), + icoms_tohex(buf, rbytes - 2)); + } + + if (se != 0) { + + /* deal with command error */ + if (rbytes == 2 && buf[0] != COLORHUG_OK) { + rv = colorhug_interp_code((inst *)p, buf[0]); + return rv; + } + + /* deal with underrun or overrun */ + if (rbytes != out_size + 2) { + rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_RD_LENGTH); + return rv; + } + + /* there's another reason it failed */ + if (se & ICOM_USERM) { + ua = (se & ICOM_USERM); + } + if (se & ~ICOM_USERM) { + if (isdeb) + fprintf(stderr,"colorhug: Response read failed with ICOM err 0x%x\n",se); + p->icom->debug = isdeb; + return colorhug_interp_code((inst *)p, COLORHUG_COMS_FAIL); + } + } + rv = colorhug_interp_code((inst *)p, icoms2colorhug_err(ua)); + if (rv != inst_ok) + return rv; + + /* check the command was the same */ + if (buf[1] != cmd) { + rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_RET_CMD); + return rv; + } + if (out != NULL) { + memcpy(out, buf + 2, out_size); + } + if (isdeb) { + fprintf(stderr,"colorhug: '%s' ICOM err 0x%x\n", + icoms_tohex(buf + 2, out_size),ua); + } + p->icom->debug = isdeb; + return rv; +} + +/* Take a short, and convert it into a byte buffer */ +static void short2buf(unsigned char *buf, int inv) +{ + buf[0] = (inv >> 0) & 0xff; + buf[1] = (inv >> 8) & 0xff; +} + +/* Converts a packed float to a double */ +static double packed_float_to_double (int32_t pf) +{ + return (double) pf / (double) 0x10000; +} + +/* Set the device LED state */ +static inst_code +colorhug_set_LEDs(colorhug *p, int mask) +{ + int i; + unsigned char ibuf[4]; + inst_code ev; + + mask &= 0x3; + p->led_state = mask; + + ibuf[0] = mask; + ibuf[1] = 0; /* repeat */ + ibuf[2] = 0; /* on */ + ibuf[3] = 0; /* off */ + + /* Do command */ + ev = colorhug_command(p, ch_set_leds, + ibuf, sizeof (ibuf), /* input */ + NULL, 0, /* output */ + 1.0); + return ev; +} + +/* Take a XYZ measurement from the device */ +static inst_code +colorhug_take_XYZ_measurement(colorhug *p, double XYZ[3]) +{ + inst_code ev; + int i; + uint8_t ibuf[2]; + uint32_t obuf[3]; + + if (!p->inited) + return colorhug_interp_code((inst *)p, COLORHUG_NOT_INITED); + + /* Choose the calibration matrix */ + short2buf(ibuf + 0, p->crt ? 65 : 64); + + /* Do the measurement, and return the values */ + ev = colorhug_command(p, ch_take_reading, + ibuf, sizeof (ibuf), + (unsigned char *) obuf, sizeof (obuf), + 5.0); + if (ev != inst_ok) + return ev; + + /* Convert to doubles */ + for (i = 0; i < 3; i++) + XYZ[i] = packed_float_to_double (obuf[i]); + + /* Apply the colorimeter correction matrix */ + icmMulBy3x3(XYZ, p->ccmat, XYZ); + + if (p->debug) { + fprintf(stderr,"colorhug: returning XYZ = %f %f %f\n", + XYZ[0],XYZ[1],XYZ[2]); + } + return inst_ok; +} + +/* Establish communications with a ColorHug */ +static inst_code +colorhug_init_coms(inst *pp, int port, baud_rate br, flow_control fc, double tout) { + colorhug *p = (colorhug *) pp; + + if (p->debug) { + p->icom->debug = p->debug; /* Turn on debugging */ + fprintf(stderr,"colorhug: About to init coms\n"); + } + + /* Open as an HID if available */ + if (p->icom->is_hid_portno(p->icom, port) != instUnknown) { + + if (p->debug) + fprintf(stderr,"colorhug: About to init HID\n"); + + /* Set config, interface */ + p->icom->set_hid_port(p->icom, port, icomuf_none, 0, NULL); + + } else if (p->icom->is_usb_portno(p->icom, port) != instUnknown) { + + if (p->debug) + fprintf(stderr,"colorhug: About to init USB\n"); + + /* Set config, interface, write end point, read end point */ + p->icom->set_usb_port(p->icom, port, 1, 0x00, 0x00, icomuf_detach, 0, NULL); + + } else { + if (p->debug) + fprintf(stderr,"colorhug: init_coms called to wrong device!\n"); + return colorhug_interp_code((inst *)p, COLORHUG_UNKNOWN_MODEL); + } + + if (p->debug) + fprintf(stderr,"colorhug: init coms has suceeded\n"); + + p->gotcoms = 1; + return inst_ok; +} + +/* Set the device multiplier */ +static inst_code +colorhug_set_multiplier (colorhug *p, int multiplier) +{ + inst_code ev; + unsigned char ibuf[1]; + + /* Set the desired multiplier */ + ibuf[0] = multiplier; + ev = colorhug_command(p, ch_set_mult, + ibuf, sizeof (ibuf), + NULL, 0, + 1.0); + return ev; +} + +/* Set the device integral time */ +static inst_code +colorhug_set_integral (colorhug *p, int integral) +{ + inst_code ev; + unsigned char ibuf[2]; + + /* Set the desired integral time */ + short2buf(ibuf + 0, integral); + ev = colorhug_command(p, ch_set_integral, + ibuf, sizeof (ibuf), + NULL, 0, + 1.0); + return ev; +} + +/* Initialise the ColorHug */ +static inst_code +colorhug_init_inst(inst *pp) +{ + colorhug *p = (colorhug *)pp; + inst_code ev; + + if (p->debug) + fprintf(stderr,"colorhug: About to init instrument\n"); + + /* Must establish coms first */ + if (p->gotcoms == 0) + return colorhug_interp_code((inst *)p, COLORHUG_NO_COMS); + + /* Turn the LEDs off */ + ev = colorhug_set_LEDs(p, 0x0); + if (ev != inst_ok) + return ev; + + /* Turn the sensor on */ + ev = colorhug_set_multiplier(p, 0x03); + if (ev != inst_ok) + return ev; + + /* Set the integral time to maximum precision */ + ev = colorhug_set_integral(p, 0xffff); + if (ev != inst_ok) + return ev; + + p->itype = instColorHug; + p->trig = inst_opt_trig_keyb; + p->inited = 1; + if (p->debug) + fprintf(stderr,"colorhug: instrument inited OK\n"); + + /* Flash the LEDs */ + ev = colorhug_set_LEDs(p, 0x1); + if (ev != inst_ok) + return ev; + msec_sleep(50); + ev = colorhug_set_LEDs(p, 0x2); + if (ev != inst_ok) + return ev; + msec_sleep(50); + ev = colorhug_set_LEDs(p, 0x1); + if (ev != inst_ok) + return ev; + msec_sleep(50); + ev = colorhug_set_LEDs(p, 0x0); + if (ev != inst_ok) + return ev; + + return ev; +} + +/* Read a single sample */ +static inst_code +colorhug_read_sample( +inst *pp, +char *name, /* Strip name (7 chars) */ +ipatch *val) { /* Pointer to instrument patch value */ + colorhug *p = (colorhug *)pp; + int user_trig = 0; + int rv = inst_protocol_error; + + if (p->trig == inst_opt_trig_keyb) { + int se; + if ((se = icoms_poll_user(p->icom, 1)) != ICOM_TRIG) { + /* Abort, term or command */ + return colorhug_interp_code((inst *)p, icoms2colorhug_err(se)); + } + user_trig = 1; + if (p->trig_return) + printf("\n"); + } + + /* Read the XYZ value */ + if ((rv = colorhug_take_XYZ_measurement(p, val->aXYZ)) != inst_ok) { + return rv; + } + + val->XYZ_v = 0; + val->aXYZ_v = 1; /* These are absolute XYZ readings ? */ + val->Lab_v = 0; + val->sp.spec_n = 0; + val->duration = 0.0; + + if (user_trig) + return inst_user_trig; + return rv; +} + +/* Insert a colorimetric correction matrix */ +inst_code colorhug_col_cor_mat( +inst *pp, +double mtx[3][3] +) { + colorhug *p = (colorhug *)pp; + + if (mtx == NULL) + icmSetUnity3x3(p->ccmat); + else + icmCpy3x3(p->ccmat, mtx); + + return inst_ok; +} + +/* Determine if a calibration is needed */ +inst_cal_type colorhug_needs_calibration(inst *pp) { + return inst_ok; +} + +/* Request an instrument calibration */ +inst_code colorhug_calibrate( +inst *pp, +inst_cal_type calt, /* Calibration type. inst_calt_all for all neeeded */ +inst_cal_cond *calc, /* Current condition/desired condition */ +char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ +) { + id[0] = '\000'; + return inst_unsupported; +} + +/* Convert a machine specific error code into an abstract dtp code */ +static inst_code +colorhug_interp_code(inst *pp, int ec) { + ec &= inst_imask; + switch (ec) { + + case COLORHUG_OK: + return inst_ok; + + case COLORHUG_INTERNAL_ERROR: + case COLORHUG_NO_COMS: + case COLORHUG_NOT_INITED: + return inst_internal_error | ec; + + case COLORHUG_COMS_FAIL: + return inst_coms_fail | ec; + + case COLORHUG_UNKNOWN_MODEL: + return inst_unknown_model | ec; + + case COLORHUG_UNKNOWN_CMD: + case COLORHUG_WRONG_UNLOCK_CODE: + case COLORHUG_NOT_IMPLEMENTED: + case COLORHUG_UNDERFLOW_SENSOR: + case COLORHUG_NO_SERIAL: + case COLORHUG_WATCHDOG: + case COLORHUG_INVALID_ADDRESS: + case COLORHUG_INVALID_LENGTH: + case COLORHUG_INVALID_CHECKSUM: + case COLORHUG_INVALID_VALUE: + case COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER: + case COLORHUG_NO_CALIBRATION: + case COLORHUG_OVERFLOW_MULTIPLY: + case COLORHUG_OVERFLOW_ADDITION: + case COLORHUG_OVERFLOW_SENSOR: + case COLORHUG_OVERFLOW_STACK: + case COLORHUG_BAD_WR_LENGTH: + case COLORHUG_BAD_RD_LENGTH: + case COLORHUG_BAD_RET_CMD: + case COLORHUG_BAD_RET_STAT: + return inst_protocol_error | ec; + + case COLORHUG_USER_ABORT: + return inst_user_abort | ec; + case COLORHUG_USER_TERM: + return inst_user_term | ec; + case COLORHUG_USER_TRIG: + return inst_user_trig | ec; + case COLORHUG_USER_CMND: + return inst_user_cmnd | ec; + } + return inst_other_error | ec; +} + +/* Destroy ourselves */ +static void +colorhug_del(inst *pp) { + colorhug *p = (colorhug *)pp; + if (p->icom != NULL) + p->icom->del(p->icom); + free(p); +} + +/* Return the instrument capabilities */ +inst_capability colorhug_capabilities(inst *pp) { + colorhug *p = (colorhug *)pp; + inst_capability rv; + + rv = inst_emis_spot + | inst_emis_disp + | inst_emis_disp_lcd + | inst_colorimeter + | inst_ccmx + ; + + return rv; +} + +/* Return the instrument capabilities 2 */ +inst2_capability colorhug_capabilities2(inst *pp) { + colorhug *p = (colorhug *)pp; + inst2_capability rv = 0; + + rv |= inst2_prog_trig; + rv |= inst2_keyb_trig; + rv |= inst2_has_leds; + + return rv; +} + +/* Set device measurement mode */ +inst_code colorhug_set_mode(inst *pp, inst_mode m) +{ + colorhug *p = (colorhug *)pp; + inst_mode mm; /* Measurement mode */ + + /* The measurement mode portion of the mode */ + mm = m & inst_mode_measurement_mask; + + /* only display emission mode and ambient supported */ + if (mm != inst_mode_emis_spot + && mm != inst_mode_emis_disp + && mm != inst_mode_emis_ambient) { + return inst_unsupported; + } + + /* Spectral mode is not supported */ + if (m & inst_mode_spectral) + return inst_unsupported; + + p->mode = m; + return inst_ok; +} + +/* Set or reset an optional mode */ +static inst_code +colorhug_set_opt_mode(inst *pp, inst_opt_mode m, ...) +{ + colorhug *p = (colorhug *)pp; + inst_code ev = inst_ok; + + /* Select CRT/LCD */ + if (m == inst_opt_disp_crt) { + if (p->crt == 0) + p->crt = 1; + return inst_ok; + } else if (m == inst_opt_disp_lcd) { + if (p->crt != 0) + p->crt = 0; + return inst_ok; + + } + /* Record the trigger mode */ + if (m == inst_opt_trig_prog + || m == inst_opt_trig_keyb) { + p->trig = m; + return inst_ok; + } + if (m == inst_opt_trig_return) { + p->trig_return = 1; + return inst_ok; + } else if (m == inst_opt_trig_no_return) { + p->trig_return = 0; + return inst_ok; + } + + /* Operate the LEDs */ + if (m == inst_opt_get_gen_ledmask) { + va_list args; + int *mask = NULL; + + va_start(args, m); + mask = va_arg(args, int *); + va_end(args); + *mask = 0x3; /* Two general LEDs */ + return inst_ok; + } else if (m == inst_opt_get_led_state) { + va_list args; + int *mask = NULL; + + va_start(args, m); + mask = va_arg(args, int *); + va_end(args); + *mask = p->led_state; + return inst_ok; + } else if (m == inst_opt_set_led_state) { + va_list args; + int mask = 0; + + va_start(args, m); + mask = va_arg(args, int); + va_end(args); + return colorhug_set_LEDs(p, mask); + } + + return inst_unsupported; +} + +/* Constructor */ +extern colorhug *new_colorhug(icoms *icom, int debug, int verb) +{ + colorhug *p; + if ((p = (colorhug *)calloc(sizeof(colorhug),1)) == NULL) + error("colorhug: malloc failed!"); + + if (icom == NULL) + p->icom = new_icoms(); + else + p->icom = icom; + + p->debug = debug; + p->verb = verb; + + /* Set the colorimeter correction matrix to do nothing */ + icmSetUnity3x3(p->ccmat); + + p->init_coms = colorhug_init_coms; + p->init_inst = colorhug_init_inst; + p->capabilities = colorhug_capabilities; + p->capabilities2 = colorhug_capabilities2; + p->set_mode = colorhug_set_mode; + p->set_opt_mode = colorhug_set_opt_mode; + p->read_sample = colorhug_read_sample; + p->needs_calibration = colorhug_needs_calibration; + p->col_cor_mat = colorhug_col_cor_mat; + p->calibrate = colorhug_calibrate; + p->interp_error = colorhug_interp_error; + p->del = colorhug_del; + + /* Until initalisation */ + p->itype = instUnknown; + + return p; +} diff --git a/spectro/colorhug.h b/spectro/colorhug.h new file mode 100644 index 0000000..6c0a485 --- /dev/null +++ b/spectro/colorhug.h @@ -0,0 +1,85 @@ +/* + * Argyll Color Correction System + * + * Hughski ColorHug related defines + * + * Author: Richard Hughes + * Date: 30/11/2011 + * + * Copyright 2006 - 2007, Graeme W. Gill + * Copyright 2011, Richard Hughes + * All rights reserved. + * + * (Based on huey.h) + * + * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :- + * see the License2.txt file for licencing details. + */ + +#ifndef COLORHUG_H + +#include "inst.h" + +/* Note: update colorhug_interp_error() and colorhug_interp_code() in colorhug.c */ +/* if anything of these #defines are added or subtracted */ + +/* Fake Error codes */ +#define COLORHUG_INTERNAL_ERROR 0x61 /* Internal software error */ +#define COLORHUG_COMS_FAIL 0x62 /* Communication failure */ +#define COLORHUG_UNKNOWN_MODEL 0x63 /* Not an colorhug */ +#define COLORHUG_DATA_PARSE_ERROR 0x64 /* Read data parsing error */ +#define COLORHUG_USER_ABORT 0x65 /* User hit abort */ +#define COLORHUG_USER_TERM 0x66 /* User hit terminate */ +#define COLORHUG_USER_TRIG 0x67 /* User hit trigger */ +#define COLORHUG_USER_CMND 0x68 /* User hit command */ + +/* Real error codes */ +#define COLORHUG_OK 0x00 +#define COLORHUG_UNKNOWN_CMD 0x01 +#define COLORHUG_WRONG_UNLOCK_CODE 0x02 +#define COLORHUG_NOT_IMPLEMENTED 0x03 +#define COLORHUG_UNDERFLOW_SENSOR 0x04 +#define COLORHUG_NO_SERIAL 0x05 +#define COLORHUG_WATCHDOG 0x06 +#define COLORHUG_INVALID_ADDRESS 0x07 +#define COLORHUG_INVALID_LENGTH 0x08 +#define COLORHUG_INVALID_CHECKSUM 0x09 +#define COLORHUG_INVALID_VALUE 0x0a +#define COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER 0x0b +#define COLORHUG_NO_CALIBRATION 0x0c +#define COLORHUG_OVERFLOW_MULTIPLY 0x0d +#define COLORHUG_OVERFLOW_ADDITION 0x0e +#define COLORHUG_OVERFLOW_SENSOR 0x0f +#define COLORHUG_OVERFLOW_STACK 0x10 + +/* Internal errors */ +#define COLORHUG_NO_COMS 0x22 +#define COLORHUG_NOT_INITED 0x23 +#define COLORHUG_BAD_WR_LENGTH 0x25 +#define COLORHUG_BAD_RD_LENGTH 0x26 +#define COLORHUG_BAD_RET_CMD 0x27 +#define COLORHUG_BAD_RET_STAT 0x28 + + +/* COLORHUG communication object */ +struct _colorhug { + INST_OBJ_BASE + + inst_mode mode; /* Currently selected mode */ + + inst_opt_mode trig; /* Reading trigger mode */ + int trig_return; /* Emit "\n" after trigger */ + + int ser_no; /* Serial number */ + int crt; /* NZ if set to CRT */ + double ccmat[3][3]; /* Colorimeter correction matrix */ + int led_state; /* Current LED state */ + +}; typedef struct _colorhug colorhug; + +/* Constructor */ +extern colorhug *new_colorhug(icoms *icom, int debug, int verb); + + +#define COLORHUG_H +#endif /* COLORHUG_H */ diff --git a/spectro/inst.c b/spectro/inst.c index b73ff6c..cbcda9e 100644 --- a/spectro/inst.c +++ b/spectro/inst.c @@ -476,6 +476,8 @@ int verb /* Verbosity flag */ p = (inst *)new_spyd2(icom, debug, verb); else if (itype == instHuey) p = (inst *)new_huey(icom, debug, verb); + else if (itype == instColorHug) + p = (inst *)new_colorhug(icom, debug, verb); else { return NULL; } diff --git a/spectro/insttypes.c b/spectro/insttypes.c index a11f299..ed0170e 100644 --- a/spectro/insttypes.c +++ b/spectro/insttypes.c @@ -73,6 +73,8 @@ char *inst_name(instType itype) { return "Datacolor Spyder3"; case instHuey: return "GretagMacbeth Huey"; + case instColorHug: + return "Hughski ColorHug"; default: break; } @@ -124,6 +126,8 @@ instType inst_enum(char *name) { return instSpyder3; else if (strcmp(name, "GretagMacbeth Huey") == 0) return instHuey; + else if (strcmp(name, "Hughski ColorHug") == 0) + return instColorHug; return instUnknown; } @@ -183,6 +187,11 @@ unsigned short idProduct) { return instSpyder3; } + if (idVendor == 0x04d8) { /* Microchip */ + if (idProduct == 0xf8da) /* Hughski ColorHug */ + return instColorHug; + } + /* Add other instruments here */ return instUnknown; @@ -260,6 +269,8 @@ int inst_illuminant(xspect *sp, instType itype) { case instHuey: return 1; /* Not applicable */ + case instColorHug: + return 1; /* Not applicable */ default: break; diff --git a/spectro/insttypes.h b/spectro/insttypes.h index 6155cf0..15c6545 100644 --- a/spectro/insttypes.h +++ b/spectro/insttypes.h @@ -44,6 +44,7 @@ typedef enum { instSpyder2, /* Datacolor/ColorVision Spyder2 */ instSpyder3, /* Datacolor Spyder3 */ instHuey, /* GretagMacbeth Huey */ + instColorHug, /* Hughski ColorHug */ } instType; diff --git a/lib/Makefile.am b/lib/Makefile.am index 95c110f..52b60e1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -41,6 +41,7 @@ libargyll_la_SOURCES += ../spectro/inst.h ../spectro/inst.c ../spectro/dtp20.c . ../spectro/i1disp.c ../spectro/i1disp.h ../spectro/i1pro.c ../spectro/i1pro.h ../spectro/i1pro_imp.c ../spectro/i1pro_imp.h \ ../spectro/munki.c ../spectro/munki_imp.c ../spectro/ss.c ../spectro/ss.h ../spectro/ss_imp.c ../spectro/ss_imp.h ../spectro/hcfr.c ../spectro/hcfr.h \ ../spectro/spyd2.c ../spectro/spyd2.h ../spectro/spyd2setup.h ../spectro/spyd2PLD.h ../spectro/huey.c ../spectro/huey.h ../spectro/unixio.c \ + ../spectro/colorhug.c ../spectro/colorhug.h \ ../spectro/usbio.c ../spectro/hidio.c ../spectro/pollem.h ../spectro/icoms.h ../spectro/conv.h ../spectro/usbio.h \ ../spectro/hidio.h ../spectro/munki.h ../spectro/munki_imp.h