~ubuntu-branches/ubuntu/trusty/argyll/trusty-proposed

« back to all changes in this revision

Viewing changes to spectro/unixio.c

  • Committer: Package Import Robot
  • Author(s): Artur Rona
  • Date: 2014-02-12 00:35:39 UTC
  • mfrom: (13.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20140212003539-24tautzlitsiz61w
Tags: 1.5.1-5ubuntu1
* Merge from Debian unstable. (LP: #1275572) Remaining changes:
  - debian/control:
    + Build-depend on libtiff-dev rather than libtiff4-dev.
  - debian/control, debian/patches/06_fix_udev_rule.patch:
    + Fix udev rules to actually work; ENV{ACL_MANAGE} has
      stopped working ages ago, and with logind it's now the
      "uaccess" tag. Dropping also consolekit from Recommends.
  - debian/patches/drop-usb-db.patch:
    + Use hwdb builtin, instead of the obsolete usb-db
      in the udev rules.
* debian/patches/05_ftbfs-underlinkage.diff:
  - Dropped change, no needed anymore.
* Refresh the patches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
 /* Unix serial I/O class */
3
 
 
4
 
/* 
5
 
 * Argyll Color Correction System
6
 
 *
7
 
 * Author: Graeme W. Gill
8
 
 * Date:   18/11/2000
9
 
 *
10
 
 * Copyright 1997 - 2010 Graeme W. Gill
11
 
 * All rights reserved.
12
 
 *
13
 
 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
14
 
 * see the License2.txt file for licencing details.
15
 
 */
16
 
 
17
 
/*
18
 
    TTBD:
19
 
 */
20
 
 
21
 
#ifdef UNIX
22
 
 
23
 
#include <sys/types.h>          /* Include sys/select.h ? */
24
 
#include <sys/stat.h>
25
 
#include <fcntl.h>
26
 
#include <termios.h>
27
 
#include <stdio.h>
28
 
#include <unistd.h>
29
 
#include <stdlib.h>
30
 
#include <stdarg.h>
31
 
#include <dirent.h>
32
 
#include <time.h>
33
 
#include <errno.h>
34
 
#include <string.h>
35
 
#ifndef SALONEINSTLIB
36
 
#include "copyright.h"
37
 
#include "aconfig.h"
38
 
#endif
39
 
#include "numsup.h"
40
 
#include "xspect.h"
41
 
#include "insttypes.h"
42
 
#include "icoms.h"
43
 
#include "conv.h"
44
 
#include "usbio.h"
45
 
#include "hidio.h"
46
 
 
47
 
#undef DEBUG
48
 
 
49
 
#ifdef DEBUG
50
 
# define errout stderr
51
 
# define DBG(xx)        fprintf(errout, xx )
52
 
# define DBGF(xx)       fprintf xx
53
 
#else
54
 
# define errout stderr
55
 
# define DBG(xx)
56
 
# define DBGF(xx)
57
 
#endif
58
 
 
59
 
/* select() defined, but not poll(), so emulate poll() */
60
 
#if defined(FD_CLR) && !defined(POLLIN)
61
 
#include "pollem.h"
62
 
#define poll_x pollem
63
 
#else
64
 
#include <sys/poll.h>   /* Else assume poll() is native */
65
 
#define poll_x poll
66
 
#endif
67
 
 
68
 
#ifdef __APPLE__
69
 
//#include <stdbool.h>
70
 
#include <sys/sysctl.h>
71
 
#include <sys/param.h>
72
 
#include <CoreFoundation/CoreFoundation.h>
73
 
#include <IOKit/IOKitLib.h>
74
 
#include <IOKit/serial/IOSerialKeys.h>
75
 
#include <IOKit/IOBSD.h>
76
 
#include <mach/mach_init.h>
77
 
#include <mach/task_policy.h>
78
 
#endif /* __APPLE__ */
79
 
 
80
 
/* Return the port type */
81
 
static icom_type icoms_port_type(
82
 
icoms *p
83
 
) {
84
 
        if (p->is_hid)
85
 
                return icomt_hid;
86
 
        if (p->is_usb)
87
 
                return icomt_usb;
88
 
        return icomt_serial;
89
 
}
90
 
 
91
 
/* Create and return a list of available serial ports or USB instruments for this system */
92
 
static icompath **
93
 
icoms_get_paths(
94
 
icoms *p 
95
 
) {
96
 
        int usbend = 0;
97
 
        int i,j;
98
 
 
99
 
        /* Free any old list */
100
 
        if (p->paths != NULL) {
101
 
                for (i = 0; i < p->npaths; i++) {
102
 
                        if (p->paths[i]->path != NULL)
103
 
                                free(p->paths[i]->path);
104
 
#ifdef ENABLE_USB
105
 
                        if (p->paths[i]->dev != NULL)
106
 
                                usb_del_usb_device(p->paths[i]->dev);
107
 
                        if (p->paths[i]->hev != NULL)
108
 
                                hid_del_hid_device(p->paths[i]->hev);
109
 
#endif /* ENABLE_USB */
110
 
                        free(p->paths[i]);
111
 
                }
112
 
                free(p->paths);
113
 
                p->npaths = 0;
114
 
                p->paths = NULL;
115
 
        }
116
 
 
117
 
        hid_get_paths(p);
118
 
        usb_get_paths(p);
119
 
        usbend = p->npaths;
120
 
 
121
 
#ifdef ENABLE_SERIAL
122
 
#ifdef __APPLE__
123
 
        /* Search the OSX registry for serial ports */
124
 
        {
125
 
            kern_return_t kstat; 
126
 
            mach_port_t mp;                                             /* Master IO port */
127
 
            CFMutableDictionaryRef sdict;               /* Serial Port  dictionary */
128
 
                io_iterator_t mit;                                      /* Matching itterator */
129
 
                io_object_t ioob;                                       /* Serial object found */
130
 
 
131
 
                /* Get dictionary of serial ports */
132
 
        if ((sdict = IOServiceMatching(kIOSerialBSDServiceValue)) == NULL) {
133
 
                warning("IOServiceMatching returned a NULL dictionary");
134
 
                }
135
 
 
136
 
                /* Set value to match to RS232 type serial */
137
 
        CFDictionarySetValue(sdict, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type));
138
 
 
139
 
                /* Init itterator to find matching types. Consumes sdict reference */
140
 
                if ((kstat = IOServiceGetMatchingServices(kIOMasterPortDefault, sdict, &mit))
141
 
                                                                                     != KERN_SUCCESS) 
142
 
                error("IOServiceGetMatchingServices returned %d\n", kstat);
143
 
 
144
 
                /* Find all the matching serial ports */
145
 
                for (;;) {
146
 
                        char pname[100];
147
 
                        
148
 
                CFTypeRef dfp;          /* Device file path */
149
 
 
150
 
                    if ((ioob = IOIteratorNext(mit)) == 0)
151
 
                                break;
152
 
 
153
 
                    /* Get the callout device's path (/dev/cu.xxxxx). */
154
 
                        if ((dfp = IORegistryEntryCreateCFProperty(ioob, CFSTR(kIOCalloutDeviceKey),
155
 
                                                              kCFAllocatorDefault, 0)) == NULL)
156
 
                                goto continue1;
157
 
 
158
 
                        /* Convert from CF string to C string */
159
 
                        if (!CFStringGetCString(dfp, pname, 100, kCFStringEncodingASCII))
160
 
                                goto continue2;
161
 
 
162
 
                        /* Ignore infra red port or Bluetooth, or any other noise */
163
 
                        if (strstr(pname, "IrDA") != NULL
164
 
                         || strstr(pname, "Dialup") != NULL
165
 
                         || strstr(pname, "Bluetooth") != NULL)
166
 
                                goto continue2;
167
 
 
168
 
                        /* Add the port to the list */
169
 
                        if (p->paths == NULL) {
170
 
                                if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL)
171
 
                                        error("icoms: calloc failed!");
172
 
                        } else {
173
 
                                if ((p->paths = (icompath **)realloc(p->paths,
174
 
                                                     sizeof(icompath *) * (p->npaths + 2))) == NULL)
175
 
                                        error("icoms: realloc failed!");
176
 
                                p->paths[p->npaths+1] = NULL;
177
 
                        }
178
 
                        if ((p->paths[p->npaths] = malloc(sizeof(icompath))) == NULL)
179
 
                                error("icoms: malloc failed!");
180
 
                        if ((p->paths[p->npaths]->path = strdup(pname)) == NULL)
181
 
                                error("icoms: strdup failed!");
182
 
#ifdef ENABLE_USB
183
 
                        p->paths[p->npaths]->dev = NULL;
184
 
                        p->paths[p->npaths]->hev = NULL;
185
 
#endif /* ENABLE_USB */
186
 
                        p->npaths++;
187
 
                        p->paths[p->npaths] = NULL;
188
 
 
189
 
                continue2:
190
 
            CFRelease(dfp);
191
 
                continue1:
192
 
                    IOObjectRelease(ioob);              /* Release found object */
193
 
                }
194
 
            IOObjectRelease(mit);                       /* Release the itterator */
195
 
        }
196
 
#else
197
 
        /* Other UNIX like systems */
198
 
        /* Many are crude and list every available device name, whether */
199
 
        /* it's usable or not. Do any UNIX systems have a mechanism for listing */
200
 
        /* serial ports ?? */
201
 
 
202
 
        /* On Linux, the list in /proc/tty/driver/serial may indicate */
203
 
        /* which are real or not (if "uart:unknown" then not real) */
204
 
        /* e.g.:
205
 
 
206
 
                0: uart:16550A port:000003F8 irq:4 tx:3 rx:1755 brk:1 RTS|DTR
207
 
                1: uart:16550A port:000002F8 irq:3 tx:11 rx:3 brk:3
208
 
                2: uart:unknown port:000003E8 irq:4
209
 
                3: uart:unknown port:000002E8 irq:3
210
 
                4: uart:unknown port:00000000 irq:0
211
 
                5: uart:unknown port:00000000 irq:0
212
 
                6: uart:unknown port:00000000 irq:0
213
 
                7: uart:unknown port:00000000 irq:0
214
 
 
215
 
                but the permissions don't allow looking at this.
216
 
         */
217
 
        /* (This info is similar to what is returned by "setserial -g /dev/ttyS*", */
218
 
        /*  and "setserial -gb /dev/ttyS*" returns just the real ports.) */
219
 
        /* None of this can distinguish if one is the mouse. */
220
 
 
221
 
        /* From "QTSerialPort": */
222
 
        /*
223
 
                Constant         Used By         Naming Convention
224
 
                ----------       -------------   ------------------------
225
 
                _TTY_WIN_        Windows         COM1, COM2
226
 
                _TTY_IRIX_       SGI/IRIX        /dev/ttyf1, /dev/ttyf2
227
 
                _TTY_HPUX_       HP-UX           /dev/tty1p0, /dev/tty2p0
228
 
                _TTY_SUN_        SunOS/Solaris   /dev/ttya, /dev/ttyb
229
 
                _TTY_DIGITAL_    Digital UNIX    /dev/tty01, /dev/tty02
230
 
                _TTY_FREEBSD_    FreeBSD         /dev/ttyd0, /dev/ttyd1
231
 
                _TTY_LINUX_      Linux           /dev/ttyS0, /dev/ttyS1
232
 
                <none>           Linux           /dev/ttyS0, /dev/ttyS1
233
 
                                 Linux           /dev/ttyUSB0, /dev/ttyUSB1
234
 
        */
235
 
 
236
 
        /*
237
 
                "Most program set a lock in /var/lock/LCK..tty<XX> on Linux ?
238
 
                <http://sunsite.ualberta.ca/LDP/LDP/nag2/x-087-2-serial.devices.html>
239
 
                <http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html>
240
 
 
241
 
                We should really use the lock files to avoid treading on
242
 
                other programs toes. We assume at the moment that the user
243
 
                only picks a serial port with an instrument on it.
244
 
        */
245
 
 
246
 
        /* Search for devices that match the pattern /dev/ttyS[0-9]* and /dev/ttyUSB* */
247
 
        {
248
 
                DIR *dd;
249
 
                struct dirent *de;
250
 
                char *dirn = "/dev/";
251
 
        
252
 
                if ((dd = opendir(dirn)) == NULL) {
253
 
//                      DBGF((errout,"failed to open directory \"%s\"\n",dirn));
254
 
                        if (p->debug) fprintf(errout,"failed to open directory \"%s\"\n",dirn);
255
 
                        return p->paths;
256
 
                }
257
 
 
258
 
                for (;;) {
259
 
                        int fd;
260
 
                        char *dpath;
261
 
 
262
 
                        if ((de = readdir(dd)) == NULL)
263
 
                                break;
264
 
 
265
 
                        if (!(
266
 
#ifdef __FreeBSD__
267
 
                           /* This should match uart & USB devs. */
268
 
                                ( strncmp (de->d_name, "cua", 3) == 0
269
 
                                && strlen (de->d_name) < 7)
270
 
#else
271
 
                                /* Presumably Linux.. */
272
 
                            (   strncmp(de->d_name, "ttyS", 4) == 0
273
 
                             && de->d_name[4] >= '0' && de->d_name[4] <= '9')
274
 
                         || (   strncmp(de->d_name, "ttyUSB", 5) == 0)
275
 
#endif
276
 
                        ))
277
 
                                continue;
278
 
 
279
 
                        if ((dpath = (char *)malloc(strlen(dirn) + strlen(de->d_name) + 1)) == NULL) {
280
 
                                closedir(dd);
281
 
                                error("icoms: malloc failed!");
282
 
                        }
283
 
                        strcpy(dpath, dirn);
284
 
                        strcat(dpath, de->d_name);
285
 
 
286
 
                        /* See if the serial port is real */
287
 
                        if (strncmp(de->d_name, "ttyUSB", 5) != 0) {
288
 
 
289
 
                                /* Hmm. This is probably a bad idea - it can upset other */
290
 
                                /* programs that use the serial ports ? */
291
 
                                if ((fd = open(dpath, O_RDONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
292
 
                                        if (p->debug) fprintf(errout,"failed to open serial \"%s\"\n",dpath);
293
 
                                        free(dpath);
294
 
                                        continue;
295
 
                                }
296
 
                                /* On linux we could do a 
297
 
                                        struct serial_struct serinfo;
298
 
        
299
 
                                        serinfo.reserved_char[0] = 0;
300
 
        
301
 
                                        if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0
302
 
                                                || serinfo.type == PORT_UNKNOWN) {
303
 
                                                free(dpath);
304
 
                                                continue;
305
 
                                        }
306
 
        
307
 
                                 */
308
 
                                close(fd);
309
 
                        }
310
 
                        if (p->debug) fprintf(errout,"managed to open serial \"%s\"\n",dpath);
311
 
 
312
 
                        /* Add the path to the list */
313
 
                        if (p->paths == NULL) {
314
 
                                if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
315
 
                                        free(dpath);
316
 
                                        closedir(dd);
317
 
                                        error("icoms: calloc failed!");
318
 
                                }
319
 
                        } else {
320
 
                                if ((p->paths = (icompath **)realloc(p->paths,
321
 
                                                     sizeof(icompath *) * (p->npaths + 2))) == NULL) {
322
 
                                        free(dpath);
323
 
                                        closedir(dd);
324
 
                                        error("icoms: realloc failed!");
325
 
                                }
326
 
                                p->paths[p->npaths+1] = NULL;
327
 
                        }
328
 
                        if ((p->paths[p->npaths] = malloc(sizeof(icompath))) == NULL) {
329
 
                                free(dpath);
330
 
                                closedir(dd);
331
 
                                error("icoms: malloc failed!");
332
 
                        }
333
 
                        p->paths[p->npaths]->path = dpath;
334
 
#ifdef ENABLE_USB
335
 
                        p->paths[p->npaths]->dev = NULL;
336
 
                        p->paths[p->npaths]->hev = NULL;
337
 
#endif /* ENABLE_USB */
338
 
                        p->npaths++;
339
 
                        p->paths[p->npaths] = NULL;
340
 
                }
341
 
                closedir(dd);
342
 
        }
343
 
#endif /* ! __APPLE__ */
344
 
#endif /* ENABLE_SERIAL */
345
 
 
346
 
        /* Sort the /dev keys so people don't get confused... */
347
 
        for (i = usbend; i < (p->npaths-1); i++) {
348
 
                for (j = i+1; j < p->npaths; j++) {
349
 
                        if (strcmp(p->paths[i]->path, p->paths[j]->path) > 0) {
350
 
                                icompath *tt = p->paths[i];
351
 
                                p->paths[i] = p->paths[j];
352
 
                                p->paths[j] = tt;
353
 
                        }
354
 
                }
355
 
        }
356
 
 
357
 
        return p->paths;
358
 
}
359
 
 
360
 
 
361
 
/* Close the port */
362
 
static void icoms_close_port(icoms *p) {
363
 
        if (p->is_open) {
364
 
                if (p->is_usb) {
365
 
                        usb_close_port(p);
366
 
                } else if (p->is_hid) {
367
 
                        hid_close_port(p);
368
 
                } else {
369
 
                        if (p->fd != -1)
370
 
                                close(p->fd);
371
 
                                p->fd = -1;
372
 
                }
373
 
                p->is_open = 0;
374
 
        }
375
 
}
376
 
 
377
 
static int icoms_ser_write(icoms *p, char *wbuf, double tout);
378
 
static int icoms_ser_read(icoms *p, char *rbuf, int bsize, char tc, int ntc, double tout);
379
 
 
380
 
/* Set the serial port number and characteristics */
381
 
static void
382
 
icoms_set_ser_port(
383
 
icoms *p, 
384
 
int              port,          /* serial com port, 1 - N. 0 for no change */
385
 
flow_control fc,
386
 
baud_rate        baud,
387
 
parity           parity,
388
 
stop_bits        stop,
389
 
word_length      word
390
 
) {
391
 
        struct termios tio;
392
 
        speed_t speed = 0;
393
 
 
394
 
        if (p->debug) {
395
 
                fprintf(stderr,"icoms: About to set port characteristics:\n");
396
 
                fprintf(stderr,"       Port = %d\n",port);
397
 
                fprintf(stderr,"       Flow control = %d\n",fc);
398
 
                fprintf(stderr,"       Baud Rate = %d\n",baud);
399
 
                fprintf(stderr,"       Parity = %d\n",parity);
400
 
                fprintf(stderr,"       Stop bits = %d\n",stop);
401
 
                fprintf(stderr,"       Word length = %d\n",word);
402
 
        }
403
 
 
404
 
        if (port >= 1) {
405
 
                if (p->is_open && port != p->port) {    /* If port number changes */
406
 
                        p->close_port(p);
407
 
                }
408
 
        }
409
 
 
410
 
        if (p->is_usb_portno(p, port) == instUnknown) {
411
 
 
412
 
                if (fc != fc_nc)
413
 
                        p->fc = fc;
414
 
                if (baud != baud_nc)
415
 
                        p->br = baud;
416
 
                if (parity != parity_nc)
417
 
                        p->py = parity;
418
 
                if (stop != stop_nc)
419
 
                        p->sb = stop;
420
 
                if (word != length_nc)
421
 
                        p->wl = word;
422
 
 
423
 
                /* Make sure the port is open */
424
 
                if (!p->is_open) {
425
 
 
426
 
                        if (p->ppath != NULL) {
427
 
                                if (p->ppath->path != NULL)
428
 
                                        free(p->ppath->path);
429
 
                                free(p->ppath);
430
 
                                p->ppath = NULL;
431
 
                        }
432
 
 
433
 
                        if (p->paths == NULL)
434
 
                                icoms_get_paths(p);
435
 
                
436
 
                        if (port <= 0 || port > p->npaths)
437
 
                                error("icoms - set_ser_port: port number out of range!");
438
 
 
439
 
                        if ((p->ppath = malloc(sizeof(icompath))) == NULL)
440
 
                                error("malloc() failed on com port path");
441
 
                        *p->ppath = *p->paths[port-1];                          /* Structure copy */
442
 
                        if ((p->ppath->path = strdup(p->paths[port-1]->path)) == NULL)
443
 
                                error("strdup() failed on com port path");
444
 
                        p->port = port;
445
 
 
446
 
                        if (p->debug) fprintf(stderr,"icoms: About to open port '%s'\n",p->ppath->path);
447
 
 
448
 
                        if ((p->fd = open(p->ppath->path, O_RDWR | O_NOCTTY )) < 0)
449
 
                                error("Opening COM port '%s' failed with '%s'",p->ppath->path, strerror(errno));
450
 
                        /* O_NONBLOCK O_SYNC */
451
 
                        if (p->debug) fprintf(stderr,"icoms: Opened port OK, fd = %d\n",p->fd);
452
 
                        p->is_open = 1;
453
 
                }
454
 
 
455
 
                if (tcgetattr(p->fd, &tio) < 0) {
456
 
                        error("tcgetattr failed with '%s' on serial port '%s'", strerror(errno),p->ppath->path);
457
 
                }
458
 
 
459
 
                /* Clear everything in the tio, and just set what we want */
460
 
                memset(&tio, 0, sizeof(struct termios));
461
 
 
462
 
                /* Turn on basic configuration: */
463
 
                tio.c_iflag |= (
464
 
                                          IGNBRK                /* Ignore Break */
465
 
                                           );
466
 
 
467
 
                tio.c_oflag |= ( 0 );
468
 
 
469
 
                tio.c_cflag |= (
470
 
                                          CREAD         /* Enable the receiver */
471
 
                                        | CLOCAL        /* Ignore modem control lines */
472
 
                                                );
473
 
 
474
 
                tio.c_lflag |= (
475
 
                                             0          /* Non-canonical input mode */
476
 
                                                );
477
 
 
478
 
                /* And configure: */
479
 
                tio.c_cc[VTIME] = 1;            /* 0.1 second timeout */
480
 
                tio.c_cc[VMIN] = 64;            /* Comfortably less than _PF_MAX_INPUT */
481
 
 
482
 
                switch (p->fc) {
483
 
                        case fc_nc:
484
 
                                error("icoms - set_ser_port: illegal flow control!");
485
 
                                break;
486
 
                        case fc_XonXOff:
487
 
                                /* Use Xon/Xoff bi-directional flow control */
488
 
                                tio.c_iflag |= IXON;            /* Enable XON/XOFF flow control on output */
489
 
                                tio.c_iflag |= IXOFF;           /* Enable XON/XOFF flow control on input */
490
 
                                tio.c_cc[VSTART] = 0x11;        /* ^Q */
491
 
                                tio.c_cc[VSTOP] = 0x13;         /* ^S */
492
 
                                break;
493
 
                        case fc_Hardware:
494
 
                                /* Use RTS/CTS bi-directional flow control */
495
 
#ifdef __APPLE__
496
 
                                tio.c_cflag |= CCTS_OFLOW;
497
 
                                tio.c_cflag |= CRTS_IFLOW;
498
 
#else
499
 
                                tio.c_cflag |= CRTSCTS;
500
 
#endif
501
 
                                break;
502
 
                        default:
503
 
                                break;
504
 
                }
505
 
 
506
 
                switch (p->py) {
507
 
                        case parity_nc:
508
 
                                error("icoms - set_ser_port: illegal parity setting!");
509
 
                                break;
510
 
                        case parity_none:
511
 
                                tio.c_iflag &= ~INPCK;          /* Disable input parity checking */
512
 
                                break;
513
 
                        case parity_odd:
514
 
                                tio.c_iflag |= INPCK;           /* Enable input parity checking */
515
 
                                tio.c_cflag |= PARENB;          /* Enable input and output parity checking */
516
 
                                tio.c_cflag |= PARODD;          /* Input and output parity is odd */
517
 
                                break;
518
 
                        case parity_even:
519
 
                                tio.c_iflag |= INPCK;           /* Enable input parity checking */
520
 
                                tio.c_cflag |= PARENB;          /* Enable input and output parity checking */
521
 
                                break;
522
 
                }
523
 
 
524
 
                switch (p->sb) {
525
 
                        case stop_nc:
526
 
                                error("icoms - set_ser_port: illegal stop bits!");
527
 
                                break;
528
 
                        case stop_1:
529
 
                                break;          /* defaults to 1 */
530
 
                        case stop_2:
531
 
                                tio.c_cflag |= CSTOPB;
532
 
                                break;
533
 
                }
534
 
 
535
 
                switch (p->wl) {
536
 
                        case length_nc:
537
 
                                error("icoms - set_ser_port: illegal word length!");
538
 
                        case length_5:
539
 
                                tio.c_cflag |= CS5;
540
 
                                break;
541
 
                        case length_6:
542
 
                                tio.c_cflag |= CS6;
543
 
                                break;
544
 
                        case length_7:
545
 
                                tio.c_cflag |= CS7;
546
 
                                break;
547
 
                        case length_8:
548
 
                                tio.c_cflag |= CS8;
549
 
                                break;
550
 
                }
551
 
 
552
 
                /* Set the baud rate */
553
 
                switch (p->br) {
554
 
                        case baud_110:
555
 
                                speed = B110;
556
 
                                break;
557
 
                        case baud_300:
558
 
                                speed = B300;
559
 
                                break;
560
 
                        case baud_600:
561
 
                                speed = B600;
562
 
                                break;
563
 
                        case baud_1200:
564
 
                                speed = B1200;
565
 
                                break;
566
 
                        case baud_2400:
567
 
                                speed = B2400;
568
 
                                break;
569
 
                        case baud_4800:
570
 
                                speed = B4800;
571
 
                                break;
572
 
                        case baud_9600:
573
 
                                speed = B9600;
574
 
                                break;
575
 
                        case baud_19200:
576
 
                                speed = B19200;
577
 
                                break;
578
 
                        case baud_38400:
579
 
                                speed = B38400;
580
 
                                break;
581
 
                        case baud_57600:
582
 
                                speed = B57600;
583
 
                                break;
584
 
                        case baud_115200:
585
 
                                speed = B115200;
586
 
                                break;
587
 
                        default:
588
 
                                error("icoms - set_ser_port: illegal baud rate!");
589
 
                                break;
590
 
                }
591
 
 
592
 
                tcflush(p->fd, TCIOFLUSH);                      /* Discard any current in/out data */
593
 
 
594
 
                if (cfsetispeed(&tio,  speed) < 0)
595
 
                        error("cfsetispeed failed with '%s'", strerror(errno));
596
 
                if (cfsetospeed(&tio,  speed) < 0)
597
 
                        error("cfsetospeed failed with '%s'", strerror(errno));
598
 
 
599
 
                /* Make change immediately */
600
 
                if (tcsetattr(p->fd, TCSANOW, &tio) < 0)
601
 
                        error("tcsetattr failed with '%s' on '%s'", strerror(errno), p->ppath->path);
602
 
 
603
 
                tcflush(p->fd, TCIOFLUSH);                      /* Discard any current in/out data */
604
 
 
605
 
                p->write = icoms_ser_write;
606
 
                p->read = icoms_ser_read;
607
 
 
608
 
        }
609
 
        if (p->debug) fprintf(stderr,"icoms: port characteristics set ok\n");
610
 
}
611
 
 
612
 
/* ---------------------------------------------------------------------------------*/
613
 
/* Serial write/read */
614
 
 
615
 
/* Write the characters in the buffer out */
616
 
/* Data will be written up to the terminating nul */
617
 
/* Return relevant error status bits */
618
 
static int
619
 
icoms_ser_write(
620
 
icoms *p,
621
 
char *wbuf,
622
 
double tout
623
 
) {
624
 
        int len, wbytes;
625
 
        long toc, i, top;               /* Timout count, counter, timeout period */
626
 
        struct pollfd pa[2];            /* Poll array to monitor serial write and stdin */
627
 
        struct termios origs, news;
628
 
 
629
 
        if (p->debug) fprintf(stderr,"About to write '%s' ",icoms_fix(wbuf));
630
 
        if (p->fd == -1)
631
 
                error("icoms_write: not initialised");
632
 
 
633
 
        /* Configure stdin to be ready with just one character */
634
 
        if (tcgetattr(STDIN_FILENO, &origs) < 0)
635
 
                error("tcgetattr failed with '%s' on stdin", strerror(errno));
636
 
        news = origs;
637
 
        news.c_lflag &= ~(ICANON | ECHO);
638
 
        news.c_cc[VTIME] = 0;
639
 
        news.c_cc[VMIN] = 1;
640
 
        if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0)
641
 
                error("tcsetattr failed with '%s' on stdin", strerror(errno));
642
 
 
643
 
        /* Wait for serial output not block */
644
 
        pa[0].fd = p->fd;
645
 
        pa[0].events = POLLOUT;
646
 
        pa[0].revents = 0;
647
 
 
648
 
        /* Wait for stdin to have a character */
649
 
        pa[1].fd = STDIN_FILENO;
650
 
        pa[1].events = POLLIN | POLLPRI;
651
 
        pa[1].revents = 0;
652
 
 
653
 
        /* Until timed out, aborted, or transmitted */
654
 
        len = strlen(wbuf);
655
 
        tout *= 1000.0;         /* Timout in msec */
656
 
        p->lerr = 0;
657
 
 
658
 
        top = 100;                                              /* Timeout period in msecs */
659
 
        toc = (int)(tout/top + 0.5);    /* Number of timout periods in timeout */
660
 
        if (toc < 1)
661
 
                toc = 1;
662
 
 
663
 
        /* Until data is all written, we time out, or the user aborts */
664
 
        for(i = toc; i > 0 && len > 0;) {
665
 
                if (poll_x(pa, 2, top) > 0) {
666
 
                        if (pa[0].revents != 0) {
667
 
                                if (pa[0].revents != POLLOUT)
668
 
                                        error("poll on serial out returned unexpected value 0x%x",pa[0].revents);
669
 
                                
670
 
                                /* We can write it without blocking */
671
 
                                if ((wbytes = write(p->fd, wbuf, len)) < 0) {
672
 
                                        p->lerr |= ICOM_SERW;
673
 
                                        break;
674
 
                                } else if (wbytes > 0) {
675
 
                                        i = toc;
676
 
                                        len -= wbytes;
677
 
                                        wbuf += wbytes;
678
 
                                }
679
 
                        }
680
 
                        if (pa[1].revents != 0) {
681
 
                                char tb[10];
682
 
                                if (pa[1].revents != POLLIN && pa[1].revents != POLLPRI)
683
 
                                        error("poll on stdin returned unexpected value 0x%x",pa[1].revents);
684
 
                                /* Check for user abort */
685
 
                                if (read(STDIN_FILENO, tb, 10) > 0 && p->uih[tb[0]] != ICOM_OK) {
686
 
                                        p->cut = tb[0];
687
 
                                        p->lerr = p->uih[tb[0]];
688
 
                                        if (p->uih[tb[0]] == ICOM_USER
689
 
                                         || p->uih[tb[0]] == ICOM_TERM
690
 
                                         || p->uih[tb[0]] == ICOM_TRIG
691
 
                                         || p->uih[tb[0]] == ICOM_CMND)
692
 
                                                break;
693
 
                                }
694
 
                        }
695
 
                } else {
696
 
                        i--;            /* timeout (or error!) */
697
 
                }
698
 
        }
699
 
        if (i <= 0) {           /* Timed out */
700
 
                p->lerr |= ICOM_TO;
701
 
        }
702
 
 
703
 
        /* Restore stdin */
704
 
        if (tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0)
705
 
                error("tcsetattr failed with '%s' on stdin", strerror(errno));
706
 
 
707
 
        if (p->debug) fprintf(stderr,"ICOM err 0x%x\n",p->lerr);
708
 
        return p->lerr;
709
 
}
710
 
 
711
 
