From c07d0c2d2f6f7b0eb6e92cc6204bf05037957e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 15:43:52 +0200 Subject: Imported Upstream version 1.6.3 --- spectro/icoms_nt.c | 280 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 227 insertions(+), 53 deletions(-) (limited to 'spectro/icoms_nt.c') 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 +/* 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); } -- cgit v1.2.3