summaryrefslogtreecommitdiff
path: root/spectro/icoms.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/icoms.c')
-rw-r--r--spectro/icoms.c484
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;
+}
+