/* Read characters into the buffer */
712
 
/* Return string will be terminated with a nul */
713
 
static int
714
 
icoms_ser_read(
715
 
icoms *p,
716
 
char *rbuf,                     /* Buffer to store characters read */
717
 
int bsize,                      /* Buffer size */
718
 
char tc,                        /* Terminating characer */
719
 
int ntc,                        /* Number of terminating characters */
720
 
double tout                     /* Time out in seconds */
721
 
) {
722
 
        int rbytes;
723
 
        long j, toc, i, top;            /* Timout count, counter, timeout period */
724
 
        struct pollfd pa[2];            /* Poll array to monitor serial read and stdin */
725
 
        struct termios origs, news;
726
 
        char *rrbuf = rbuf;             /* Start of return buffer */
727
 
 
728
 
        if (p->debug) fprintf(stderr,"icoms: Read called\n");
729
 
        if (p->fd == -1)
730
 
                error("icoms_read: not initialised");
731
 
 
732
 
        if (bsize < 3)
733
 
                error("icoms_read given too small a buffer");
734
 
 
735
 
#ifdef NEVER
736
 
        /* The Prolific 2303 USB<->serial seems to choke on this, */
737
 
        /* so we just put up with the 100msec delay at the end of each reply. */
738
 
        if (tc != p->tc) {      /* Set the termination char */
739
 
                struct termios tio;
740
 
 
741
 
                if (tcgetattr(p->fd, &tio) < 0)
742
 
                        error("tcgetattr failed with '%s' on '%s'", strerror(errno),p->ppath->path);
743
 
 
744
 
                tio.c_cc[VEOL] = tc;
745
 
 
746
 
                /* Make change immediately */
747
 
                tcflush(p->fd, TCIFLUSH);
748
 
                if (tcsetattr(p->fd, TCSANOW, &tio) < 0)
749
 
                        error("tcsetattr failed with '%s' on '%s'", strerror(errno),p->ppath->path);
750
 
 
751
 
                p->tc = tc;
752
 
        }
753
 
#endif
754
 
 
755
 
        /* Configure stdin to be ready with just one character */
756
 
        if (tcgetattr(STDIN_FILENO, &origs) < 0)
757
 
                error("ycgetattr failed with '%s' on stdin", strerror(errno));
758
 
        news = origs;
759
 
        news.c_lflag &= ~(ICANON | ECHO);
760
 
        news.c_cc[VTIME] = 0;
761
 
        news.c_cc[VMIN] = 1;
762
 
        if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0)
