summaryrefslogtreecommitdiff
path: root/spectro/icoms.h
blob: be36cacf1d67cc4f16b8cb18542d54bb999001d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613

#ifndef ICOMS_H

/* An abstracted instrument serial and USB communication class. */

/* 
 * Argyll Color Correction System
 *
 * Author: Graeme W. Gill
 * Date:   2006/4/20
 *
 * Copyright 1996 - 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.
 * 
 * Derived from serio.h
 */

/* Some MSWin specific stuff is in icoms, and used by usbio & hidio */
#if defined (NT)
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
# if defined(_WIN32_WINNT) 
#  undef _WIN32_WINNT
# endif
# define _WIN32_WINNT 0x0501
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#if defined(UNIX_APPLE)
#include <IOKit/usb/IOUSBLib.h>
#endif

#ifdef __cplusplus
	extern "C" {
#endif

#undef QUIET_MEMCHECKERS		/* #define to memset coms read buffers before reading */

/* USB open/handling/buf workaround flags */
typedef enum {
	icomuf_none                = 0x0000,
	icomuf_detach              = 0x0001,	/* Attempt to detach from system driver */
	icomuf_no_open_clear       = 0x0002,	/* Don't send a clear_halt after opening the port */
	icomuf_reset_before_close  = 0x0004,	/* Reset port before closing it */
											/* ??? Could change to reset before open ??? */
	icomuf_resetep_before_read = 0x0008		/* Do a usb_resetep before each ep read */
} icomuflags;

typedef enum {
	icomt_unknown        = 0x0000,

	/* Category of device */
	icomt_instrument     = 0x010000,		/* Color measurement instrument (default) */
	icomt_3dlut          = 0x020000,		/* A 3D cLUT box */
	icomt_vtpg           = 0x040000,		/* A video test patern generator box */
	icomt_printer        = 0x080000,		/* A printing device */

	icomt_cat_any        = 0x0f0000,		/* Could be any device category */
	icomt_cat_mask       = 0xff0000,		/* Mask for device category */

	/* Type of underlying communication port */
	/* (fastserio driver will have icomt_serial and icomt_usb set) */
	icomt_serial         = 0x000001,		/* Serial port (i.e. has baud rate etc.) */
	icomt_usb            = 0x000002,		/* USB port */
	icomt_hid            = 0x000004,		/* HID USB port */
	icomt_bt             = 0x000008,		/* Bluetooth (non-serial) */

	icomt_port_mask      = 0x0000ff,		/* Mask for port type */

	/* Attributes */
	icomt_fastserial     = 0x000100,		/* Fast Serial (i.e. USB, fastserio, Bluetooth) */
	icomt_btserial       = 0x000200,		/* Bluetooth serial port */
	icomt_seriallike     = 0x000400,		/* Uses serial message methods, but */
											/* may not be actual icomt_serial. */

	icomt_attr_mask      = 0x00ff00,		/* Mask for port attributes */

	icomt_portattr_mask  = icomt_port_mask | icomt_attr_mask,

	icomt_portattr_all   = icomt_portattr_mask	/* Scan for all port types */


} icom_type;

/* Status bits/return values */
#define ICOM_OK	    0x000000		/* No error */

#define ICOM_NOTS 	0x001000		/* Not supported */
#define ICOM_SIZE	0x002000		/* Request/response size exceeded limits */
#define ICOM_TO		0x004000		/* Timed out, but there may be bytes read/written */
#define ICOM_SHORT	0x008000		/* No timeout but number of bytes wasn't read/written */
#define ICOM_CANC	0x010000		/* Was cancelled */
#define ICOM_SYS	0x020000		/* System error (ie. malloc, system call fail) */
#define ICOM_VER	0x040000		/* Version error - need up to date kernel driver */

#define ICOM_USBR	0x000100		/* Unspecified USB read error */
#define ICOM_USBW	0x000200		/* Unspecified USB write error */
#define ICOM_SERR	0x000400		/* Unspecified Serial read error */
#define ICOM_SERW	0x000800		/* Unspecified Serial write error */

#define ICOM_XRE	0x000040		/* Xmit shift reg empty */
#define ICOM_XHE	0x000020		/* Xmit hold reg empty */
#define ICOM_BRK	0x000010		/* Break detected */
#define ICOM_FER	0x000008		/* Framing error */
#define ICOM_PER	0x000004		/* Parity error */
#define ICOM_OER	0x000002		/* Overun error */
#define ICOM_DRY	0x000001		/* Recv data ready */

typedef struct _icompath icompath;
typedef struct _icompaths icompaths;
typedef struct _icoms icoms;

#ifdef ENABLE_USB

struct usb_idevice;		/* Forward declarations */
struct hid_idevice;

/* Information about each end point */
typedef struct {
	int valid;			/* Flag, nz if this endpoint is valid */
	int addr;			/* Address of end point */
	int packetsize;		/* The max packet size */
	int type;			/* 2 = bulk, 3 = interrupt */	
	int interface;		/* interface number */
#if defined(UNIX_APPLE)
	int pipe;			/* pipe number (1..N, OS X only) */
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
	int fd;				/* ep file descriptor */
#endif
} usb_ep;

#define ICOM_EP_TYPE_BULK 2
#define ICOM_EP_TYPE_INTERRUPT 3

#include "usbio.h"
#include "hidio.h"

#endif /* ENABLE_USB */

/* - - - - - - - - - - - - - - - - - - - -  */

/* Store information about a possible instrument communication path */
/* (Note a path doesn't have a reference to icompaths or its' log) */
struct _icompath {
	devType itype;				/* Type of device if known */
	char *name;					/* instance description */

	icom_type dctype;			/* Device and com. type */
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
	char *spath;				/* Serial device path */
#endif
#ifdef ENABLE_USB
	int nep;					/* Number of end points */
	unsigned int vid, pid; 		/* USB vendor and product id's */
	struct usb_idevice *usbd;	/* USB port, NULL if not USB */
	struct hid_idevice *hidd;	/* HID port, NULL if not HID */
#endif /* ENABLE_USB */
};

extern icompath icomFakeDevice;	/* Declare fake device */

/* Device type specific list index */
typedef enum {
	dtix_combined = 0,		/* Combined list */
	dtix_inst,				/* Instrument */
	dtix_3dlut,
	dtix_vtpg,
	dtix_printer,

	dtix_number				/* Number of entries */
} icom_dtix;

/* The available instrument communication paths */
struct _icompaths {
	a1log *log;					/* Verbose, debuge & error logging */

	/* Combined and device category specific path lists (read only). */
	/* Paths may appear on more than one, if they are multi-function, */
	/* or the category can't be determined without opening them. */
	/* (dpaths[dtix_combined] is the owner of the icompath, */
	/* and all the others are only populated after discovery.) */
	icompath **dpaths[dtix_number];		/* Device paths if any */
	int ndpaths[dtix_number];			/* Number of device paths */

	/* Alias of dpaths[dtix_inst] for backwards compatibility, */
	/* only set after discovery. */
	icompath **paths;			/* Device instrument if any */
	int npaths;					/* Number of instrument paths */

	/* Re-discover and populate the available instrument list */
	/* return icom error */
	int (*refresh)(struct _icompaths *p);

	/* Same as above, but just scan for selected types of devices and/or port types */
	int (*refresh_sel)(struct _icompaths *p, icom_type mask);

	/* Return the instrument path corresponding to the port number, or NULL if out of range */
	icompath *(*get_path)(
		struct _icompaths *p, 
		int  	       port);		/* Enumerated port number, 1..n */
#define FAKE_DEVICE_PORT -98		/* Fake display & instrument */
#define DEMO_DEVICE_PORT -99		/* Fake Demo instrument */

	/* Return the device path corresponding to the port number, or NULL if out of range */
	icompath *(*get_path_sel)(
		struct _icompaths *p, 
		icom_type dctype,			/* Device type list */
		int  	       port);		/* Enumerated port number, 1..n */

	/* Clear all the device paths */
	void (*clear)(struct _icompaths *p);

	/* We're done */
	void (*del)(struct _icompaths *p);

	/* ====== internal implementation ======= */

#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
	/* Add a serial path to combined. path is copied. Return icom error */
	int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_type dctype);
#endif /* ENABLE_SERIAL */

#ifdef ENABLE_USB
	/* Add a usb path to combined. usbd is taken, others are copied. Return icom error */
	int (*add_usb)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
	               int nep, struct usb_idevice *usbd, devType itype);

	/* Add an hid path to combined. hidd is taken, others are copied. Return icom error */
	int (*add_hid)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
	               int nep, struct hid_idevice *hidd, devType itype);
