01-24-2018 08:33 AM
Hi,
I have a weird problem.
I have many applications that use COM port. I use either FTDI Usb to Serial, or STM32 Virtual COM port. I have used both successfully for a long time, suddenly COM port derived from STM32 Virtual COM port is no longer recognized by CVI (but it does by device manager and terminal application such as docklight).
I use code I got from this forum to populate a list of available COM ports (always worked perfectly until now), I will present the code below. The code no longer returns with the STM32 Virtual COM port number (It always did), so I tried to force the code to see the COM port exists (I force "com_port = 4" since it is COM4), and sometimes it works and most of the time OpenComConfig returns with -6 even though the COM port exists.
Any ideas?
Here is the code that lists the COM ports (it populates a menu ring):
if (number_of_found_ports) { for(i = 0 ; i < number_of_found_ports ; i++) { sprintf(str , "COM %d", portlist[i]) ; InsertListItem(main_panel_handle , kPANEL_COM_RING , -1 , str , i) ; } GetLabelFromIndex(main_panel_handle, kPANEL_COM_RING, 0, selected_com_port); strcpy(selected_com_port, &selected_com_port[4]); com_port = atoi(selected_com_port); com_port_selected = 1; }
Here is the COM port initialization, OpenComConfig returns with -6
OpenComConfig(com_port, "", COM_BAUDRATE, NO_PARITY, DATA_BITS_8, ONE_STOP_BIT, INPUT_QUEUE, NO_OUTPUT_QUEUE); SetCTSMode(com_port, LWRS_HWHANDSHAKE_OFF);
This is the code I downloaded from this forum a while back to get a list of available COM ports:
static HDEVINFO BeginEnumeratePorts(VOID) { BOOL guidTest = FALSE; DWORD RequiredSize = 0; HDEVINFO DeviceInfoSet; char *buf; guidTest = SetupDiClassGuidsFromNameA("Ports", 0, 0, &RequiredSize); if(RequiredSize < 1)return INVALID_HANDLE_VALUE; buf = malloc(RequiredSize * sizeof(GUID)); guidTest = SetupDiClassGuidsFromNameA("Ports", (GUID *)buf, RequiredSize * sizeof(GUID), &RequiredSize); if(!guidTest)return (HANDLE) - 1; DeviceInfoSet = SetupDiGetClassDevs((GUID *)buf, NULL, NULL, DIGCF_PRESENT); if(DeviceInfoSet == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; free(buf); return DeviceInfoSet; } int LocateCom(char *inval, int *list, int maxnum) { DWORD i; SP_DEVINFO_DATA DeviceInfoData = {0}; int portsfound = 0; HDEVINFO hDevInfo = BeginEnumeratePorts(); if (INVALID_HANDLE_VALUE == hDevInfo) return 0; // Enumerate through all devices in Set. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) { DWORD DataT; LPTSTR buffer = NULL; DWORD buffersize = 0; // // Call function with null to begin with, // then use the returned buffer size // to Alloc the buffer. Keep calling until // success or an unknown failure. // while (!SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buffer, buffersize, &buffersize)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Change the buffer size. if (buffer) free(buffer); buffer = malloc(buffersize); } else { if (buffer) free(buffer); SetupDiDestroyDeviceInfoList(hDevInfo); return 0; } } if (NULL == buffer) { if (buffersize > 0) { buffer = malloc(buffersize); SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buffer, buffersize, &buffersize); } } // We may have found the device if ((NULL != buffer) && strstr(buffer, inval)) { char *xval; xval = strstr(buffer, "COM"); if (xval != NULL) { int d; if ((1 == sscanf(xval, "COM%d", &d)) && (d >= 1) && (d <= 255)) { if ((NULL == list) || (maxnum <= 0)) { free(buffer); SetupDiDestroyDeviceInfoList(hDevInfo); return d; } else { if (portsfound < maxnum) list[portsfound++] = d; } } } } if (buffer) free(buffer); } SetupDiDestroyDeviceInfoList(hDevInfo); return portsfound; }
Any help will be greatly appreciated
01-25-2018 09:21 AM
Missing code in the OP
The first code segment was missing a line, here is the full code segment:
number_of_found_ports = LocateCom("", portlist, 255); if (number_of_found_ports) { for(i = 0 ; i < number_of_found_ports ; i++) { sprintf(str , "COM %d", portlist[i]) ; InsertListItem(main_panel_handle , kPANEL_COM_RING , -1 , str , i) ; } GetLabelFromIndex(main_panel_handle, kPANEL_COM_RING, 0, selected_com_port); strcpy(selected_com_port, &selected_com_port[4]); com_port = atoi(selected_com_port); com_port_selected = 1; }
01-25-2018 09:32 AM
I found a bug in "LocateCom" function.
In case the friendly name of the COM port is "Virtual COM port (COM4)" for instance, it will find the first COM and see there's no COM port number.
I created a function that looks for the "COM" string at the end of the friendly name instead of the first instance of the "COM" string.
That leaves me with 2 questions:
Up until recently I never had any problems with this code (even before the bug fix, which is weird), could a certain windows update be the cause?
01-25-2018 09:40 AM - edited 01-25-2018 09:41 AM
I am normally using a code very similar to yours, with only a small but significant variation:
for (i = 0; i < nports; i++) { sprintf (msg, "COM%d", portList[i]); InsertListItem (mainH, Main_com, -1, msg, portList[i]); }
This way I can simply GetCtrlVal on the ring directly obtaining the number to pass to OpenComConfig. No need to scan the port number from the label, which could ultimately return unpredictable values.
Have you observed which number are you actually passing to OpenComConfig when it fails?
01-25-2018 09:58 AM
Before the bug fix the following line was executed with com_port = 4 where there was COM2 (virtual com port - USB to serial)
OpenComConfig(com_port, "", COM_BAUDRATE, NO_PARITY, DATA_BITS_8, ONE_STOP_BIT, INPUT_QUEUE, NO_OUTPUT_QUEUE);
Still it returned with -6
01-25-2018 10:04 AM
BTW, I see what you did there, it is smart 🙂
But it is not the source of my problem, nevertheless I will use your idea for it's simplicity.
Thanks
01-25-2018 10:06 AM
Clonimus74 ha scritto:
I found a bug in "LocateCom" function.
In case the friendly name of the COM port is "Virtual COM port (COM4)" for instance, it will find the first COM and see there's no COM port number.
I see, that's bad news! When coming to real world we cannot be sure of which name the com port will assume, as it is determined by the driver programmer. Searching for a number will not be enough, for example, for MOXA ethernet-to-serial devices, that set friendly name to e.g. "NPort Communication Port 1 (COM5)".
The last occurrence of "COM" string is probably the best option, but we cannot be 100% sure there won't be some virtual port named for example "COM4: virtual COM port"
Nevertheless up to now your solution is probably the best we can think of.
Thanks to highlight this problem: I will be prepared in case I face strange errors while opening the port
01-25-2018 10:16 AM
Sure 🙂
I created the following function
static char *rstrstr(char *s1, char *s2) { size_t s1len = strlen(s1); size_t s2len = strlen(s2); char *compare_point = NULL; if (s2len > s1len) return NULL; compare_point = s1 + s1len - s2len; do { if (strncmp(compare_point, s2, s2len) == 0) return compare_point; if (compare_point > s1) compare_point--; else compare_point = NULL; //to exit } while (compare_point != NULL); return NULL; }
And used it in LocateCom here:
if ((NULL != buffer) && strstr(buffer, inval)) { char *xval; xval = rstrstr(buffer, "COM");
Though I still try to figure out the reason for #2 issue...
02-07-2020 11:42 AM
I ran into the problem where the Com port description contains "COM" before the port number. The fix was to search in LocateCom() from the end of the string, but I don't see the fixed code here. The function posted appears to be the same as the locatecomcvi function. Am I missing the fix? Can you re-post the fixed function?
Thanks!
Dave
02-07-2020 12:17 PM
On further consideration, what I really need is a new dll with the bug fix.
Dave