From 3db384424bd7398ffbb7a355cab8f15f3add009f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 2 Oct 2016 19:24:58 +0200 Subject: New upstream version 1.9.1+repack --- spectro/icoms_nt.c | 341 ++++++++++++++++++++++++++--------------------------- 1 file changed, 164 insertions(+), 177 deletions(-) (limited to 'spectro/icoms_nt.c') diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c index 14258e9..b9e0d0c 100644 --- a/spectro/icoms_nt.c +++ b/spectro/icoms_nt.c @@ -1,5 +1,5 @@ - - /* Windows NT serial I/O class */ + +/* Windows NT serial I/O class */ /* * Argyll Color Correction System @@ -14,195 +14,171 @@ * see the License2.txt file for licencing details. */ +#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) + #include -#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. */ -/* Create and return a list of available serial ports or USB instruments for this system */ -/* return icom error */ -int icompaths_refresh_paths(icompaths *p) { - int rv, usbend = 0; - int i, j; + +/* Add paths to serial connected device. */ +/* Return an icom error */ +int serial_get_paths(icompaths *p, icom_type mask) { + int i; LONG stat; HKEY sch; /* Serial coms handle */ - a1logd(p->log, 8, "icoms_get_paths: called\n"); + a1logd(p->log, 7, "serial_get_paths: called with mask = %d\n",mask); - /* Clear any existing paths */ - p->clear(p); - -#ifdef ENABLE_USB - if ((rv = hid_get_paths(p)) != ICOM_OK) - return rv; - if ((rv = usb_get_paths(p)) != ICOM_OK) - return rv; -#endif /* ENABLE_USB */ - usbend = p->npaths; - - a1logd(p->log, 6, "icoms_get_paths: got %d paths, looking up the registry for serial ports\n",p->npaths); - -#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) // (Beware KEY_WOW64_64KEY ?) #define MXKSIZE 500 #define MXVSIZE 300 - /* Look in the registry for serial ports */ - if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", - 0, KEY_READ, &sch)) != ERROR_SUCCESS) { - a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any serial ports\n"); - return ICOM_OK; /* Maybe they have USB ports */ - } + if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) { - /* 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[MXKSIZE], *vp; - DWORD vnsize = MXKSIZE; - DWORD vtype; - char value[MXVSIZE]; - DWORD vsize = MXVSIZE; - icom_ser_attr sattr = icom_normal; - - stat = RegEnumValue( - sch, /* handle to key to enumerate */ - i, /* index of subkey to enumerate */ - valname, /* address of buffer for value name */ - &vnsize, /* address for size of value name buffer */ - NULL, /* reserved */ - &vtype, /* Address of value type */ - value, /* Address of value buffer */ - &vsize /* Address of value buffer size */ - ); - if (stat == ERROR_NO_MORE_ITEMS) { - a1logd(p->log, 8, "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; + a1logd(p->log, 6, "serial_get_paths: looking up the registry for serial ports\n"); + /* Look in the registry for serial ports */ + if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", + 0, KEY_READ, &sch)) != ERROR_SUCCESS) { + a1logd(p->log, 1, "serial_get_paths: There don't appear to be any serial ports\n"); + return ICOM_OK; } - 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; - } + /* Look at all the values in this key */ + a1logd(p->log, 8, "serial_get_paths: looking through all the values in the SERIALCOMM key\n"); + + for (i = 0; ; i++) { + char valname[MXKSIZE], *vp; + DWORD vnsize = MXKSIZE; + DWORD vtype; + char value[MXVSIZE]; + DWORD vsize = MXVSIZE; + icom_type dctype = icomt_unknown; + + stat = RegEnumValue( + sch, /* handle to key to enumerate */ + i, /* index of subkey to enumerate */ + valname, /* address of buffer for value name */ + &vnsize, /* address for size of value name buffer */ + NULL, /* reserved */ + &vtype, /* Address of value type */ + value, /* Address of value buffer */ + &vsize /* Address of value buffer size */ + ); + if (stat == ERROR_NO_MORE_ITEMS) { + a1logd(p->log, 8, "serial_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, "serial_get_paths: RegEnumValue failed with %d\n",stat); + break; + } + valname[MXKSIZE-1] = '\000'; + value[MXVSIZE-1] = '\000'; - if ((vp = strrchr(valname, '\\')) == NULL) - vp = valname; - else - vp++; + if (vtype != REG_SZ) { + a1logw(p->log, "serial_get_paths: RegEnumValue didn't return stringz type\n"); + continue; + } - /* See if it looks like a fast port */ - if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */ - sattr |= icom_fast; - } + if ((vp = strrchr(valname, '\\')) == NULL) + vp = valname; + else + vp++; - if (strncmp(vp, "BtPort", 6) == 0) { /* Blue tooth */ - sattr |= icom_fast; - sattr |= icom_bt; - } + a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",vp); + + /* See if it looks like a fast port */ + if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */ + dctype |= icomt_fastserial; + } + + if (strncmp(vp, "USBSER", 6) == 0) { /* USB Serial port */ + dctype |= icomt_fastserial; + } + + if (strncmp(vp, "BtPort", 6) == 0 /* Blue tooth */ + || strncmp(vp, "BthModem", 8) == 0) { + dctype |= icomt_fastserial; + dctype |= icomt_btserial; + } #ifndef ENABLE_SERIAL - if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */ + if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */ #endif - /* Add the port to the list */ - p->add_serial(p, value, value, sattr); - a1logd(p->log, 8, "icoms_get_paths: Added path '%s' sattr 0x%x\n",value,sattr); + if (((mask & icomt_serial) && !(dctype & icomt_fastserial)) + || ((mask & icomt_fastserial) && (dctype & icomt_fastserial) + && !(dctype & icomt_btserial)) + || ((mask & icomt_btserial) && (dctype & icomt_btserial))) { + + // ~~ would be nice to add better description, similar + // to that of device manager, i.e. "Prolific USB-to-SerialBridge (COM6)" + /* Add the port to the list */ + p->add_serial(p, value, value, dctype); + a1logd(p->log, 8, "serial_get_paths: Added '%s' path '%s' dctype 0x%x\n",vp, value,dctype); + } #ifndef ENABLE_SERIAL - } + } #endif - /* If fast, try and identify it */ - if (sattr & icom_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 fast, try and identify it */ + if (dctype & icomt_fastserial) { + icompath *path; + icoms *icom; + if ((path = p->get_last_path(p)) != NULL + && (icom = new_icoms(path, p->log)) != NULL) { + devType itype = fast_ser_inst_type(icom, 0, NULL, NULL); + if (itype != instUnknown) + icompaths_set_serial_itype(path, itype); /* And set category */ + icom->del(icom); + } + a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype); } } - } - if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) { - a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat); - } -#endif /* ENABLE_SERIAL || ENABLE_FAST_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 ((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; - } + if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) { + a1logw(p->log, "serial_get_paths: RegCloseKey failed with %d\n",stat); } } - a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths); - return ICOM_OK; } +/* -------------------------------------------------------------------- */ -/* Close the port */ -static void icoms_close_port(icoms *p) { - if (p->is_open) { -#ifdef ENABLE_USB - if (p->usbd) { - usb_close_port(p); - } else if (p->hidd) { - hid_close_port(p); - } -#endif -#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) - if (p->phandle != NULL) { - CloseHandle(p->phandle); - } -#endif /* ENABLE_SERIAL */ - p->is_open = 0; - } +/* Is the serial port actually open ? */ +int serial_is_open(icoms *p) { + return p->phandle != NULL; } -#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL) +/* Close the serial port */ +void serial_close_port(icoms *p) { + + if (p->is_open && p->phandle != NULL) { + CloseHandle(p->phandle); + p->phandle = NULL; + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ + } +} -static int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout); -static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread, - char *tc, int ntc, double tout); +/* -------------------------------------------------------------------- */ #ifndef CBR_921600 # define CBR_921600 921600 #endif -/* Set the serial port characteristics */ +/* Set the serial port characteristics - extended */ /* This always re-opens the port */ /* return an icom error */ static int -icoms_set_ser_port( +icoms_set_ser_port_ex( icoms *p, flow_control fc, baud_rate baud, parity parity, stop_bits stop, -word_length word) -{ +word_length word, +int delayms) { /* Delay after open in msec */ a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n" " Port name = %s\n" @@ -211,10 +187,13 @@ word_length word) " Parity = %d\n" " Stop bits = %d\n" " Word length = %d\n" - ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word); + " Open delay = %d ms\n" + ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word, delayms); - if (p->is_open) + if (p->is_open) { + a1logd(p->log, 8, "icoms_set_ser_port: closing port '%s'\n",p->name); p->close_port(p); + } if (p->port_type(p) == icomt_serial) { DCB dcb; @@ -234,7 +213,7 @@ word_length word) /* Make sure the port is open */ if (!p->is_open) { - char buf[50]; /* Temporary for COM device path */ + char buf[100]; /* Temporary for COM device path */ a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath); @@ -253,11 +232,18 @@ word_length word) a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",buf,GetLastError()); return ICOM_SYS; } + + if (delayms < 160) /* Seems to need at least 80 msec with many drivers */ + delayms = 160; + + msec_sleep(delayms); /* For Bluetooth */ + p->is_open = 1; } if (GetCommState(p->phandle, &dcb) == FALSE) { CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: reading state '%s' failed with LastError %d\n",p->spath,GetLastError()); return ICOM_SYS; } @@ -274,14 +260,17 @@ word_length word) dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; /* Turn RTS on during connection */ -// dcb.fAbortOnError = TRUE; // Hmm. Stuffs up FTDI. Is it needed ? - dcb.fAbortOnError = FALSE; + dcb.fAbortOnError = FALSE; /* Hmm. TRUE Stuffs up FTDI. Is it needed ? */ switch (p->fc) { case fc_nc: CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc); return ICOM_SYS; + case fc_None: + /* Use no flow control */ + break; case fc_XonXOff: /* Use Xon/Xoff bi-directional flow control */ dcb.fOutX = TRUE; @@ -307,6 +296,7 @@ word_length word) switch (p->py) { case parity_nc: CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py); return ICOM_SYS; case parity_none: @@ -328,6 +318,7 @@ word_length word) switch (p->sb) { case stop_nc: CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb); return ICOM_SYS; case stop_1: @@ -341,6 +332,7 @@ word_length word) switch (p->wl) { case length_nc: CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl); return ICOM_SYS; case length_5: @@ -399,20 +391,24 @@ word_length word) break; default: CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br); return ICOM_SYS; } - PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR); + PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); if (!SetCommState(p->phandle, &dcb)) { CloseHandle(p->phandle); + msec_sleep(100); /* Improves reliability of USB<->Serial converters */ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: SetCommState failed with LastError %d\n", GetLastError()); return ICOM_SYS; } - PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR); + PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + + msec_sleep(50); /* Improves reliability of USB<->Serial converters */ p->write = icoms_ser_write; p->read = icoms_ser_read; @@ -423,6 +419,22 @@ word_length word) return ICOM_OK; } +/* Set the serial port characteristics */ +/* This always re-opens the port */ +/* return an icom error */ +static int +icoms_set_ser_port( +icoms *p, +flow_control fc, +baud_rate baud, +parity parity, +stop_bits stop, +word_length word) +{ + return icoms_set_ser_port_ex(p, fc, baud, parity, stop, word, 0); +} + + /* ---------------------------------------------------------------------------------*/ /* Serial write, read */ @@ -430,7 +442,7 @@ word_length word) /* Data will be written up to the terminating nul */ /* Return relevant error status bits */ /* Set the icoms lserr value */ -static int +int icoms_ser_write( icoms *p, char *wbuf, /* null terminated unless nwch > 0 */ @@ -519,7 +531,7 @@ double tout) /* Read characters into the buffer */ /* Return string will be terminated with a nul */ -static int +int icoms_ser_read( icoms *p, char *rbuf, /* Buffer to store characters read */ @@ -645,30 +657,5 @@ double tout /* Time out in seconds */ return p->lserr; } -#endif /* ENABLE_SERIAL */ -/* ---------------------------------------------------------------------------------*/ - - -/* Destroy ourselves */ -static void -icoms_del(icoms *p) { - a1logd(p->log, 8, "icoms_del: called\n"); - if (p->is_open) { - a1logd(p->log, 8, "icoms_del: closing port\n"); - p->close_port(p); - } -#ifdef ENABLE_USB - 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); -} +#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL*/ -- cgit v1.2.3