summaryrefslogtreecommitdiff
path: root/spectro/icoms_nt.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/icoms_nt.c')
-rw-r--r--spectro/icoms_nt.c280
1 files changed, 227 insertions, 53 deletions
diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c
index ef364c4..3caa8e0 100644
--- a/spectro/icoms_nt.c
+++ b/spectro/icoms_nt.c
@@ -16,6 +16,16 @@
#include <conio.h>
+/* Link list element to hold fast_serial port names */
+typedef struct fast_com_name {
+ char name[100];
+ struct fast_com_name *next;
+} fast_com_name;
+
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
+#endif /* ENABLE_SERIAL */
+
/* Create and return a list of available serial ports or USB instruments for this system. */
/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
/* to determine serial ports, and use libusb to discover USB instruments. */
@@ -23,9 +33,10 @@
/* return icom error */
int icompaths_refresh_paths(icompaths *p) {
int rv, usbend = 0;
- int i,j;
+ int i, j;
LONG stat;
HKEY sch; /* Serial coms handle */
+ fast_com_name *fastlist = NULL, *fn, *fn2;
a1logd(p->log, 8, "icoms_get_paths: called\n");
@@ -42,7 +53,131 @@ int icompaths_refresh_paths(icompaths *p) {
a1logd(p->log, 6, "icoms_get_paths: got %d paths, looking up the registry for serial ports\n",p->npaths);
-#ifdef ENABLE_SERIAL
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ // (Beware KEY_WOW64_64KEY ?)
+
+ /* See if there are and FTDI fast_serial ports, and make a list of them */
+ if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS",
+ 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
+ a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any FTDI serial ports\n");
+ } else {
+
+#define MXKSIZE 500
+#define MXVSIZE 300
+
+ a1logd(p->log, 6, "icoms_get_paths: looking through FTDI ports\n");
+ for (i = 0; ; i++) {
+ char ftdiname[MXKSIZE];
+ DWORD ftdisize = MXKSIZE;
+ HKEY devkey;
+
+ stat = RegEnumKeyEx(
+ sch, /* handle to key to enumerate */
+ i, /* index of subkey to enumerate */
+ ftdiname, /* address of buffer for value name */
+ &ftdisize, /* address for size of value name buffer */
+ NULL, /* reserved */
+ NULL, /* Address of value type */
+ NULL, /* Address of value buffer */
+ NULL /* Address of value buffer size */
+ );
+ if (stat == ERROR_NO_MORE_ITEMS) {
+ a1logd(p->log, 9, "icoms_get_paths: got ERROR_NO_MORE_ITEMS\n");
+ break;
+ }
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
+ break;
+ }
+ ftdiname[MXKSIZE-1] = '\000';
+
+ /* Enumerate subkeys, looking for Device Parameters/PortName */
+ if ((stat = RegOpenKeyEx(sch, ftdiname, 0, KEY_READ, &devkey)) != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: OpenKey '%s' failed with %d\n",ftdiname,stat);
+ continue;
+ }
+
+ a1logd(p->log, 6, "icoms_get_paths: looking through '%s'\n",ftdiname);
+
+ for (j = 0; ; j++) {
+ char skname[MXKSIZE + 50]; /* Allow for cat of "\Device Parameters" */
+ DWORD sksize = MXKSIZE;
+ HKEY skkey;
+ DWORD vtype;
+ char value[MXVSIZE];
+ DWORD vsize = MXVSIZE;
+
+ stat = RegEnumKeyEx(
+ devkey, /* handle to key to enumerate */
+ j, /* index of subkey to enumerate */
+ skname, /* address of buffer for value name */
+ &sksize, /* address for size of value name buffer */
+ NULL, /* reserved */
+ NULL, /* Address of value type */
+ NULL, /* Address of value buffer */
+ NULL /* Address of value buffer size */
+ );
+ if (stat == ERROR_NO_MORE_ITEMS) {
+ a1logd(p->log, 9, "icoms_get_paths: got ERROR_NO_MORE_ITEMS\n");
+ break;
+ }
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
+ break;
+ }
+ skname[MXKSIZE-1] = '\000';
+
+ /* See if there is a Device Parameters\PortName */
+ strcat(skname, "\\Device Parameters");
+
+ if ((stat = RegOpenKeyEx(devkey, skname, 0, KEY_READ, &skkey)) != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: OpenKey '%s' failed with %d\n",skname,stat);
+ continue;
+ }
+ stat = RegQueryValueEx(
+ skkey, /* handle to key to enumerate */
+ "PortName", /* address of buffer for value name */
+ NULL, /* reserved */
+ &vtype, /* Address of value type */
+ value, /* Address of value buffer */
+ &vsize /* Address of value buffer size */
+ );
+ RegCloseKey(skkey);
+
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegQueryValueEx '%s' failed with %d\n",skname,stat);
+ break;
+ }
+ if (vtype != REG_SZ) {
+ a1logw(p->log, "icoms_get_paths: RegEnumValue '%s' didn't return stringz type\n",skname);
+ continue;
+ }
+ value[MXVSIZE-1] = '\000';
+
+ if ((fn = malloc(sizeof(fast_com_name))) == NULL) {
+ a1loge(p->log, 1, "icoms_get_paths: malloc failed\n");
+ continue;
+ }
+ strcpy(fn->name, value);
+ fn->next = fastlist;
+ fastlist = fn;
+ a1logd(p->log, 2, "icoms_get_paths: got FTDI port '%s'\n",value);
+
+ }
+ if ((stat = RegCloseKey(devkey)) != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
+ }
+
+ }
+ if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
+ }
+ }
+
+
/* Look in the registry for serial ports */
if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
0, KEY_READ, &sch)) != ERROR_SUCCESS) {
@@ -52,13 +187,14 @@ int icompaths_refresh_paths(icompaths *p) {
/* Look at all the values in this key */
a1logd(p->log, 8, "icoms_get_paths: looking through all the values in the SERIALCOMM key\n");
-
+
for (i = 0; ; i++) {
- char valname[500];
- DWORD vnsize = 500;
+ char valname[MXKSIZE];
+ DWORD vnsize = MXKSIZE;
DWORD vtype;
- char value[500];
- DWORD vsize = 500;
+ char value[MXVSIZE];
+ DWORD vsize = MXVSIZE;
+ int fast = 0;
stat = RegEnumValue(
sch, /* handle to key to enumerate */
@@ -79,17 +215,36 @@ int icompaths_refresh_paths(icompaths *p) {
a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
break;
}
- valname[500-1] = '\000';
- value[500-1] = '\000';
+ valname[MXKSIZE-1] = '\000';
+ value[MXVSIZE-1] = '\000';
if (vtype != REG_SZ) {
a1logw(p->log, "icoms_get_paths: RegEnumValue didn't return stringz type\n");
continue;
}
+ /* Check if it's a fast serial port */
+ for (fn = fastlist; fn != NULL; fn = fn->next) {
+ if (strcmp(fn->name, value) == 0)
+ fast = 1;
+ }
+
/* Add the port to the list */
- p->add_serial(p, value, value);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s'\n",value);
+ p->add_serial(p, value, value, fast);
+ a1logd(p->log, 8, "icoms_get_paths: Added path '%s' fast %d\n",value,fast);
+
+ /* If fast, try and identify it */
+ if (fast) {
+ icompath *path;
+ icoms *icom;
+ if ((path = p->get_last_path(p)) != NULL
+ && (icom = new_icoms(path, p->log)) != NULL) {
+ instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
+ if (itype != instUnknown)
+ icompaths_set_serial_itype(path, itype);
+ icom->del(icom);
+ }
+ }
}
if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
@@ -97,10 +252,14 @@ int icompaths_refresh_paths(icompaths *p) {
#endif /* ENABLE_SERIAL */
/* Sort the COM keys so people don't get confused... */
+ /* Sort identified instruments ahead of unknown serial ports */
a1logd(p->log, 6, "icoms_get_paths: we now have %d entries and are about to sort them\n",p->npaths);
for (i = usbend; i < (p->npaths-1); i++) {
for (j = i+1; j < p->npaths; j++) {
- if (strcmp(p->paths[i]->name, p->paths[j]->name) > 0) {
+ if ((p->paths[i]->itype == instUnknown && p->paths[j]->itype != instUnknown)
+ || (((p->paths[i]->itype == instUnknown && p->paths[j]->itype == instUnknown)
+ || (p->paths[i]->itype != instUnknown && p->paths[j]->itype != instUnknown))
+ && strcmp(p->paths[i]->name, p->paths[j]->name) > 0)) {
icompath *tt = p->paths[i];
p->paths[i] = p->paths[j];
p->paths[j] = tt;
@@ -110,6 +269,12 @@ int icompaths_refresh_paths(icompaths *p) {
a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ /* Free fast list */
+ for (fn = fastlist; fn != NULL; fn = fn2) {
+ fn2 = fn->next;
+ free(fn);
+ }
+
return ICOM_OK;
}
@@ -124,7 +289,7 @@ static void icoms_close_port(icoms *p) {
hid_close_port(p);
}
#endif
-#ifdef ENABLE_SERIAL
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
if (p->phandle != NULL) {
CloseHandle(p->phandle);
}
@@ -133,10 +298,14 @@ static void icoms_close_port(icoms *p) {
}
}
-#ifdef ENABLE_SERIAL
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
static int icoms_ser_write(icoms *p, char *wbuf, double tout);
-static int icoms_ser_read(icoms *p, char *rbuf, int bsize, char tc, int ntc, double tout);
+static int icoms_ser_read(icoms *p, char *rbuf, int bsize, char *tc, int ntc, double tout);
+
+#ifndef CBR_921600
+# define CBR_921600 921600
+#endif
/* Set the serial port characteristics */
/* This always re-opens the port */
@@ -150,6 +319,7 @@ parity parity,
stop_bits stop,
word_length word)
{
+
a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
" Port name = %s\n"
" Flow control = %d\n"
@@ -180,10 +350,15 @@ word_length word)
/* Make sure the port is open */
if (!p->is_open) {
+ char buf[50]; /* Temporary for COM device path */
+
a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
+ /* Workaround bug of ports > COM9 */
+ sprintf(buf, "\\\\.\\%s", p->spath);
+
if ((p->phandle = CreateFile(
- p->spath,
+ buf,
GENERIC_READ|GENERIC_WRITE,
0, /* Exclusive access */
NULL, /* No security */
@@ -191,7 +366,7 @@ word_length word)
0, /* No overlapped I/O */
NULL) /* NULL template */
) == INVALID_HANDLE_VALUE) {
- a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",p->spath,GetLastError());
+ a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",buf,GetLastError());
return ICOM_SYS;
}
p->is_open = 1;
@@ -215,7 +390,8 @@ word_length word)
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE; /* Turn RTS on during connection */
- dcb.fAbortOnError = TRUE;
+// dcb.fAbortOnError = TRUE; // Hmm. Stuffs up FTDI. Is it needed ?
+ dcb.fAbortOnError = FALSE;
switch (p->fc) {
case fc_nc:
@@ -329,6 +505,9 @@ word_length word)
case baud_115200:
dcb.BaudRate = CBR_115200;
break;
+ case baud_921600:
+ dcb.BaudRate = CBR_921600;
+ break;
default:
CloseHandle(p->phandle);
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
@@ -370,7 +549,7 @@ double tout)
{
COMMTIMEOUTS tmo;
DWORD wbytes;
- int c, len;
+ int len;
long toc, i, top; /* Timout count, counter, timeout period */
int rv = ICOM_OK;
@@ -384,7 +563,7 @@ double tout)
len = strlen(wbuf);
tout *= 1000.0; /* Timout in msec */
- top = 100; /* Timeout period in msecs */
+ top = 20; /* Timeout period in msecs */
toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
if (toc < 1)
toc = 1;
@@ -393,8 +572,8 @@ double tout)
tmo.ReadIntervalTimeout = top;
tmo.ReadTotalTimeoutMultiplier = 0;
tmo.ReadTotalTimeoutConstant = top;
- tmo.WriteTotalTimeoutMultiplier = top;
- tmo.WriteTotalTimeoutConstant = 0;
+ tmo.WriteTotalTimeoutMultiplier = 0;
+ tmo.WriteTotalTimeoutConstant = top;
if (!SetCommTimeouts(p->phandle, &tmo)) {
a1loge(p->log, ICOM_SYS, "icoms_ser_write: SetCommTimeouts failed with %d\n",GetLastError());
p->lserr = rv = ICOM_SYS;
@@ -441,13 +620,13 @@ icoms_ser_read(
icoms *p,
char *rbuf, /* Buffer to store characters read */
int bsize, /* Buffer size */
-char tc, /* Terminating characer */
-int ntc, /* Number of terminating characters */
+char *tc, /* Terminating characers, NULL for none */
+int ntc, /* Number of terminating characters seen */
double tout /* Time out in seconds */
) {
COMMTIMEOUTS tmo;
DWORD rbytes;
- int c, j;
+ int j;
long toc, i, top; /* Timout count, counter, timeout period */
char *rrbuf = rbuf; /* Start of return buffer */
DCB dcb;
@@ -460,35 +639,15 @@ double tout /* Time out in seconds */
}
if (bsize < 3) {
- a1loge(p->log, ICOM_SYS, "icoms_read: given too small a buffer\n");
+ a1loge(p->log, ICOM_SYS, "icoms_read: given too small a bufferi (%d)\n",bsize);
p->lserr = rv = ICOM_SYS;
return rv;
}
-#ifdef NEVER
- /* The Prolific 2303 USB<->serial seems to choke on this, */
- /* so we just put up with a 100msec delay at the end of each */
- /* reply. */
- if (GetCommState(p->phandle, &dcb) == FALSE) {
- a1loge(p->log, ICOM_SYS, "icoms_ser_read: GetCommState failed with %d\n",GetLastError());
- p->lserr = rv = ICOM_SYS;
- return rv;
- }
-
- dcb.EofChar = tc;
-
- if (!SetCommState(p->phandle, &dcb)) {
- a1loge(p->log, ICOM_SYS, "icoms_ser_read: SetCommState failed %d\n",GetLastError());
- p->lserr = rv = ICOM_SYS;
- return rv;
- }
-#endif
- p->tc = tc;
-
tout *= 1000.0; /* Timout in msec */
bsize--; /* Allow space for null */
- top = 100; /* Timeout period in msecs */
+ top = 20; /* Timeout period in msecs */
toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
if (toc < 1)
toc = 1;
@@ -497,8 +656,8 @@ double tout /* Time out in seconds */
tmo.ReadIntervalTimeout = top;
tmo.ReadTotalTimeoutMultiplier = 0;
tmo.ReadTotalTimeoutConstant = top;
- tmo.WriteTotalTimeoutMultiplier = top;
- tmo.WriteTotalTimeoutConstant = 0;
+ tmo.WriteTotalTimeoutMultiplier = 0;
+ tmo.WriteTotalTimeoutConstant = top;
if (!SetCommTimeouts(p->phandle, &tmo)) {
a1loge(p->log, ICOM_SYS, "icoms_ser_read: SetCommTimeouts failed with %d\n",GetLastError());
p->lserr = rv = ICOM_SYS;
@@ -525,10 +684,18 @@ double tout /* Time out in seconds */
} else if (rbytes > 0) { /* Account for bytes done */
i = toc;
bsize -= rbytes;
- while(rbytes--) { /* Count termination characters */
- if (*rbuf++ == tc)
- j++;
- }
+ if (tc != NULL) {
+ while(rbytes--) { /* Count termination characters */
+ char ch = *rbuf++, *tcp = tc;
+
+ while(*tcp != '\000') {
+ if (ch == *tcp)
+ j++;
+ tcp++;
+ }
+ }
+ } else
+ rbuf += rbytes;
}
}
if (i <= 0) { /* timed out */
@@ -557,6 +724,13 @@ icoms_del(icoms *p) {
usb_del_usb(p);
hid_del_hid(p);
#endif
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ if (p->spath != NULL)
+ free(p->spath);
+#endif
+ p->log = del_a1log(p->log);
+ if (p->name != NULL)
+ free(p->name);
p->log = del_a1log(p->log); /* unref */
free (p);
}