763
 
                error("tcsetattr failed with '%s' on stdin", strerror(errno));
764
 
 
765
 
        /* Wait for serial input to have data */
766
 
        pa[0].fd = p->fd;
767
 
        pa[0].events = POLLIN | POLLPRI;
768
 
        pa[0].revents = 0;
769
 
 
770
 
        /* Wait for stdin to have a character */
771
 
        pa[1].fd = STDIN_FILENO;
772
 
        pa[1].events = POLLIN | POLLPRI;
773
 
        pa[1].revents = 0;
774
 
 
775
 
        bsize--;        /* Allow space for null */
776
 
        tout *= 1000.0;         /* Timout in msec */
777
 
        p->lerr = 0;
778
 
 
779
 
        top = 100;                                              /* Timeout period in msecs */
780
 
        toc = (int)(tout/top + 0.5);    /* Number of timout periods in timeout */
781
 
        if (toc < 1)
782
 
                toc = 1;
783
 
 
784
 
        /* Until data is all read, we time out, or the user aborts */
785
 
        for(i = toc, j = 0; i > 0 && bsize > 1 && j < ntc ;) {
786
 
 
787
 
                if (poll_x(pa, 2, top) > 0) {
788
 
                        if (pa[0].revents != 0) {
789
 
                                if (pa[0].revents != POLLIN &&  pa[0].revents != POLLPRI)
790
 
                                        error("poll on serial in returned unexpected value 0x%x",pa[0].revents);
791
 
 
792
 
                                /* We have data to read from input */
793
 
                                if ((rbytes = read(p->fd, rbuf, bsize)) < 0) {
794
 
                                        p->lerr |= ICOM_SERR;
795
 
                                        break;
796
 
                                } else if (rbytes > 0) {
797
 
                                        i = toc;                /* Reset time */
798
 
                                        bsize -= rbytes;
799
 
                                        while(rbytes--) {       /* Count termination characters */
800
 
                                                if (*rbuf++ == tc)
801
 
                                                        j++;
802
 
                                        }
803
 
                                }
804
 
                        }
805
 
                        if (pa[1].revents != 0) {
806
 
                                char tb[10];
807
 
                                if (pa[1].revents != POLLIN && pa[1].revents != POLLPRI)
808
 
                                        error("poll on stdin returned unexpected value 0x%x",pa[1].revents);
809
 
                                /* Check for user abort */
810
 
                                if (read(STDIN_FILENO, tb, 10) > 0 && p->uih[tb[0]] != ICOM_OK) {
811
 
                                        p->cut = tb[0];
812
 
                                        p->lerr = p->uih[tb[0]];
813
 
                                        if (p->uih[tb[0]] == ICOM_USER
814
 
                                         || p->uih[tb[0]] == ICOM_TERM
815
 
                                         || p->uih[tb[0]] == ICOM_TRIG
816
 
                                         || p->uih[tb[0]] == ICOM_CMND)
817
 
                                                break;
818
 
                                }
819
 
                        }
820
 
                } else {
821
 
                        i--;            /* We timed out (or error!) */
822
 
                }
823
 
        }
