diff options
Diffstat (limited to 'spectro/icoms.c')
-rw-r--r-- | spectro/icoms.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/spectro/icoms.c b/spectro/icoms.c new file mode 100644 index 0000000..0dc815c --- /dev/null +++ b/spectro/icoms.c @@ -0,0 +1,484 @@ + + /* General instrument + serial I/O support */ + +/* + * Argyll Color Correction System + * + * Author: Graeme W. Gill + * Date: 28/9/97 + * + * Copyright 1997 - 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. + */ + +/* These routines supliement the class code in ntio.c and unixio.c */ +/* with common and USB specific routines */ +/* Rename to icoms.c ?? */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <time.h> +#include <signal.h> +#if defined(UNIX) +#include <termios.h> +#include <errno.h> +#include <unistd.h> +#endif +#ifndef SALONEINSTLIB +#include "copyright.h" +#include "aconfig.h" +#else +#include "sa_config.h" +#endif +#include "numsup.h" +#include "xspect.h" +#include "insttypes.h" +#include "conv.h" +#include "icoms.h" + + +/* ----------------------------------------------------- */ + +/* Fake device */ +icompath icomFakeDevice = { "Fake Display Device" }; + +/* Return the path corresponding to the port number, or NULL if out of range */ +static icompath *icompaths_get_path( + icompaths *p, + int port /* Enumerated port number, 1..n */ +) { + if (port == -99) + return &icomFakeDevice; + + if (port <= 0 || port > p->npaths) + return NULL; + + return p->paths[port-1]; +} + +static void icompaths_clear(icompaths *p) { + + /* Free any old list */ + if (p->paths != NULL) { + int i; + for (i = 0; i < p->npaths; i++) { + if (p->paths[i]->name != NULL) + free(p->paths[i]->name); +#ifdef ENABLE_SERIAL + if (p->paths[i]->spath != NULL) + free(p->paths[i]->spath); +#endif /* ENABLE_SERIAL */ +#ifdef ENABLE_USB + usb_del_usb_idevice(p->paths[i]->usbd); + hid_del_hid_idevice(p->paths[i]->hidd); +#endif /* ENABLE_USB */ + free(p->paths[i]); + } + free(p->paths); + p->npaths = 0; + p->paths = NULL; + } +} + +/* Add an empty new path. */ +/* Return icom error */ +static int icompaths_add_path(icompaths *p) { + if (p->paths == NULL) { + if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: calloc failed!\n"); + return ICOM_SYS; + } + } else { + icompath **npaths; + if ((npaths = (icompath **)realloc(p->paths, + sizeof(icompath *) * (p->npaths + 2))) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: realloc failed!\n"); + return ICOM_SYS; + } + p->paths = npaths; + p->paths[p->npaths+1] = NULL; + } + if ((p->paths[p->npaths] = calloc(sizeof(icompath), 1)) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n"); + return ICOM_SYS; + } + p->npaths++; + p->paths[p->npaths] = NULL; + return ICOM_OK; +} + +#ifdef ENABLE_SERIAL + +/* Add a serial path */ +/* return icom error */ +static int icompaths_add_serial(icompaths *p, char *name, char *spath) { + int rv; + + if ((rv = icompaths_add_path(p)) != ICOM_OK) + return rv; + + if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n"); + return ICOM_SYS; + } + if ((p->paths[p->npaths-1]->spath = strdup(spath)) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n"); + return ICOM_SYS; + } + return ICOM_OK; +} + +#endif /* ENABLE_SERIAL */ + +#ifdef ENABLE_USB + +/* Set an icompath details */ +/* return icom error */ +int icompath_set_usb(a1log *log, icompath *p, char *name, unsigned int vid, unsigned int pid, + int nep, struct usb_idevice *usbd, instType itype) { + int rv; + + if ((p->name = strdup(name)) == NULL) { + a1loge(log, ICOM_SYS, "icompath: strdup failed!\n"); + return ICOM_SYS; + } + + p->nep = nep; + p->vid = vid; + p->pid = pid; + p->usbd = usbd; + p->itype = itype; + + return ICOM_OK; +} + +/* Add a usb path. usbd is taken, others are copied. */ +/* return icom error */ +static int icompaths_add_usb(icompaths *p, char *name, unsigned int vid, unsigned int pid, + int nep, struct usb_idevice *usbd, instType itype) { + int rv; + + if ((rv = icompaths_add_path(p)) != ICOM_OK) + return rv; + + return icompath_set_usb(p->log, p->paths[p->npaths-1], name, vid, pid, nep, usbd, itype); + + return ICOM_OK; +} + +/* Add an hid path. hidd is taken, others are copied. */ +/* return icom error */ +static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigned int pid, + int nep, struct hid_idevice *hidd, instType itype) { + int rv; + + if ((rv = icompaths_add_path(p)) != ICOM_OK) + return rv; + + if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) { + a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n"); + return ICOM_SYS; + } + + p->paths[p->npaths-1]->nep = nep; + p->paths[p->npaths-1]->vid = vid; + p->paths[p->npaths-1]->pid = pid; + p->paths[p->npaths-1]->hidd = hidd; + p->paths[p->npaths-1]->itype = itype; + + return ICOM_OK; +} +#endif /* ENABLE_USB */ + +static void icompaths_del(icompaths *p) { + icompaths_clear(p); + + p->log = del_a1log(p->log); /* Unreference it */ + free(p); +} + +int icompaths_refresh_paths(icompaths *p); /* Defined in platform specific */ + +/* Allocate an icom paths and set it to the list of available devices */ +/* Return NULL on error */ +icompaths *new_icompaths(a1log *log) { + icompaths *p; + if ((p = (icompaths *)calloc(sizeof(icompaths), 1)) == NULL) { + a1loge(log, ICOM_SYS, "new_icompath: calloc failed!\n"); + return NULL; + } + + p->log = new_a1log_d(log); + + p->clear = icompaths_clear; + p->refresh = icompaths_refresh_paths; + p->get_path = icompaths_get_path; +#ifdef ENABLE_SERIAL + p->add_serial = icompaths_add_serial; +#endif /* ENABLE_SERIAL */ +#ifdef ENABLE_USB + p->add_usb = icompaths_add_usb; + p->add_hid = icompaths_add_hid; +#endif /* ENABLE_USB */ + p->del = icompaths_del; + + if (icompaths_refresh_paths(p)) { + a1loge(log, ICOM_SYS, "new_icompaths: icompaths_refresh_paths failed!\n"); + return NULL; + } + + return p; +} + + +/* ----------------------------------------------------- */ + +/* Copy an icompath into an icom */ +/* return icom error */ +static int icom_copy_path_to_icom(icoms *p, icompath *pp) { + int rv; + + if ((p->name = strdup(pp->name)) == NULL) { + a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc name failed\n"); + return ICOM_SYS; + } +#ifdef ENABLE_SERIAL + if (pp->spath != NULL) { + if ((p->spath = strdup(pp->spath)) == NULL) { + a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc spath failed\n"); + return ICOM_SYS; + } + } else { + p->spath = NULL; + } +#endif /* ENABLE_SERIAL */ +#ifdef ENABLE_USB + p->nep = pp->nep; + p->vid = pp->vid; + p->pid = pp->pid; + if ((rv = usb_copy_usb_idevice(p, pp)) != ICOM_OK) + return rv; + if ((rv = hid_copy_hid_idevice(p, pp)) != ICOM_OK) + return rv; +#endif + p->itype = pp->itype; + + return ICOM_OK; +} + +/* Return the port type */ +static icom_type icoms_port_type( +icoms *p +) { +#ifdef ENABLE_USB + if (p->hidd != NULL) + return icomt_hid; + if (p->usbd != NULL) + return icomt_usb; +#endif + return icomt_serial; +} + +/* ----------------------------------------------------- */ + +/* Include the icoms implementation dependent function implementations */ +#ifdef NT +# include "icoms_nt.c" +#endif +#if defined(UNIX) +# include "icoms_ux.c" +#endif + +/* write and read convenience function */ +/* return icom error */ +static int +icoms_write_read( +icoms *p, +char *wbuf, /* Write puffer */ +char *rbuf, /* Read buffer */ +int bsize, /* Buffer size */ +char tc, /* Terminating characer */ +int ntc, /* Number of terminating characters */ +double tout +) { + int rv = ICOM_OK; + + a1logd(p->log, 8, "icoms_write_read: called with '%s'\n",icoms_fix(wbuf)); + + if (p->write == NULL || p->read == NULL) { /* Neither serial nor USB ? */ + a1loge(p->log, ICOM_NOTS, "icoms_write_read: Neither serial nor USB device!\n"); + return ICOM_NOTS; + } + +#ifdef ENABLE_SERIAL + /* Flush any stray chars if serial */ + if (p->usbd == NULL && p->hidd == NULL) { + int debug = p->log->debug; + if (debug < 8) + p->log->debug = 0; + for (; rv == ICOM_OK;) /* Until we get a timeout */ + rv = p->read(p, rbuf, bsize, '\000', 100000, 0.01); + p->log->debug = debug; + rv = ICOM_OK; + } +#endif + + /* Write the write data */ + rv = p->write(p, wbuf, tout); + + /* Return error if coms */ + if (rv != ICOM_OK) { + a1logd(p->log, 8, "icoms_write_read: failed - returning 0x%x\n",rv); + return rv; + } + + /* Read response */ + rv = p->read(p, rbuf, bsize, tc, ntc, tout); + + a1logd(p->log, 8, "icoms_write_read: returning 0x%x\n",rv); + + return rv; +} + +/* icoms Constructor */ +/* Return NULL on error */ +icoms *new_icoms( + icompath *ipath, /* instrument to open */ + a1log *log /* log to take reference from, NULL for default */ +) { + icoms *p; + if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL) { + a1loge(log, ICOM_SYS, "new_icoms: calloc failed!\n"); + return NULL; + } + + if ((p->name = strdup(ipath->name)) == NULL) { + a1loge(log, ICOM_SYS, "new_icoms: strdup failed!\n"); + return NULL; + } + p->itype = ipath->itype; + + /* Copy ipath info to this icoms */ + if (icom_copy_path_to_icom(p, ipath)) { + free(p); + return NULL; + } + +#ifdef ENABLE_SERIAL +#ifdef NT + p->phandle = NULL; +#endif +#ifdef UNIX + p->fd = -1; +#endif + p->fc = fc_nc; + p->br = baud_nc; + p->py = parity_nc; + p->sb = stop_nc; + p->wl = length_nc; +#endif /* ENABLE_SERIAL */ + + p->lserr = 0; + p->tc = -1; + + p->log = new_a1log_d(log); + p->debug = p->log->debug; /* Legacy code */ + + p->close_port = icoms_close_port; + + p->port_type = icoms_port_type; +#ifdef ENABLE_SERIAL + p->set_ser_port = icoms_set_ser_port; +#endif /* ENABLE_SERIAL */ + + p->write = NULL; /* Serial open or set_methods will set */ + p->read = NULL; + p->write_read = icoms_write_read; + + p->del = icoms_del; + +#ifdef ENABLE_USB + usb_set_usb_methods(p); + hid_set_hid_methods(p); +#endif /* ENABLE_USB */ + + return p; +} + +/* ---------------------------------------------------------------------------------*/ +/* utilities */ + +/* Emit a "normal" beep */ +void normal_beep() { + /* 0msec delay, 1.0KHz for 200 msec */ + msec_beep(0, 1000, 200); +} + +/* Emit a "good" beep */ +void good_beep() { + /* 0msec delay, 1.2KHz for 200 msec */ + msec_beep(0, 1200, 200); +} + +/* Emit a "bad" double beep */ +void bad_beep() { + /* 0msec delay, 800Hz for 200 msec */ + msec_beep(0, 800, 200); + /* 500msec delay, 800Hz for 200 msec */ + msec_beep(350, 800, 200); +} + +/* Convert control chars to ^[A-Z] notation in a string */ +/* Can be called 5 times without reusing the static buffer */ +char * +icoms_fix(char *ss) { + static unsigned char buf[5][1005]; + static int ix = 0; + unsigned char *d; + unsigned char *s = (unsigned char *)ss; + if (++ix >= 5) + ix = 0; + for(d = buf[ix]; (d - buf[ix]) < 1000;) { + if (*s < ' ' && *s > '\000') { + *d++ = '^'; + *d++ = *s++ + '@'; + } else if (*s >= 0x80) { + *d++ = '\\'; + *d++ = '0' + ((*s >> 6) & 0x3); + *d++ = '0' + ((*s >> 3) & 0x7); + *d++ = '0' + ((*s++ >> 0) & 0x7); + } else { + *d++ = *s++; + } + if (s[-1] == '\000') + break; + } + *d++ = '.'; + *d++ = '.'; + *d++ = '.'; + *d++ = '\000'; + return (char *)buf[ix]; +} + +/* Convert a limited binary buffer to a list of hex */ +char * +icoms_tohex(unsigned char *s, int len) { + static char buf[64 * 3 + 10]; + int i; + char *d; + + buf[0] = '\000'; + for(i = 0, d = buf; i < 64 && i < len; i++, s++) { + sprintf(d, "%s%02x", i > 0 ? " " : "", *s); + d += strlen(d); + } + if (i < len) + sprintf(d, " ..."); + + return buf; +} + |