LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

OpenComConfig returns an error even though Device manager lists the COM port

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

 

 

 

0 Kudos
Message 1 of 13
(3,669 Views)

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;
}
0 Kudos
Message 2 of 13
(3,643 Views)

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:

  1. Why forcing com_port = 4 (a valid COM number)  still caused OpenComConfig return with an error?
  2. Why, after the above bug fix, I have to disconnect-reconnect the USB, and restart the CVI application, in order to not get any com port related errors (in OpenComConfig or later in ComWrt)

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?

Message 3 of 13
(3,640 Views)

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?



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 4 of 13
(3,639 Views)

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 

0 Kudos
Message 5 of 13
(3,631 Views)

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

0 Kudos
Message 6 of 13
(3,630 Views)

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" Smiley Surprised

 

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 Smiley Wink



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 7 of 13
(3,629 Views)

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...

 

0 Kudos
Message 8 of 13
(3,625 Views)

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

0 Kudos
Message 9 of 13
(2,504 Views)

On further consideration, what I really need is a new dll with the bug fix.

 

Dave

0 Kudos
Message 10 of 13
(2,503 Views)