#endif /* ENABLE_USB */

	/* Delete the last combined path */
	void (*del_last_path)(struct _icompaths *p);

	/* Return the last combined path */
	icompath *(*get_last_path)(struct _icompaths *p);

};

/* Allocate an icom paths and set it to the list of available devices */
/* Use g_log as argument for default logging. */
/* Return NULL on error */
icompaths *new_icompaths(a1log *log);

/* Same as above, but just scan for selected types of devices and/or port types */
icompaths *new_icompaths_sel(a1log *log, icom_type mask);


/* - - - - - - - - - - - */
/* Serial related stuff */

/* Flow control */
typedef enum {
	fc_nc = 0,			/* not configured/default */
	fc_None,
	fc_XonXOff,
	fc_Hardware,		/* RTS CTS flow control */
	fc_HardwareDTR		/* DTR DSR flow control */			
} flow_control;

/* baud rate available on all systems */
typedef enum {
	baud_nc      = 0,		/* Not Configured */
	baud_110     = 1,
	baud_300     = 2,
	baud_600     = 3,
	baud_1200    = 4,
	baud_2400    = 5,
	baud_4800    = 6,
	baud_9600    = 7,
	baud_14400   = 8,
	baud_19200   = 9,
	baud_38400   = 10,
	baud_57600   = 11,
	baud_115200  = 12,
	baud_921600  = 13
} baud_rate;

