1
2 /* General instrument + serial I/O support */
3
4 /*
5 * Argyll Color Correction System
6 *
7 * Author: Graeme W. Gill
8 * Date: 28/9/97
9 *
10 * Copyright 1997 - 2013 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 /* These routines supliement the class code in ntio.c and unixio.c */
18 /* with common and USB specific routines */
19 /* Rename to icoms.c ?? */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <time.h>
25 #include <signal.h>
26 #if defined(UNIX)
27 #include <termios.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #endif
31 #ifndef SALONEINSTLIB
32 #include "copyright.h"
33 #include "aconfig.h"
34 #else
35 #include "sa_config.h"
36 #endif
37 #include "numsup.h"
38 #include "xspect.h"
39 #include "insttypes.h"
40 #include "conv.h"
41 #include "icoms.h"
42
43
44 /* ----------------------------------------------------- */
45
46 /* Fake display & instrument device */
47 icompath icomFakeDevice = { instFakeDisp, "Fake Display Device" };
48
49
50
51 /* Free an icompath */
52 static
icompath_del_contents(icompath * p)53 void icompath_del_contents(icompath *p) {
54
55 if (p->name != NULL)
56 free(p->name);
57 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
58 if (p->spath != NULL)
59 free(p->spath);
60 #endif /* ENABLE_SERIAL */
61 #ifdef ENABLE_USB
62 usb_del_usb_idevice(p->usbd);
63 hid_del_hid_idevice(p->hidd);
64 #endif /* ENABLE_USB */
65 }
66
67 /* Free an icompath */
icompath_del(icompath * p)68 static void icompath_del(icompath *p) {
69
70 icompath_del_contents(p);
71 free(p);
72 }
73
74 /* Delete the last combined path */
75 /* (Assume this is before icompaths_make_dslists() has been called) */
icompaths_del_last_path(icompaths * p)76 static void icompaths_del_last_path(
77 icompaths *p
78 ) {
79 icom_dtix ix = dtix_combined;
80
81 if (p->ndpaths[ix] == 0)
82 return;
83
84 icompath_del(p->dpaths[ix][p->ndpaths[ix]-1]);
85 p->dpaths[ix][p->ndpaths[ix]-1] = NULL;
86 p->ndpaths[ix]--;
87 }
88
89 /* Return the last combined path */
90 /* (Assume this is before icompaths_make_dslists() has been called) */
icompaths_get_last_path(icompaths * p)91 static icompath *icompaths_get_last_path(
92 icompaths *p
93 ) {
94 icom_dtix ix = dtix_combined;
95
96 if (p->ndpaths[ix] == 0)
97 return NULL;
98
99 return p->dpaths[ix][p->ndpaths[ix]-1];
100 }
101
102 /* Return the instrument path corresponding to the port number, or NULL if out of range */
icompaths_get_path(icompaths * p,int port)103 static icompath *icompaths_get_path(
104 icompaths *p,
105 int port /* Enumerated port number, 1..n */
106 ) {
107 if (port == FAKE_DEVICE_PORT)
108 return &icomFakeDevice;
109
110
111
112 if (port <= 0 || port > p->ndpaths[dtix_inst])
113 return NULL;
114
115 return p->dpaths[dtix_inst][port-1];
116 }
117
118 /* Return the device path corresponding to the port number, or NULL if out of range */
icompaths_get_path_sel(icompaths * p,icom_type dctype,int port)119 static icompath *icompaths_get_path_sel(
120 icompaths *p,
121 icom_type dctype, /* Device type list */
122 int port /* Enumerated port number, 1..n */
123 ) {
124 /* Check it is an enumeration */
125 if (dctype != dtix_combined
126 && dctype != dtix_inst
127 && dctype != dtix_3dlut
128 && dctype != dtix_vtpg
129 && dctype != dtix_printer)
130 return NULL;
131
132 if (dctype == dtix_inst)
133 return icompaths_get_path(p, port);
134
135 if (port <= 0 || port > p->ndpaths[dctype])
136 return NULL;
137
138 return p->dpaths[dctype][port-1];
139 }
140
141 /* Clear a single device paths list */
icompaths_clear(icompaths * p,icom_dtix ix)142 static void icompaths_clear(icompaths *p, icom_dtix ix) {
143
144 if (p->dpaths[ix] != NULL) {
145 int i;
146 /* If underlying owner of icompaths */
147 if (ix == dtix_combined) {
148 for (i = 0; i < p->ndpaths[ix]; i++) {
149 icompath_del(p->dpaths[ix][i]);
150 }
151 }
152 free(p->dpaths[ix]);
153 p->dpaths[ix] = NULL;
154 p->ndpaths[ix] = 0;
155
156 /* Clear instrument alias */
157 if (ix == dtix_inst) {
158 p->npaths = 0;
159 p->paths = NULL;
160 }
161 }
162 }
163
164 /* Clear all device paths */
icompaths_clear_all(icompaths * p)165 static void icompaths_clear_all(icompaths *p) {
166
167 if (p == NULL)
168 return;
169
170 /* Free any old instrument list */
171 icompaths_clear(p, dtix_inst);
172 icompaths_clear(p, dtix_3dlut);
173 icompaths_clear(p, dtix_vtpg);
174 icompaths_clear(p, dtix_printer);
175 icompaths_clear(p, dtix_combined);
176 }
177
178 /* Add the give path to the given list. */
179 /* If the path is NULL, allocat an empty */
180 /* one and add it to the combined list */
181 /* Return icom error */
icompaths_add_path(icompaths * p,int ix,icompath * xp)182 static int icompaths_add_path(icompaths *p, int ix, icompath *xp) {
183 if (xp == NULL)
184 ix = dtix_combined;
185 if (p->dpaths[ix] == NULL) {
186 if ((p->dpaths[ix] = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
187 a1loge(p->log, ICOM_SYS, "icompaths: calloc failed!\n");
188 return ICOM_SYS;
189 }
190 } else {
191 icompath **npaths;
192 if ((npaths = (icompath **)realloc(p->dpaths[ix],
193 sizeof(icompath *) * (p->ndpaths[ix] + 2))) == NULL) {
194 a1loge(p->log, ICOM_SYS, "icompaths: realloc failed!\n");
195 return ICOM_SYS;
196 }
197 p->dpaths[ix] = npaths;
198 p->dpaths[ix][p->ndpaths[ix]+1] = NULL;
199 }
200 if (xp == NULL) {
201 if ((xp = calloc(sizeof(icompath), 1)) == NULL) {
202 a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
203 return ICOM_SYS;
204 }
205 }
206 p->dpaths[ix][p->ndpaths[ix]] = xp;
207 p->ndpaths[ix]++;
208 p->dpaths[ix][p->ndpaths[ix]] = NULL;
209 return ICOM_OK;
210 }
211
212 /* Based on each icompath's dctype, create aliase lists for everything */
213 /* on the combined path based on each device type. */
214 /* (We are only called after clearing all lists) */
icompaths_make_dslists(icompaths * p)215 int icompaths_make_dslists(icompaths *p) {
216 int rv, i;
217
218 for (i = 0; i < p->ndpaths[dtix_combined]; i++) {
219 icompath *xp = p->dpaths[dtix_combined][i];
220
221 if (xp == NULL)
222 break;
223
224 a1logd(g_log, 8, "icompaths_make_dslists '%s' dctype 0x%x\n",xp->name,xp->dctype);
225
226 if (xp->dctype & icomt_instrument) {
227 if ((rv = icompaths_add_path(p, dtix_inst, xp)) != ICOM_OK)
228 return rv;
229 }
230 if (xp->dctype & icomt_3dlut) {
231 if ((rv = icompaths_add_path(p, dtix_3dlut, xp)) != ICOM_OK)
232 return rv;
233 }
234 if (xp->dctype & icomt_vtpg) {
235 if ((rv = icompaths_add_path(p, dtix_vtpg, xp)) != ICOM_OK)
236 return rv;
237 }
238 if (xp->dctype & icomt_printer) {
239 if ((rv = icompaths_add_path(p, dtix_printer, xp)) != ICOM_OK)
240 return rv;
241 }
242 }
243
244 /* Maintain backwards compatible instrument list alias */
245 p->npaths = p->ndpaths[dtix_inst];
246 p->paths = p->dpaths[dtix_inst];
247
248 return ICOM_OK;
249 }
250
251 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
252
253 /* Add a serial path. */
254 /* return icom error */
icompaths_add_serial(icompaths * p,char * name,char * spath,icom_type dctype)255 static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_type dctype) {
256 icom_dtix ix = dtix_combined;
257 icompath *xp;
258 int rv;
259
260 if ((rv = icompaths_add_path(p, ix, NULL)) != ICOM_OK)
261 return rv;
262
263 xp = p->dpaths[ix][p->ndpaths[ix]-1];
264
265 a1logd(g_log, 8, "icompaths_add_serial got '%s' dctype 0x%x\n",name,dctype);
266
267 /* Type of port, port attributes, device category */
268 xp->dctype |= icomt_cat_any; /* Assume any for now */
269 xp->dctype |= icomt_serial;
270 xp->dctype |= icomt_seriallike;
271 xp->dctype |= dctype;
272
273 if ((xp->name = strdup(name)) == NULL) {
274 a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
275 return ICOM_SYS;
276 }
277 if ((xp->spath = strdup(spath)) == NULL) {
278 a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
279 return ICOM_SYS;
280 }
281
282 a1logd(g_log, 8, "icompaths_add_serial returning '%s' dctype 0x%x\n",xp->name,xp->dctype);
283
284 return ICOM_OK;
285 }
286
287 /* Modify a serial path to add the device type */
icompaths_set_serial_itype(icompath * p,devType itype)288 int icompaths_set_serial_itype(icompath *p, devType itype) {
289 char pname[400], *cp;
290
291 /* Convert device type to category */
292 p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
293
294 p->itype = itype;
295
296 /* Strip any existing description in brackets */
297 if ((cp = strchr(p->name, '(')) != NULL && cp > p->name)
298 cp[-1] = '\000';
299 sprintf(pname,"%s (%s)", p->name, inst_name(itype));
300 cp = p->name;
301 if ((p->name = strdup(pname)) == NULL) {
302 p->name = cp;
303 a1loge(g_log, ICOM_SYS, "icompaths_set_serial_itype: strdup path failed!\n");
304 return ICOM_SYS;
305 }
306 free(cp);
307
308 a1logd(g_log, 8, "icompaths_set_serial_itype '%s' returning dctype 0x%x\n",p->name,p->dctype);
309
310 return ICOM_OK;
311 }
312
313 #endif /* ENABLE_SERIAL */
314
315 #ifdef ENABLE_USB
316
317 /* Set an icompath details. */
318 /* return icom error */
319 static
icompath_set_usb(a1log * log,icompath * p,char * name,unsigned int vid,unsigned int pid,int nep,struct usb_idevice * usbd,devType itype)320 int icompath_set_usb(a1log *log, icompath *p, char *name, unsigned int vid, unsigned int pid,
321 int nep, struct usb_idevice *usbd, devType itype) {
322 int rv;
323
324
325 if ((p->name = strdup(name)) == NULL) {
326 a1loge(log, ICOM_SYS, "icompath: strdup failed!\n");
327 return ICOM_SYS;
328 }
329
330 a1logd(g_log, 8, "icompath_set_usb '%s' got dctype 0x%x\n",p->name,p->dctype);
331
332 p->dctype |= icomt_usb;
333 p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
334
335 p->nep = nep;
336 p->vid = vid;
337 p->pid = pid;
338 p->usbd = usbd;
339 p->itype = itype;
340
341 a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",p->name,p->dctype);
342
343 return ICOM_OK;
344 }
345
346 /* Add a usb path. usbd is taken, others are copied. */
347 /* return icom error */
icompaths_add_usb(icompaths * p,char * name,unsigned int vid,unsigned int pid,int nep,struct usb_idevice * usbd,devType itype)348 static int icompaths_add_usb(icompaths *p, char *name, unsigned int vid, unsigned int pid,
349 int nep, struct usb_idevice *usbd, devType itype) {
350 icom_dtix ix = dtix_combined;
351 icompath *xp;
352 int rv;
353
354 if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
355 return rv;
356
357 xp = p->dpaths[ix][p->ndpaths[ix]-1];
358
359 return icompath_set_usb(p->log, xp, name, vid, pid, nep, usbd, itype);
360 }
361
362 /* Add an hid path. hidd is taken, others are copied. */
363 /* return icom error */
icompaths_add_hid(icompaths * p,char * name,unsigned int vid,unsigned int pid,int nep,struct hid_idevice * hidd,devType itype)364 static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigned int pid,
365 int nep, struct hid_idevice *hidd, devType itype) {
366 icom_dtix ix = dtix_combined;
367 icompath *xp;
368 int rv;
369
370 if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
371 return rv;
372
373 xp = p->dpaths[ix][p->ndpaths[ix]-1];
374
375 a1logd(g_log, 8, "icompaths_add_hid '%s' got dctype 0x%x\n",xp->name,xp->dctype);
376
377 xp->dctype |= icomt_hid;
378 xp->dctype = (xp->dctype & ~icomt_cat_mask) | inst_category(itype);
379
380 if ((xp->name = strdup(name)) == NULL) {
381 a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
382 return ICOM_SYS;
383 }
384
385 xp->nep = nep;
386 xp->vid = vid;
387 xp->pid = pid;
388 xp->hidd = hidd;
389 xp->itype = itype;
390
391 a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",xp->name,xp->dctype);
392
393 return ICOM_OK;
394 }
395 #endif /* ENABLE_USB */
396
icompaths_del(icompaths * p)397 static void icompaths_del(icompaths *p) {
398 if (p != NULL) {
399 icompaths_clear_all(p);
400
401 p->log = del_a1log(p->log); /* Unreference it and set to NULL */
402 free(p);
403 }
404 }
405
406 /* Create and return a list of available serial ports or USB devices for this system. */
407 /* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
408 /* to determine serial ports, and use libusb to discover USB devices. */
409 /* return icom error */
icompaths_refresh_paths_sel(icompaths * p,icom_type mask)410 int icompaths_refresh_paths_sel(icompaths *p, icom_type mask) {
411 int rv, usbend = 0;
412 int i, j;
413
414 a1logd(p->log, 7, "icoms_refresh_paths: called with mask = %d\n",mask);
415
416 /* Clear any existing device paths */
417 p->clear(p);
418
419 #ifdef ENABLE_USB
420 if (mask & icomt_hid) {
421 a1logd(p->log, 6, "icoms_refresh_paths: looking for HID device\n");
422 if ((rv = hid_get_paths(p)) != ICOM_OK)
423 return rv;
424 }
425 if (mask & icomt_usb) {
426 a1logd(p->log, 6, "icoms_refresh_paths: looking for USB device\n");
427 if ((rv = usb_get_paths(p)) != ICOM_OK)
428 return rv;
429 }
430 usbend = p->ndpaths[dtix_combined];
431 a1logd(p->log, 6, "icoms_refresh_paths: now got %d paths\n",usbend);
432 #endif /* ENABLE_USB */
433
434 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
435
436 if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
437 a1logd(p->log, 6, "icoms_refresh_paths: looking for serial ports\n");
438 if ((rv = serial_get_paths(p, mask)) != ICOM_OK)
439 return rv;
440
441 }
442 #endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL */
443
444 /* Sort the COM keys so people don't get confused... */
445 /* Sort identified instruments ahead of unknown serial ports */
446 a1logd(p->log, 6, "icoms_refresh_paths: we now have %d devices and are about to sort them\n",p->ndpaths[dtix_combined]);
447
448 {
449 icompath **pl = p->dpaths[dtix_combined];
450 int np = p->ndpaths[dtix_combined];
451
452 for (i = usbend; i < (np-1); i++) {
453 for (j = i+1; j < np; j++) {
454 if ((pl[i]->itype == instUnknown && pl[j]->itype != instUnknown)
455 || (((pl[i]->itype == instUnknown && pl[j]->itype == instUnknown)
456 || (pl[i]->itype != instUnknown && pl[j]->itype != instUnknown))
457 && strcmp(pl[i]->name, pl[j]->name) > 0)) {
458 icompath *tt = pl[i];
459 pl[i] = pl[j];
460 pl[j] = tt;
461 }
462 }
463 }
464 }
465
466 /* Create the device specific lists */
467 if ((rv = icompaths_make_dslists(p)) != ICOM_OK) {
468 a1logd(p->log, 1, "icoms_refresh_paths: icompaths_make_dslists failed with %d\n",rv);
469 return rv;
470 }
471
472 a1logd(p->log, 8, "icoms_refresh_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
473
474 return ICOM_OK;
475 }
476
477 /* (In implementation specific) */
478 int serial_is_open(icoms *p);
479 void serial_close_port(icoms *p);
480
481 /* Close the port */
icoms_close_port(icoms * p)482 static void icoms_close_port(icoms *p) {
483 if (p->is_open) {
484 #ifdef ENABLE_USB
485 if (p->usbd) {
486 usb_close_port(p);
487 } else if (p->hidd) {
488 hid_close_port(p);
489 }
490 #endif
491 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
492 if (serial_is_open(p)) {
493 serial_close_port(p);
494 }
495 #endif /* ENABLE_SERIAL */
496 p->is_open = 0;
497 }
498 }
499
icompaths_refresh_paths(icompaths * p)500 int icompaths_refresh_paths(icompaths *p) {
501 return icompaths_refresh_paths_sel(p, icomt_instrument | icomt_portattr_all);
502 }
503
504 /* Allocate an icom paths and set it to the list of available devices */
505 /* that match the icom_type mask. */
506 /* Return NULL on error */
new_icompaths_sel(a1log * log,icom_type mask)507 icompaths *new_icompaths_sel(a1log *log, icom_type mask) {
508 icompaths *p;
509 if ((p = (icompaths *)calloc(sizeof(icompaths), 1)) == NULL) {
510 a1loge(log, ICOM_SYS, "new_icompath: calloc failed!\n");
511 return NULL;
512 }
513
514 p->log = new_a1log_d(log);
515
516 p->clear = icompaths_clear_all;
517 p->refresh = icompaths_refresh_paths;
518 p->refresh_sel = icompaths_refresh_paths_sel;
519 p->get_path = icompaths_get_path;
520 p->get_path_sel = icompaths_get_path_sel;
521 p->del = icompaths_del;
522
523 /* ====== internal implementation ======= */
524 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
525 p->add_serial = icompaths_add_serial;
526 #endif /* ENABLE_SERIAL */
527 #ifdef ENABLE_USB
528 p->add_usb = icompaths_add_usb;
529 p->add_hid = icompaths_add_hid;
530 #endif /* ENABLE_USB */
531 p->del_last_path = icompaths_del_last_path;
532 p->get_last_path = icompaths_get_last_path;
533 /* ====================================== */
534
535 if (icompaths_refresh_paths_sel(p, mask)) {
536 a1loge(log, ICOM_SYS, "new_icompaths: icompaths_refresh_paths failed!\n");
537 free(p);
538 return NULL;
539 }
540
541 return p;
542 }
543
544 /* Allocate an icom paths and set it to the list of available instruments */
545 /* Return NULL on error */
new_icompaths(a1log * log)546 icompaths *new_icompaths(a1log *log) {
547 return new_icompaths_sel(log, icomt_instrument | icomt_portattr_all);
548 }
549
550
551 /* ----------------------------------------------------- */
552
553 /* Copy an icompath into an icom */
554 /* return icom error */
icom_copy_path_to_icom(icoms * p,icompath * pp)555 static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
556 int rv;
557
558 if (p->name != NULL)
559 free(p->name);
560 if ((p->name = strdup(pp->name)) == NULL) {
561 a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc name failed\n");
562 return ICOM_SYS;
563 }
564 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
565 if (pp->spath != NULL) {
566 if ((p->spath = strdup(pp->spath)) == NULL) {
567 a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc spath failed\n");
568 return ICOM_SYS;
569 }
570 } else {
571 p->spath = NULL;
572 }
573 #endif /* ENABLE_SERIAL */
574 #ifdef ENABLE_USB
575 p->nep = pp->nep;
576 p->vid = pp->vid;
577 p->pid = pp->pid;
578 if ((rv = usb_copy_usb_idevice(p, pp)) != ICOM_OK)
579 return rv;
580 if ((rv = hid_copy_hid_idevice(p, pp)) != ICOM_OK)
581 return rv;
582 #endif
583 p->dctype = pp->dctype;
584 p->itype = pp->itype;
585
586 a1logd(g_log, 8, "icom_copy_path_to_icom '%s' returning dctype 0x%x\n",p->name,p->dctype);
587
588 return ICOM_OK;
589 }
590
591 /* Return the device category */
592 /* (Returns bit flags) */
icoms_cat_type(icoms * p)593 static icom_type icoms_cat_type(
594 icoms *p
595 ) {
596 return p->dctype & icomt_cat_mask;
597 }
598
599 /* Return the communication port type */
600 /* (Can use equality tests on return value) */
icoms_port_type(icoms * p)601 static icom_type icoms_port_type(
602 icoms *p
603 ) {
604 return p->dctype & icomt_port_mask;
605 }
606
607 /* Return the communication port attributes */
608 /* (Returns bit flags) */
icoms_port_attr(icoms * p)609 static icom_type icoms_port_attr(
610 icoms *p
611 ) {
612 return p->dctype & icomt_attr_mask;
613 }
614
615 /* ----------------------------------------------------- */
616
617 /* Include the icoms implementation dependent function implementations */
618 #ifdef NT
619 # include "icoms_nt.c"
620 #endif
621 #if defined(UNIX)
622 # include "icoms_ux.c"
623 #endif
624
625 /* write and read convenience function with read flush */
626 /* return icom error */
627 static int
icoms_write_read_ex(icoms * p,char * wbuf,int nwch,char * rbuf,int bsize,int * bread,char * tc,int ntc,double tout,int frbw)628 icoms_write_read_ex(
629 icoms *p,
630 char *wbuf, /* Write puffer */
631 int nwch, /* if > 0, number of characters to write, else nul terminated */
632 char *rbuf, /* Read buffer */
633 int bsize, /* Buffer size */
634 int *bread, /* Bytes read (not including forced '\000') */
635 char *tc, /* Terminating characers, NULL for none or char count mode */
636 int ntc, /* Number of terminating characters needed, or char count needed */
637 double tout, /* Timeout for write and then read (i.e. max = 2 x tout) */
638 int frbw /* nz to Flush Read Before Write */
639 ) {
640 int rv = ICOM_OK;
641
642 a1logd(p->log, 8, "icoms_write_read: called\n");
643
644 if (p->write == NULL || p->read == NULL) { /* Neither serial nor USB ? */
645 a1loge(p->log, ICOM_NOTS, "icoms_write_read: No write and read functions set!\n");
646 return ICOM_NOTS;
647 }
648
649 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
650 /* Flush any stray chars if serial */
651 if (frbw && (p->dctype & icomt_serial)) {
652 char tbuf[500];
653 int debug = p->log->debug;
654 int bread;
655
656 if (debug < 8)
657 p->log->debug = 0;
658 for (;;) {
659 bread = 0;
660 p->read(p, tbuf, 500, &bread, NULL, 500, 0.02);
661 if (bread == 0)
662 break;
663 }
664 p->log->debug = debug;
665 rv = ICOM_OK;
666 }
667 #endif
668
669 /* Write the write data */
670 rv = p->write(p, wbuf, nwch, tout);
671
672 /* Return error if coms */
673 if (rv != ICOM_OK) {
674 a1logd(p->log, 8, "icoms_write_read: failed - returning 0x%x\n",rv);
675 return rv;
676 }
677
678 /* Read response */
679 rv = p->read(p, rbuf, bsize, bread, tc, ntc, tout);
680
681 a1logd(p->log, 8, "icoms_write_read: returning 0x%x\n",rv);
682
683 return rv;
684 }
685
686 /* write and read convenience function */
687 /* return icom error */
688 static int
icoms_write_read(icoms * p,char * wbuf,int nwch,char * rbuf,int bsize,int * bread,char * tc,int ntc,double tout)689 icoms_write_read(
690 icoms *p,
691 char *wbuf, /* Write puffer */
692 int nwch, /* if > 0, number of characters to write, else nul terminated */
693 char *rbuf, /* Read buffer */
694 int bsize, /* Buffer size */
695 int *bread, /* Bytes read (not including forced '\000') */
696 char *tc, /* Terminating characers, NULL for none or char count mode */
697 int ntc, /* Number of terminating characters needed, or char count needed */
698 double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
699 ) {
700 return icoms_write_read_ex(p, wbuf, nwch, rbuf, bsize, bread, tc, ntc, tout, 0);
701 }
702
703 /* Optional callback to client from device */
704 /* Default implementation is a NOOP */
icoms_interrupt(icoms * p,int icom_int)705 static int icoms_interrupt(icoms *p,
706 int icom_int /* Interrupt cause */
707 ) {
708 return ICOM_OK;
709 }
710
711 /* Destroy ourselves */
712 static void
icoms_del(icoms * p)713 icoms_del(icoms *p) {
714 a1logd(p->log, 8, "icoms_del: called\n");
715 if (p->is_open) {
716 a1logd(p->log, 8, "icoms_del: closing port\n");
717 p->close_port(p);
718 }
719 #ifdef ENABLE_USB
720 usb_del_usb(p);
721 hid_del_hid(p);
722 #endif
723 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
724 if (p->spath != NULL)
725 free(p->spath);
726 #endif
727 p->log = del_a1log(p->log);
728 if (p->name != NULL)
729 free(p->name);
730 p->log = del_a1log(p->log); /* unref */
731 free (p);
732 }
733
734 /* icoms Constructor */
735 /* Return NULL on error */
new_icoms(icompath * ipath,a1log * log)736 icoms *new_icoms(
737 icompath *ipath, /* instrument to open */
738 a1log *log /* log to take reference from, NULL for default */
739 ) {
740 icoms *p;
741
742 a1logd(log, 2, "new_icoms '%s' itype '%s' dctype 0x%x\n",ipath->name,inst_sname(ipath->itype),ipath->dctype);
743
744 if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL) {
745 a1loge(log, ICOM_SYS, "new_icoms: calloc failed!\n");
746 return NULL;
747 }
748
749 if ((p->name = strdup(ipath->name)) == NULL) {
750 a1loge(log, ICOM_SYS, "new_icoms: strdup failed!\n");
751 return NULL;
752 }
753 p->itype = ipath->itype;
754
755 /* Copy ipath info to this icoms */
756 if (icom_copy_path_to_icom(p, ipath)) {
757 free(p->name);
758 free(p);
759 return NULL;
760 }
761
762 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
763 #ifdef NT
764 p->phandle = NULL;
765 #endif
766 #ifdef UNIX
767 p->fd = -1;
768 #endif
769 p->fc = fc_nc;
770 p->br = baud_nc;
771 p->py = parity_nc;
772 p->sb = stop_nc;
773 p->wl = length_nc;
774 #endif /* ENABLE_SERIAL */
775
776 p->lserr = 0;
777 // p->tc = -1;
778
779 p->log = new_a1log_d(log);
780 p->debug = p->log->debug; /* Legacy code */
781
782 p->close_port = icoms_close_port;
783
784 p->dev_cat = icoms_cat_type;
785 p->port_type = icoms_port_type;
786 p->port_attr = icoms_port_attr;
787
788 #if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
789 p->set_ser_port_ex = icoms_set_ser_port_ex;
790 p->set_ser_port = icoms_set_ser_port;
791 #endif /* ENABLE_SERIAL */
792
793 p->write = NULL; /* Serial open or set_methods will set */
794 p->read = NULL;
795 p->write_read = icoms_write_read;
796 p->write_read_ex = icoms_write_read_ex;
797 p->interrupt = icoms_interrupt;
798
799 p->del = icoms_del;
800
801 #ifdef ENABLE_USB
802 usb_set_usb_methods(p);
803 hid_set_hid_methods(p);
804 #endif /* ENABLE_USB */
805
806 return p;
807 }
808
809 /* ---------------------------------------------------------------------------------*/
810 /* utilities */
811
812 /* Emit a "normal" beep */
normal_beep()813 void normal_beep() {
814 /* 0msec delay, 1.0KHz for 200 msec */
815 msec_beep(0, 1000, 200);
816 }
817
818 /* Emit a "good" beep */
good_beep()819 void good_beep() {
820 /* 0msec delay, 1.2KHz for 200 msec */
821 msec_beep(0, 1200, 200);
822 }
823
824 /* Emit a "bad" double beep */
bad_beep()825 void bad_beep() {
826 /* 0 msec delay, 800Hz for 200 msec */
827 msec_beep(0, 800, 200);
828 /* 350 msec delay, 800Hz for 200 msec */
829 msec_beep(350, 800, 200);
830 }
831
baud_rate_to_str(baud_rate br)832 char *baud_rate_to_str(baud_rate br) {
833 switch (br) {
834 case baud_nc:
835 return "Not Configured";
836 case baud_110:
837 return "110";
838 case baud_300:
839 return "300";
840 case baud_600:
841 return "600";
842 case baud_1200:
843 return "1400";
844 case baud_2400:
845 return "2400";
846 case baud_4800:
847 return "4800";
848 case baud_9600:
849 return "9600";
850 case baud_14400:
851 return "14400";
852 case baud_19200:
853 return "19200";
854 case baud_38400:
855 return "38400";
856 case baud_57600:
857 return "57600";
858 case baud_115200:
859 return "115200";
860 case baud_921600:
861 return "921600";
862 }
863 return "Unknown";
864 }
865
866 /* Convert control chars to ^[A-Z] notation in a string */
867 /* Can be called 3 times without reusing the static buffer */
868 /* Returns a maximum of 5000 characters */
869 char *
icoms_fix(char * ss)870 icoms_fix(char *ss) {
871 static unsigned char buf[3][10005];
872 static int ix = 0;
873 unsigned char *d;
874 unsigned char *s = (unsigned char *)ss;
875 if (++ix >= 3)
876 ix = 0;
877 if (ss == NULL) {
878 strcpy((char *)buf[ix],"(null)");
879 return (char *)buf[ix];
880 }
881 for(d = buf[ix]; (d - buf[ix]) < 10000;) {
882 if (*s < ' ' && *s > '\000') {
883 *d++ = '^';
884 *d++ = *s++ + '@';
885 } else if (*s >= 0x80) {
886 *d++ = '\\';
887 *d++ = '0' + ((*s >> 6) & 0x3);
888 *d++ = '0' + ((*s >> 3) & 0x7);
889 *d++ = '0' + ((*s++ >> 0) & 0x7);
890 } else {
891 *d++ = *s++;
892 }
893 if (s[-1] == '\000')
894 break;
895 }
896 *d++ = '.';
897 *d++ = '.';
898 *d++ = '.';
899 *d++ = '\000';
900 return (char *)buf[ix];
901 }
902
903 /* Convert a limited binary buffer to a list of hex */
904 char *
icoms_tohex(unsigned char * s,int len)905 icoms_tohex(unsigned char *s, int len) {
906 static char buf[64 * 3 + 10];
907 int i;
908 char *d;
909
910 buf[0] = '\000';
911 for(i = 0, d = buf; i < 64 && i < len; i++, s++) {
912 sprintf(d, "%s%02x", i > 0 ? " " : "", *s);
913 d += strlen(d);
914 }
915 if (i < len)
916 sprintf(d, " ...");
917
918 return buf;
919 }
920
921