From 032b43c92285625866ec2343ed6329d97668ee66 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
Date: Sat, 14 Jan 2012 14:44:10 +0100
Subject: [PATCH] Add Colorhug driver

---
 debian/changelog                                   |    9 +
 debian/patches/01_autotools-support.diff           |   10 +-
 debian/patches/03_add-ColorHug_sensor_driver.patch |  991 ++++++++++++++++++++
 debian/patches/series                              |    1 +
 4 files changed, 1007 insertions(+), 4 deletions(-)
 create mode 100644 debian/patches/03_add-ColorHug_sensor_driver.patch

diff --git a/debian/changelog b/debian/changelog
index d2a6a77..7324b2d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+argyll (1.3.5-4) UNRELEASED; urgency=low
+
+  * debian/patches/03_add-ColorHug_sensor_driver.patch
+    + Added, add support for the ColorHug sensor
+  * debian/patches/01_autotools-support.diff
+    + Updated, compile support for the ColorHug sensor
+
+ -- Sjoerd Simons <sjoerd@debian.org>  Sat, 14 Jan 2012 15:40:46 +0100
+
 argyll (1.3.5-3) unstable; urgency=low
 
   * debian/rules Enable make distclean (Closes: #649728).
diff --git a/debian/patches/01_autotools-support.diff b/debian/patches/01_autotools-support.diff
index 75741ab..a9831d4 100644
--- a/debian/patches/01_autotools-support.diff
+++ b/debian/patches/01_autotools-support.diff
@@ -392,7 +392,7 @@ Index: argyll-1.3.5/spectro/Makefile.am
 +	dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h		\
 +	i1disp.c i1disp.h i1pro.c i1pro.h i1pro_imp.c i1pro_imp.h	\
 +	munki.c munki_imp.c ss.c ss.h ss_imp.c ss_imp.h hcfr.c hcfr.h	\
-+	spyd2.c spyd2.h spyd2setup.h spyd2PLD.h huey.c huey.h unixio.c	\
++	spyd2.c spyd2.h spyd2setup.h spyd2PLD.h colorhug.c colorhug.h huey.c huey.h unixio.c	\
 +	usbio.c hidio.c pollem.c pollem.h icoms.h conv.h usbio.h	\
 +	hidio.h i1d3.h i1d3.c
 +libinst_la_LIBADD = ../libargyllusb.la $(ICC_LIBS) ../numlib/libargyllnum.la	\
@@ -35936,8 +35936,9 @@ Index: argyll-1.3.5/imdi/imdi_k.h
 +	libconv.la
 +am_libinst_la_OBJECTS = inst.lo insttypes.lo dtp20.lo dtp22.lo \
 +	dtp41.lo dtp51.lo dtp92.lo i1disp.lo i1pro.lo i1pro_imp.lo \
-+	munki.lo munki_imp.lo ss.lo ss_imp.lo hcfr.lo spyd2.lo huey.lo \
-+	unixio.lo usbio.lo hidio.lo pollem.lo i1d3.lo
++	munki.lo munki_imp.lo ss.lo ss_imp.lo hcfr.lo spyd2.lo \
++	colorhug.lo huey.lo unixio.lo usbio.lo hidio.lo pollem.lo \
++	i1d3.lo
 +libinst_la_OBJECTS = $(am_libinst_la_OBJECTS)
 +libinsttypes_la_DEPENDENCIES = ../libargyll.la
 +am_libinsttypes_la_OBJECTS = insttypes.lo
@@ -36253,7 +36254,7 @@ Index: argyll-1.3.5/imdi/imdi_k.h
 +	dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h		\
 +	i1disp.c i1disp.h i1pro.c i1pro.h i1pro_imp.c i1pro_imp.h	\
 +	munki.c munki_imp.c ss.c ss.h ss_imp.c ss_imp.h hcfr.c hcfr.h	\
-+	spyd2.c spyd2.h spyd2setup.h spyd2PLD.h huey.c huey.h unixio.c	\
++	spyd2.c spyd2.h spyd2setup.h spyd2PLD.h colorhug.c colorhug.h huey.c huey.h unixio.c	\
 +	usbio.c hidio.c pollem.c pollem.h icoms.h conv.h usbio.h	\
 +	hidio.h i1d3.h i1d3.c
 +
@@ -36452,6 +36453,7 @@ Index: argyll-1.3.5/imdi/imdi_k.h
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ccss.Plo@am__quote@
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ccxxmake.Po@am__quote@
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chartread.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colorhug.Plo@am__quote@
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conv.Plo@am__quote@
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispcal.Po@am__quote@
 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispread.Po@am__quote@
diff --git a/debian/patches/03_add-ColorHug_sensor_driver.patch b/debian/patches/03_add-ColorHug_sensor_driver.patch
new file mode 100644
index 0000000..f168f97
--- /dev/null
+++ b/debian/patches/03_add-ColorHug_sensor_driver.patch
@@ -0,0 +1,991 @@
+From abd5019264a92f329860bce22abf1c96b6b18ff6 Mon Sep 17 00:00:00 2001
+From: Richard Hughes <richard@hughsie.com>
+Date: Wed, 30 Nov 2011 15:28:57 +0000
+Subject: [PATCH] Add an experimental ColorHug sensor driver
+
+---
+ libusb1/55-Argyll.rules   |    3 +
+ spectro/Jamfile           |    2 +-
+ spectro/afiles            |    2 +
+ spectro/colorhug.c        |  752 +++++++++++++++++++++++++++++++++++++++++++++
+ spectro/colorhug.h        |   85 +++++
+ spectro/inst.c            |    2 +
+ spectro/insttypes.c       |   11 +
+ spectro/insttypes.h       |    1 +
+ 24 files changed, 858 insertions(+), 2 deletions(-)
+ create mode 100644 spectro/colorhug.c
+ create mode 100644 spectro/colorhug.h
+
+diff --git a/libusb1/55-Argyll.rules b/libusb1/55-Argyll.rules
+index a3b3cd4..a047d26 100644
+--- a/libusb1/55-Argyll.rules
++++ b/libusb1/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/Jamfile b/spectro/Jamfile
+index a58ae5a..bed42cf 100644
+--- a/spectro/Jamfile
++++ b/spectro/Jamfile
+@@ -69,7 +69,7 @@ HDRS = ../h ../numlib ../icc ../cgats ../rspl ../xicc ../gamut ../spectro
+        ../plot $(LIBUSBHDRS) $(CMMHDRS) ;
+ 
+ # Instrument access library library
+-Library libinst : inst.c insttypes.c dtp20.c dtp22.c dtp41.c dtp51.c dtp92.c i1disp.c i1d3.c i1pro.c i1pro_imp.c munki.c munki_imp.c ss.c ss_imp.c hcfr.c spyd2.c huey.c $(IOFILE) usbio.c hidio.c ;
++Library libinst : inst.c insttypes.c dtp20.c dtp22.c dtp41.c dtp51.c dtp92.c i1disp.c i1d3.c i1pro.c i1pro_imp.c munki.c munki_imp.c ss.c ss_imp.c hcfr.c spyd2.c huey.c colorhug.c $(IOFILE) usbio.c hidio.c ;
+ 
+ # Display access library 
+ Library libdisp : dispsup.c dispwin.c : : : $(LibWinH) ;
+diff --git a/spectro/afiles b/spectro/afiles
+index 32bbcf1..668409c 100644
+--- a/spectro/afiles
++++ b/spectro/afiles
+@@ -60,6 +60,8 @@ LzmaDec.h
+ LzmaDec.c
+ huey.c
+ huey.h
++colorhug.c
++colorhug.h
+ spec2cie.c
+ average.c
+ conv.h
+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 <stdio.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <string.h>
++#include <time.h>
++#include <stdarg.h>
++#include <math.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 "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 (uint32_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),
++						  1.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/instlib.ksh b/spectro/instlib.ksh
+index 0d2a7d2..d8e47dc 100644
+--- a/spectro/instlib.ksh
++++ b/spectro/instlib.ksh
+@@ -9,7 +9,7 @@
+ 
+ echo "Making standalone GPLv2 instrument archive instlib.zip "
+ 
+-FILES="License2.txt Makefile.OSX  Makefile.UNIX  Makefile.WNT pollem.h pollem.c conv.h conv.c hidio.h hidio.c icoms.h inst.h inst.c insttypes.c insttypes.h insttypeinst.h dtp20.c dtp20.h dtp22.c dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h ss.h ss.c ss_imp.h ss_imp.c i1disp.c i1disp.h i1d3.h i1d3.c i1pro.h i1pro.c i1pro_imp.h i1pro_imp.c munki.h munki.c munki_imp.h munki_imp.c hcfr.c hcfr.h huey.c huey.h spyd2.c spyd2.h spyd2setup.h spyd2PLD.h spyd2en.c i1d3ccss.c vinflate.c inflate.c LzmaDec.c  LzmaDec.h LzmaTypes.h ntio.c unixio.c usbio.h usbio.c xdg_bds.c xdg_bds.h ../xicc/xspect.h ../xicc/xspect.c ../xicc/ccss.h ../xicc/ccss.c ../rspl/rspl1.h ../rspl/rspl1.c ../h/sort.h ../numlib/numsup.h ../numlib/numsup.c ../cgats/pars.h ../cgats/pars.c ../cgats/parsstd.c ../cgats/cgats.h ../cgats/cgats.c ../cgats/cgatsstd.c  spotread.c"
++FILES="License2.txt Makefile.OSX  Makefile.UNIX  Makefile.WNT pollem.h pollem.c conv.h conv.c hidio.h hidio.c icoms.h inst.h inst.c insttypes.c insttypes.h insttypeinst.h dtp20.c dtp20.h dtp22.c dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h ss.h ss.c ss_imp.h ss_imp.c i1disp.c i1disp.h i1d3.h i1d3.c i1pro.h i1pro.c i1pro_imp.h i1pro_imp.c munki.h munki.c munki_imp.h munki_imp.c hcfr.c hcfr.h huey.c huey.h colorhug.c colorhug.h spyd2.c spyd2.h spyd2setup.h spyd2PLD.h spyd2en.c i1d3ccss.c vinflate.c inflate.c LzmaDec.c  LzmaDec.h LzmaTypes.h ntio.c unixio.c usbio.h usbio.c xdg_bds.c xdg_bds.h ../xicc/xspect.h ../xicc/xspect.c ../xicc/ccss.h ../xicc/ccss.c ../rspl/rspl1.h ../rspl/rspl1.c ../h/sort.h ../numlib/numsup.h ../numlib/numsup.c ../cgats/pars.h ../cgats/pars.c ../cgats/parsstd.c ../cgats/cgats.h ../cgats/cgats.c ../cgats/cgatsstd.c  spotread.c"
+ 
+ rm -f instlib.zip
+ rm -rf _zipdir
+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;
+ 
+-- 
+1.7.7.3
+
diff --git a/debian/patches/series b/debian/patches/series
index 8d4a118..bf4471d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,3 @@
 01_autotools-support.diff
 02_firmware-package-builder.diff
+03_add-ColorHug_sensor_driver.patch
-- 
1.7.8.3