char *baud_rate_to_str(baud_rate br);

/* Possible parity */
typedef enum {
	parity_nc,
	parity_none,
	parity_odd,
	parity_even
} parity;

/* Possible stop bits */
typedef enum {
	stop_nc,
	stop_1,
	stop_2
} stop_bits;

/* Possible word length */
typedef enum {
	length_nc,
	length_5,
	length_6,
	length_7,
	length_8
} word_length;

/* Interrupt callback type */
typedef enum {
	icomi_data_available		/* Data is available to be read */
} icom_int;

/* Cancelation token. */
typedef struct _usb_cancelt usb_cancelt;

#ifdef ENABLE_USB
void usb_init_cancel(usb_cancelt *p);
void usb_uninit_cancel(usb_cancelt *p);
void usb_reinit_cancel(usb_cancelt *p);
#endif

struct _icoms {
  /* Private: */

	/* Copy of some of icompath contents: */
	icom_type dctype;			/* Device cat. and com. type */
	devType itype;				/* Type of device if known */

	char *name;					/* Device description */
	
	int is_open;				/* Flag, NZ if this port is open */

	void *icntx;				/* Optional instrument context */

#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)

	/* Serial port parameters */
	char *spath;				/* Serial port path */
#if defined (MSDOS)
	unsigned short porta;		/* Hardware port address */
#endif
#if defined (NT)
	HANDLE phandle;				/* NT handle */
#endif
#if defined (UNIX)
	int fd;						/* Unix file descriptor */
#endif
	flow_control fc;
	baud_rate	br;
	parity		py;
	stop_bits	sb;
	word_length	wl;

#endif	/* ENABLE_SERIAL */

#ifdef ENABLE_USB

	/* USB port parameters */
	struct usb_idevice *usbd;	/* USB port - copy of ppath->usbd */
	icomuflags uflags;		/* Bug workaround flags */

	unsigned int vid, pid; 	/* USB vendor and product id's, used to distiguish instruments */
	int nconfig;			/* Number of configurations */
	int config;				/* Config this info applies to (always 1 ?) */
	int cconfig;			/* Current configuration (0 or 1 ?) */
	int nifce;				/* Number of interfaces */
	int nep;				/* Number of end points */
	int wr_ep, rd_ep;		/* Default end points to use for "serial" read/write */
	int rd_qa;				/* Read quanta size */
	int ms_bytes;			/* No. of Modem status bytes to strip from each read */
	int latmsec;			/* Latency timeout in msec for modem status bytes */
	int (*interp_ms)(struct _icoms *p, unsigned char *msbytes);
							/* return icom error from ms bytes, NULL if none */

