1 
2 #ifndef ICOMS_H
3 
4 /* An abstracted instrument serial and USB communication class. */
5 
6 /*
7  * Argyll Color Correction System
8  *
9  * Author: Graeme W. Gill
10  * Date:   2006/4/20
11  *
12  * Copyright 1996 - 2013 Graeme W. Gill
13  * All rights reserved.
14  *
15  * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
16  * see the License2.txt file for licencing details.
17  *
18  * Derived from serio.h
19  */
20 
21 /* Some MSWin specific stuff is in icoms, and used by usbio & hidio */
22 #if defined (NT)
23 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
24 # if defined(_WIN32_WINNT)
25 #  undef _WIN32_WINNT
26 # endif
27 # define _WIN32_WINNT 0x0501
28 #endif
29 #define WIN32_LEAN_AND_MEAN
30 #include <windows.h>
31 #endif
32 
33 #if defined(UNIX_APPLE)
34 #include <IOKit/usb/IOUSBLib.h>
35 #endif
36 
37 #ifdef __cplusplus
38 	extern "C" {
39 #endif
40 
41 #undef QUIET_MEMCHECKERS		/* #define to memset coms read buffers before reading */
42 
43 /* USB open/handling/buf workaround flags */
44 typedef enum {
45 	icomuf_none                = 0x0000,
46 	icomuf_detach              = 0x0001,	/* Attempt to detach from system driver */
47 	icomuf_no_open_clear       = 0x0002,	/* Don't send a clear_halt after opening the port */
48 	icomuf_reset_before_close  = 0x0004,	/* Reset port before closing it */
49 											/* ??? Could change to reset before open ??? */
50 	icomuf_resetep_before_read = 0x0008		/* Do a usb_resetep before each ep read */
51 } icomuflags;
52 
53 typedef enum {
54 	icomt_unknown        = 0x0000,
55 
56 	/* Category of device */
57 	icomt_instrument     = 0x010000,		/* Color measurement instrument (default) */
58 	icomt_3dlut          = 0x020000,		/* A 3D cLUT box */
59 	icomt_vtpg           = 0x040000,		/* A video test patern generator box */
60 	icomt_printer        = 0x080000,		/* A printing device */
61 
62 	icomt_cat_any        = 0x0f0000,		/* Could be any device category */
63 	icomt_cat_mask       = 0xff0000,		/* Mask for device category */
64 
65 	/* Type of underlying communication port */
66 	/* (fastserio driver will have icomt_serial and icomt_usb set) */
67 	icomt_serial         = 0x000001,		/* Serial port (i.e. has baud rate etc.) */
68 	icomt_usb            = 0x000002,		/* USB port */
69 	icomt_hid            = 0x000004,		/* HID USB port */
70 	icomt_bt             = 0x000008,		/* Bluetooth (non-serial) */
71 
72 	icomt_port_mask      = 0x0000ff,		/* Mask for port type */
73 
74 	/* Attributes */
75 	icomt_fastserial     = 0x000100,		/* Fast Serial (i.e. USB, fastserio, Bluetooth) */
76 	icomt_btserial       = 0x000200,		/* Bluetooth serial port */
77 	icomt_seriallike     = 0x000400,		/* Uses serial message methods, but */
78 											/* may not be actual icomt_serial. */
79 
80 	icomt_attr_mask      = 0x00ff00,		/* Mask for port attributes */
81 
82 	icomt_portattr_mask  = icomt_port_mask | icomt_attr_mask,
83 
84 	icomt_portattr_all   = icomt_portattr_mask	/* Scan for all port types */
85 
86 
87 } icom_type;
88 
89 /* Status bits/return values */
90 #define ICOM_OK	    0x000000		/* No error */
91 
92 #define ICOM_NOTS 	0x001000		/* Not supported */
93 #define ICOM_SIZE	0x002000		/* Request/response size exceeded limits */
94 #define ICOM_TO		0x004000		/* Timed out, but there may be bytes read/written */
95 #define ICOM_SHORT	0x008000		/* No timeout but number of bytes wasn't read/written */
96 #define ICOM_CANC	0x010000		/* Was cancelled */
97 #define ICOM_SYS	0x020000		/* System error (ie. malloc, system call fail) */
98 #define ICOM_VER	0x040000		/* Version error - need up to date kernel driver */
99 
100 #define ICOM_USBR	0x000100		/* Unspecified USB read error */
101 #define ICOM_USBW	0x000200		/* Unspecified USB write error */
102 #define ICOM_SERR	0x000400		/* Unspecified Serial read error */
103 #define ICOM_SERW	0x000800		/* Unspecified Serial write error */
104 
105 #define ICOM_XRE	0x000040		/* Xmit shift reg empty */
106 #define ICOM_XHE	0x000020		/* Xmit hold reg empty */
107 #define ICOM_BRK	0x000010		/* Break detected */
108 #define ICOM_FER	0x000008		/* Framing error */
109 #define ICOM_PER	0x000004		/* Parity error */
110 #define ICOM_OER	0x000002		/* Overun error */
111 #define ICOM_DRY	0x000001		/* Recv data ready */
112 
113 typedef struct _icompath icompath;
114 typedef struct _icompaths icompaths;
115 typedef struct _icoms icoms;
116 
117 #ifdef ENABLE_USB
118 
119 struct usb_idevice;		/* Forward declarations */
120 struct hid_idevice;
121 
122 /* Information about each end point */
123 typedef struct {
124 	int valid;			/* Flag, nz if this endpoint is valid */
125 	int addr;			/* Address of end point */
126 	int packetsize;		/* The max packet size */
127 	int type;			/* 2 = bulk, 3 = interrupt */
128 	int interface;		/* interface number */
129 #if defined(UNIX_APPLE)
130 	int pipe;			/* pipe number (1..N, OS X only) */
131 #endif
132 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
133 	int fd;				/* ep file descriptor */
134 #endif
135 } usb_ep;
136 
137 #define ICOM_EP_TYPE_BULK 2
138 #define ICOM_EP_TYPE_INTERRUPT 3
139 
140 #include "usbio.h"
141 #include "hidio.h"
142 
143 #endif /* ENABLE_USB */
144 
145 /* - - - - - - - - - - - - - - - - - - - -  */
146 
147 /* Store information about a possible instrument communication path */
148 /* (Note a path doesn't have a reference to icompaths or its' log) */
149 struct _icompath {
150 	devType itype;				/* Type of device if known */
151 	char *name;					/* instance description */
152 
153 	icom_type dctype;			/* Device and com. type */
154 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
155 	char *spath;				/* Serial device path */
156 #endif
157 #ifdef ENABLE_USB
158 	int nep;					/* Number of end points */
159 	unsigned int vid, pid; 		/* USB vendor and product id's */
160 	struct usb_idevice *usbd;	/* USB port, NULL if not USB */
161 	struct hid_idevice *hidd;	/* HID port, NULL if not HID */
162 #endif /* ENABLE_USB */
163 };
164 
165 extern icompath icomFakeDevice;	/* Declare fake device */
166 
167 /* Device type specific list index */
168 typedef enum {
169 	dtix_combined = 0,		/* Combined list */
170 	dtix_inst,				/* Instrument */
171 	dtix_3dlut,
172 	dtix_vtpg,
173 	dtix_printer,
174 
175 	dtix_number				/* Number of entries */
176 } icom_dtix;
177 
178 /* The available instrument communication paths */
179 struct _icompaths {
180 	a1log *log;					/* Verbose, debuge & error logging */
181 
182 	/* Combined and device category specific path lists (read only). */
183 	/* Paths may appear on more than one, if they are multi-function, */
184 	/* or the category can't be determined without opening them. */
185 	/* (dpaths[dtix_combined] is the owner of the icompath, */
186 	/* and all the others are only populated after discovery.) */
187 	icompath **dpaths[dtix_number];		/* Device paths if any */
188 	int ndpaths[dtix_number];			/* Number of device paths */
189 
190 	/* Alias of dpaths[dtix_inst] for backwards compatibility, */
191 	/* only set after discovery. */
192 	icompath **paths;			/* Device instrument if any */
193 	int npaths;					/* Number of instrument paths */
194 
195 	/* Re-discover and populate the available instrument list */
196 	/* return icom error */
197 	int (*refresh)(struct _icompaths *p);
198 
199 	/* Same as above, but just scan for selected types of devices and/or port types */
200 	int (*refresh_sel)(struct _icompaths *p, icom_type mask);
201 
202 	/* Return the instrument path corresponding to the port number, or NULL if out of range */
203 	icompath *(*get_path)(
204 		struct _icompaths *p,
205 		int  	       port);		/* Enumerated port number, 1..n */
206 #define FAKE_DEVICE_PORT -98		/* Fake display & instrument */
207 #define DEMO_DEVICE_PORT -99		/* Fake Demo instrument */
208 
209 	/* Return the device path corresponding to the port number, or NULL if out of range */
210 	icompath *(*get_path_sel)(
211 		struct _icompaths *p,
212 		icom_type dctype,			/* Device type list */
213 		int  	       port);		/* Enumerated port number, 1..n */
214 
215 	/* Clear all the device paths */
216 	void (*clear)(struct _icompaths *p);
217 
218 	/* We're done */
219 	void (*del)(struct _icompaths *p);
220 
221 	/* ====== internal implementation ======= */
222 
223 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
224 	/* Add a serial path to combined. path is copied. Return icom error */
225 	int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_type dctype);
226 #endif /* ENABLE_SERIAL */
227 
228 #ifdef ENABLE_USB
229 	/* Add a usb path to combined. usbd is taken, others are copied. Return icom error */
230 	int (*add_usb)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
231 	               int nep, struct usb_idevice *usbd, devType itype);
232 
233 	/* Add an hid path to combined. hidd is taken, others are copied. Return icom error */
234 	int (*add_hid)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
235 	               int nep, struct hid_idevice *hidd, devType itype);
236 #endif /* ENABLE_USB */
237 
238 	/* Delete the last combined path */
239 	void (*del_last_path)(struct _icompaths *p);
240 
241 	/* Return the last combined path */
242 	icompath *(*get_last_path)(struct _icompaths *p);
243 
244 };
245 
246 /* Allocate an icom paths and set it to the list of available devices */
247 /* Use g_log as argument for default logging. */
248 /* Return NULL on error */
249 icompaths *new_icompaths(a1log *log);
250 
251 /* Same as above, but just scan for selected types of devices and/or port types */
252 icompaths *new_icompaths_sel(a1log *log, icom_type mask);
253 
254 
255 /* - - - - - - - - - - - */
256 /* Serial related stuff */
257 
258 /* Flow control */
259 typedef enum {
260 	fc_nc = 0,			/* not configured/default */
261 	fc_None,
262 	fc_XonXOff,
263 	fc_Hardware,		/* RTS CTS flow control */
264 	fc_HardwareDTR		/* DTR DSR flow control */
265 } flow_control;
266 
267 /* baud rate available on all systems */
268 typedef enum {
269 	baud_nc      = 0,		/* Not Configured */
270 	baud_110     = 1,
271 	baud_300     = 2,
272 	baud_600     = 3,
273 	baud_1200    = 4,
274 	baud_2400    = 5,
275 	baud_4800    = 6,
276 	baud_9600    = 7,
277 	baud_14400   = 8,
278 	baud_19200   = 9,
279 	baud_38400   = 10,
280 	baud_57600   = 11,
281 	baud_115200  = 12,
282 	baud_921600  = 13
283 } baud_rate;
284 
285 char *baud_rate_to_str(baud_rate br);
286 
287 /* Possible parity */
288 typedef enum {
289 	parity_nc,
290 	parity_none,
291 	parity_odd,
292 	parity_even
293 } parity;
294 
295 /* Possible stop bits */
296 typedef enum {
297 	stop_nc,
298 	stop_1,
299 	stop_2
300 } stop_bits;
301 
302 /* Possible word length */
303 typedef enum {
304 	length_nc,
305 	length_5,
306 	length_6,
307 	length_7,
308 	length_8
309 } word_length;
310 
311 /* Interrupt callback type */
312 typedef enum {
313 	icomi_data_available		/* Data is available to be read */
314 } icom_int;
315 
316 /* Cancelation token. */
317 typedef struct _usb_cancelt usb_cancelt;
318 
319 #ifdef ENABLE_USB
320 void usb_init_cancel(usb_cancelt *p);
321 void usb_uninit_cancel(usb_cancelt *p);
322 void usb_reinit_cancel(usb_cancelt *p);
323 #endif
324 
325 struct _icoms {
326   /* Private: */
327 
328 	/* Copy of some of icompath contents: */
329 	icom_type dctype;			/* Device cat. and com. type */
330 	devType itype;				/* Type of device if known */
331 
332 	char *name;					/* Device description */
333 
334 	int is_open;				/* Flag, NZ if this port is open */
335 
336 	void *icntx;				/* Optional instrument context */
337 
338 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
339 
340 	/* Serial port parameters */
341 	char *spath;				/* Serial port path */
342 #if defined (MSDOS)
343 	unsigned short porta;		/* Hardware port address */
344 #endif
345 #if defined (NT)
346 	HANDLE phandle;				/* NT handle */
347 #endif
348 #if defined (UNIX)
349 	int fd;						/* Unix file descriptor */
350 #endif
351 	flow_control fc;
352 	baud_rate	br;
353 	parity		py;
354 	stop_bits	sb;
355 	word_length	wl;
356 
357 #endif	/* ENABLE_SERIAL */
358 
359 #ifdef ENABLE_USB
360 
361 	/* USB port parameters */
362 	struct usb_idevice *usbd;	/* USB port - copy of ppath->usbd */
363 	icomuflags uflags;		/* Bug workaround flags */
364 
365 	unsigned int vid, pid; 	/* USB vendor and product id's, used to distiguish instruments */
366 	int nconfig;			/* Number of configurations */
367 	int config;				/* Config this info applies to (always 1 ?) */
368 	int cconfig;			/* Current configuration (0 or 1 ?) */
369 	int nifce;				/* Number of interfaces */
370 	int nep;				/* Number of end points */
371 	int wr_ep, rd_ep;		/* Default end points to use for "serial" read/write */
372 	int rd_qa;				/* Read quanta size */
373 	int ms_bytes;			/* No. of Modem status bytes to strip from each read */
374 	int latmsec;			/* Latency timeout in msec for modem status bytes */
375 	int (*interp_ms)(struct _icoms *p, unsigned char *msbytes);
376 							/* return icom error from ms bytes, NULL if none */
377 
378 	usb_ep ep[32];			/* Information about each end point for general usb i/o */
379 
380 /* Macro to access end point information */
381 #define EPINFO(addr) ep[((addr >> 3) & 0x10) + (addr & 0x0f)]
382 
383 	/* HID port parameters */
384 	struct hid_idevice *hidd;	/* HID port - copy of ppath->hidd */
385 
386 #endif /* ENABLE_USB */
387 
388 	/* General parameters */
389 	int lserr;					/* Last serial communication error code */
390 	a1log *log;					/* Debug & Error log */
391 	int debug;					/* legacy - Flag, nz to print instrument io info to stderr */
392 
393 	/* Linked list to automate SIGKILL cleanup */
394 	struct _icoms *next;
395 
396   /* Public: */
397 
398 	/* Return the device category */
399 	/* (Returns bit flags) */
400 	icom_type (*dev_cat)(struct _icoms *p);
401 
402 	/* Return the communication port type */
403 	/* (Can use equality tests on return value for normal ports, */
404 	/* or bit flag for fastserio USB/serial port) */
405 	icom_type (*port_type)(struct _icoms *p);
406 
407 	/* Return the communication port attributes */
408 	/* (Returns bit flags) */
409 	icom_type (*port_attr)(struct _icoms *p);
410 
411 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
412 	/* Select the serial communications port and characteristics - extended version */
413 	/* return icom error */
414 	int (*set_ser_port_ex)(
415 		struct _icoms *p,
416 		flow_control fc,		/* Flow control */
417 		baud_rate	 baud,
418 		parity		 parity,
419 		stop_bits	 stop_bits,
420 		word_length	 word_length,
421 		int delayms);			/* Delay in ms after open */
422 
423 	/* Select the serial communications port and characteristics */
424 	/* return icom error */
425 	int (*set_ser_port)(
426 		struct _icoms *p,
427 		flow_control fc,		/* Flow control */
428 		baud_rate	 baud,
429 		parity		 parity,
430 		stop_bits	 stop_bits,
431 		word_length	 word_length);
432 #endif  /* ENABLE_SERIAL */
433 
434 #ifdef ENABLE_USB
435 	/* Select the USB communications port and characteristics */
436 	/* return icom error */
437 	int (*set_usb_port)(
438 		struct _icoms *p,
439 	    int            config,		/* Configuration */
440 	    int            wr_ep,		/* "serial" write end point */
441 	    int            rd_ep,		/* "serial" read end point */
442 		icomuflags usbflags,		/* Any special handling flags */
443 		int retries,				/* > 0 if we should retry set_configuration (100msec) */
444 		char **pnames				/* List of process names to try and kill before opening */
445 	);
446 
447 	/* Select the HID communications port and characteristics */
448 	/* return icom error */
449 	int (*set_hid_port)(
450 		struct _icoms *p,
451 		icomuflags usbflags,		/* Any special handling flags */
452 		int retries,				/* > 0 if we should retry set_configuration (100msec) */
453 		char **pnames				/* List of process names to try and kill before opening */
454 	);
455 #endif /* ENABLE_USB */
456 
457 	/* Close the port */
458 	void (*close_port)(struct _icoms *p);
459 
460 	/* "Serial" write the characters in the buffer out */
461 	/* Data will be written up to the terminating nul. */
462 	/* return icom error */
463 	int (*write)(
464 		struct _icoms *p,
465 		char *buf,			/* nul terminated unless nch > 0 */
466 		int nch,			/* if > 0, number of characters to write, else nul terminated */
467 		double tout);		/* Timeout in seconds */
468 
469 	/* "Serial" read characters into the buffer */
470 	/* The returned data will be terminated by a nul. */
471 	/* return icom error */
472 	int (*read)(
473 		struct _icoms *p,
474 		char *buf,			/* Buffer to store characters read */
475 		int bsize,			/* Buffer size. Make this larger than chars required! */
476 		int *bread,			/* Bytes read (not including forced '\000') */
477 		char *tc,			/* Terminating characters, NULL for none or char count mode */
478 		int ntc,			/* Number of terminating characters or char count needed. */
479 		double tout);		/* Timeout in seconds */
480 
481 	/* "Serial" write and read */
482 	/* return icom error */
483 	int (*write_read)(
484 		struct _icoms *p,
485 		char *wbuf,			/* Write puffer */
486 		int nwch,			/* if > 0, number of characters to write, else nul terminated */
487 		char *rbuf,			/* Read buffer */
488 		int bsize,			/* Buffer size. Make this larger than chars required! */
489 		int *bread,			/* Bytes read (not including forced '\000') */
490 		char *tc,			/* Terminating characers, NULL for none or char count mode */
491 		int ntc,			/* Number of any terminating characters needed, or char count needed */
492 		double tout);		/* Timeout in seconds */
493 
494 	/* "Serial" write and read with read flush */
495 	/* return icom error */
496 	int (*write_read_ex)(
497 		struct _icoms *p,
498 		char *wbuf,			/* Write puffer */
499 		int nwch,			/* if > 0, number of characters to write, else nul terminated */
500 		char *rbuf,			/* Read buffer */
501 		int bsize,			/* Buffer size. Make this larger than chars required! */
502 		int *bread,			/* Bytes read (not including forced '\000') */
503 		char *tc,			/* Terminating characers, NULL for none or char count mode */
504 		int ntc,			/* Number of any terminating characters needed, or char count needed */
505 		double tout,		/* Timeout in seconds */
506 		int frbw);			/* nz to Flush Read Before Write */
507 
508 	/* For a USB device, do a control message */
509 	/* return icom error */
510 	int (*usb_control)(struct _icoms *p,
511 		int requesttype,		/* 8 bit request type (USB bmRequestType) */
512 		int request,			/* 8 bit request code (USB bRequest) */
513 		int value,				/* 16 bit value (USB wValue, sent little endian) */
514 		int index,				/* 16 bit index (USB wIndex, sent little endian) */
515 		unsigned char *rwbuf,	/* Read or write buffer */
516 		int rwsize,				/* Bytes to read or write */
517 		double tout);			/* Timeout in seconds */
518 
519 	/* For a USB device, do a bulk or interrupt read from an end point */
520 	/* return icom error */
521 	int (*usb_read)(struct _icoms *p,
522 		usb_cancelt *cancelt,	/* Optionaly tokem that can be used to cancel */
523 		int ep,					/* End point address */
524 		unsigned char *buf,		/* Read buffer */
525 		int bsize,				/* Bytes to read or write */
526 		int *bread,				/* Bytes read */
527 		double tout);			/* Timeout in seconds */
528 
529 	/* For a USB device, do a bulk or interrupt write to an end point */
530 	/* return icom error */
531 	int (*usb_write)(struct _icoms *p,
532 		usb_cancelt *cancelt,	/* Optionaly tokem that can be used to cancel */
533 		int ep,					/* End point address */
534 		unsigned char *wbuf,	/* Write buffer */
535 		int wsize,				/* Bytes to or write */
536 		int *bwritten,			/* Bytes written */
537 		double tout);			/* Timeout in seconds */
538 
539 	/* Wait until a read/write in another thread has started. */
540 	/* return icom error */
541 	int (*usb_wait_io)(struct _icoms *p,
542 		usb_cancelt *cantelt);			/* Cancel handle */
543 
544 	/* Cancel a read/write in another thread */
545 	/* return icom error */
546 	int (*usb_cancel_io)(struct _icoms *p,
547 		usb_cancelt *cantelt);			/* Cancel handle */
548 
549 	/* Reset and end point toggle state to 0 */
550 	/* return icom error */
551 	int (*usb_resetep)(struct _icoms *p,
552 		int ep);				/* End point address */
553 
554 	/* Clear an end point halt */
555 	/* return icom error */
556 	int (*usb_clearhalt)(struct _icoms *p,
557 		int ep);				/* End point address */
558 
559 	/* For an HID device, read a message from the device. */
560 	/* return icom error */
561 	int (*hid_read)(struct _icoms *p,
562 		unsigned char *buf,		/* Read buffer */
563 		int bsize,				/* Bytes to read or write */
564 		int *bread,				/* Bytes read */
565 		double tout);			/* Timeout in seconds */
566 
567 	/* For an HID device, write a message to the device */
568 	/* return icom error */
569 	int (*hid_write)(struct _icoms *p,
570 		unsigned char *wbuf,	/* Write buffer */
571 		int wsize,				/* Bytes to or write */
572 		int *bwritten,			/* Bytes written */
573 		double tout);			/* Timeout in seconds */
574 
575 	/* Optional callback to client from device */
576 	/* Default implementation is a NOOP */
577 	int (*interrupt)(struct _icoms *p,
578 		int icom_int);			/* Interrupt cause */
579 
580 	/* Destroy ourselves */
581 	void (*del)(struct _icoms *p);
582 
583 };
584 
585 /* Constructor */
586 extern icoms *new_icoms(icompath *ipath, a1log *log);
587 
588 /* - - - - - - - - - - - - - - - - - - -- */
589 /* Utilities */
590 
591 /* Convert control chars to ^[A-Z] notation in a string. */
592 /* Returns a maximum of 1000 characters in static buffer. */
593 char *icoms_fix(char *s);
594 
595 /* Convert a limited binary buffer to a list of hex */
596 char *icoms_tohex(unsigned char *s, int len);
597 
598 /* Implementation declarations */
599 
600 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
601 
602 int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
603 int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
604                                     char *tc, int ntc, double tout);
605 
606 #endif
607 
608 #ifdef __cplusplus
609 	}
610 #endif
611 
612 #define ICOMS_H
613 #endif /* ICOMS_H */
614