824
 
 
825
 
        *rbuf = '\000';
826
 
        if (i <= 0) {                   /* timed out */
827
 
                p->lerr |= ICOM_TO;
828
 
        }
829
 
        if (p->debug) fprintf(stderr,"icoms: About to return read '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),p->lerr);
830
 
 
831
 
        /* Restore stdin */
832
 
        if (tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0)
833
 
                error("tcsetattr failed with '%s' on stdin", strerror(errno));
834
 
 
835
 
        if (p->debug) fprintf(stderr,"icoms: Read returning with 0x%x\n",p->lerr);
836
 
 
837
 
        return p->lerr;
838
 
}
839
 
 
840
 
/* ---------------------------------------------------------------------------------*/
841
 
 
842
 
/* Destroy ourselves */
843
 
static void
844
 
icoms_del(icoms *p) {
845
 
        if (p->debug) fprintf(stderr,"icoms: delete called\n");
846
 
        if (p->is_open) {
847
 
                if (p->debug) fprintf(stderr,"icoms: closing port\n");
848
 
                p->close_port(p);
849
 
        }
850
 
        if (p->paths != NULL) {
851
 
                int i;
852
 
                for (i = 0; i < p->npaths; i++) {
853
 
                        if (p->paths[i]->path != NULL)
854
 
                                free(p->paths[i]->path);
855
 
#ifdef ENABLE_USB
856
 
                        if (p->paths[i]->dev != NULL)
857
 
                                usb_del_usb_device(p->paths[i]->dev);
858
 
                        if (p->paths[i]->hev != NULL)
859
 
                                hid_del_hid_device(p->paths[i]->hev);
860
 
#endif /* ENABLE_USB */
861
 
                        free(p->paths[i]);
862
 
                }
863
 
                free(p->paths);
864
 
        }
865
 
        if (p->ppath != NULL) {
866
 
                if (p->ppath->path != NULL)
867
 
                        free(p->ppath->path);
868
 
                free(p->ppath);
869
 
        }
870
 
        free (p);
871
 
}
872
 
 
873
 
/* Constructor */
874
 
icoms *new_icoms() {
875
 
        icoms *p;
876
 
        if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL)
877
 
                error("icoms: malloc failed!");
878
 
 
879
 
        /* Init things to null values */
880
 
        p->fd = -1;
881
 
        p->lerr = 0;
882
 
        p->ppath = NULL;
883
 
        p->port = -1;
884
 
        p->br = baud_nc;
885
 
        p->py = parity_nc;
886
 
        p->sb = stop_nc;
887
 
        p->wl = length_nc;
888
 
        p->debug = 0;
889
 
        
890
 
        p->close_port = icoms_close_port;
891
 
 
892
 
        p->port_type = icoms_port_type;
893
 
        p->get_paths = icoms_get_paths;
894
 
        p->set_ser_port = icoms_set_ser_port;
895
 
 
896
 
        p->write = NULL;
897
 
        p->read = NULL;
898
 
        p->del = icoms_del;
899
 
 
900
 
        usb_set_usb_methods(p);
901
 
        hid_set_hid_methods(p);
902
 
 
903
 
        return p;
904
 
}
905
 
 
906
 
#endif /* UNIX */