	usb_ep ep[32];			/* Information about each end point for general usb i/o */

/* Macro to access end point information */
#define EPINFO(addr) ep[((addr >> 3) & 0x10) + (addr & 0x0f)]

	/* HID port parameters */
	struct hid_idevice *hidd;	/* HID port - copy of ppath->hidd */

#endif /* ENABLE_USB */

	/* General parameters */
	int lserr;					/* Last serial communication error code */
	a1log *log;					/* Debug & Error log */
	int debug;					/* legacy - Flag, nz to print instrument io info to stderr */

	/* Linked list to automate SIGKILL cleanup */
	struct _icoms *next;
	
  /* Public: */

	/* Return the device category */
	/* (Returns bit flags) */
	icom_type (*dev_cat)(struct _icoms *p);

	/* Return the communication port type */
	/* (Can use equality tests on return value for normal ports, */
	/* or bit flag for fastserio USB/serial port) */
	icom_type (*port_type)(struct _icoms *p);

	/* Return the communication port attributes */
	/* (Returns bit flags) */
	icom_type (*port_attr)(struct _icoms *p);

#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
	/* Select the serial communications port and characteristics - extended version */
	/* return icom error */
	int (*set_ser_port_ex)(
		struct _icoms *p, 
		flow_control fc,		/* Flow control */
		baud_rate	 baud,
		parity		 parity,
		stop_bits	 stop_bits,
		word_length	 word_length,
		int delayms);			/* Delay in ms after open */

	/* Select the serial communications port and characteristics */
	/* return icom error */
	int (*set_ser_port)(
		struct _icoms *p, 
		flow_control fc,		/* Flow control */
		baud_rate	 baud,
		parity		 parity,
		stop_bits	 stop_bits,
		word_length	 word_length);
#endif  /* ENABLE_SERIAL */

#ifdef ENABLE_USB
	/* Select the USB communications port and characteristics */
	/* return icom error */
	int (*set_usb_port)(
		struct _icoms *p, 
	    int            config,		/* Configuration */
	    int            wr_ep,		/* "serial" write end point */
	    int            rd_ep,		/* "serial" read end point */
		icomuflags usbflags,		/* Any special handling flags */
		int retries,				/* > 0 if we should retry set_configuration (100msec) */
		char **pnames				/* List of process names to try and kill before opening */
	);

	/* Select the HID communications port and characteristics */
	/* return icom error */
	int (*set_hid_port)(
		struct _icoms *p, 
		icomuflags usbflags,		/* Any special handling flags */
		int retries,				/* > 0 if we should retry set_configuration (100msec) */
		char **pnames				/* List of process names to try and kill before opening */
	);
#endif /* ENABLE_USB */

	/* Close the port */
	void (*close_port)(struct _icoms *p);

	/* "Serial" write the characters in the buffer out */
	/* Data will be written up to the terminating nul. */
	/* return icom error */
	int (*write)(
		struct _icoms *p,
		char *buf,			/* nul terminated unless nch > 0 */
		int nch,			/* if > 0, number of characters to write, else nul terminated */
		double tout);		/* Timeout in seconds */

	/* "Serial" read characters into the buffer */
	/* The returned data will be terminated by a nul. */
	/* return icom error */
	int (*read)(
		struct _icoms *p,
		char *buf,			/* Buffer to store characters read */
		int bsize,			/* Buffer size. Make this larger than chars required! */
		int *bread,			/* Bytes read (not including forced '\000') */
		char *tc,			/* Terminating characters, NULL for none or char count mode */
		int ntc,			/* Number of terminating characters or char count needed. */
		double tout);		/* Timeout in seconds */

	/* "Serial" write and read */
	/* return icom error */
	int (*write_read)(
		struct _icoms *p,
		char *wbuf,			/* Write puffer */
		int nwch,			/* if > 0, number of characters to write, else nul terminated */
		char *rbuf,			/* Read buffer */
		int bsize,			/* Buffer size. Make this larger than chars required! */
		int *bread,			/* Bytes read (not including forced '\000') */
		char *tc,			/* Terminating characers, NULL for none or char count mode */
		int ntc,			/* Number of any terminating characters needed, or char count needed */
		double tout);		/* Timeout in seconds */

	/* "Serial" write and read with read flush */
	/* return icom error */
	int (*write_read_ex)(
		struct _icoms *p,
		char *wbuf,			/* Write puffer */
		int nwch,			/* if > 0, number of characters to write, else nul terminated */
		char *rbuf,			/* Read buffer */
		int bsize,			/* Buffer size. Make this larger than chars required! */
		int *bread,			/* Bytes read (not including forced '\000') */
		char *tc,			/* Terminating characers, NULL for none or char count mode */
		int ntc,			/* Number of any terminating characters needed, or char count needed */
		double tout,		/* Timeout in seconds */
		int frbw);			/* nz to Flush Read Before Write */

	/* For a USB device, do a control message */
	/* return icom error */
	int (*usb_control)(struct _icoms *p,
		int requesttype,		/* 8 bit request type (USB bmRequestType) */
		int request,			/* 8 bit request code (USB bRequest) */
		int value,				/* 16 bit value (USB wValue, sent little endian) */
		int index,				/* 16 bit index (USB wIndex, sent little endian) */
		unsigned char *rwbuf,	/* Read or write buffer */
		int rwsize,				/* Bytes to read or write */
		double tout);			/* Timeout in seconds */

	/* For a USB device, do a bulk or interrupt read from an end point */
	/* return icom error */
	int (*usb_read)(struct _icoms *p,
		usb_cancelt *cancelt,	/* Optionaly tokem that can be used to cancel */
		int ep,					/* End point address */
		unsigned char *buf,		/* Read buffer */
		int bsize,				/* Bytes to read or write */
		int *bread,				/* Bytes read */
		double tout);			/* Timeout in seconds */

	/* For a USB device, do a bulk or interrupt write to an end point */
	/* return icom error */
	int (*usb_write)(struct _icoms *p,
		usb_cancelt *cancelt,	/* Optionaly tokem that can be used to cancel */
		int ep,					/* End point address */
		unsigned char *wbuf,	/* Write buffer */
		int wsize,				/* Bytes to or write */
		int *bwritten,			/* Bytes written */
		double tout);			/* Timeout in seconds */

	/* Wait until a read/write in another thread has started. */
	/* return icom error */
	int (*usb_wait_io)(struct _icoms *p,
		usb_cancelt *cantelt);			/* Cancel handle */

	/* Cancel a read/write in another thread */
	/* return icom error */
	int (*usb_cancel_io)(struct _icoms *p,
		usb_cancelt *cantelt);			/* Cancel handle */

	/* Reset and end point toggle state to 0 */
	/* return icom error */
	int (*usb_resetep)(struct _icoms *p,
		int ep);				/* End point address */

	/* Clear an end point halt */
	/* return icom error */
	int (*usb_clearhalt)(struct _icoms *p,
		int ep);				/* End point address */

	/* For an HID device, read a message from the device. */
	/* return icom error */
	int (*hid_read)(struct _icoms *p,
		unsigned char *buf,		/* Read buffer */
		int bsize,				/* Bytes to read or write */
		int *bread,				/* Bytes read */
		double tout);			/* Timeout in seconds */

	/* For an HID device, write a message to the device */
	/* return icom error */
	int (*hid_write)(struct _icoms *p,
		unsigned char *wbuf,	/* Write buffer */
		int wsize,				/* Bytes to or write */
		int *bwritten,			/* Bytes written */
		double tout);			/* Timeout in seconds */

	/* Optional callback to client from device */ 
	/* Default implementation is a NOOP */
	int (*interrupt)(struct _icoms *p,
		int icom_int);			/* Interrupt cause */

	/* Destroy ourselves */
	void (*del)(struct _icoms *p);

};

/* Constructor */
extern icoms *new_icoms(icompath *ipath, a1log *log);

/* - - - - - - - - - - - - - - - - - - -- */
/* Utilities */

/* Convert control chars to ^[A-Z] notation in a string. */
/* Returns a maximum of 1000 characters in static buffer. */
char *icoms_fix(char *s);

/* Convert a limited binary buffer to a list of hex */
char *icoms_tohex(unsigned char *s, int len);

/* Implementation declarations */

#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)

int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
                                    char *tc, int ntc, double tout);

#endif

#ifdef __cplusplus
	}
#endif

#define ICOMS_H
#endif /* ICOMS_H */