Finding Connected FTDI Devices


using namespace Microsoft::Win32;		//< Needed to access registry

int Count;
int CharPosn;
int CheckEachPortCount;
String ^RegistryMainFolder;
String ^SerialNumber;
String ^Port;
array<String^> ^FoundCommPorts = gcnew array<String^>(0);
array<String^> ^FoundSerialNumbers = gcnew array<String^>(0);

//----- SETUP THE COMM PORT COMBO BOX -----

//Add the default comm port "None"
cmbCommPort->Items->Add(L"None");

try
{
	//----- DISCOVER ALL AVAILABLE SERIAL PORTS -----
	array<String^> ^AvailableSerialPorts;
	 AvailableSerialPorts = SerialPort::GetPortNames();

	//>>>>>>>>>>>>>>>> DEBUG SIMULATE COM PORT CONNECTED
	//Array::Resize(AvailableSerialPorts, AvailableSerialPorts->Length + 1);
	//AvailableSerialPorts[AvailableSerialPorts->Length - 1] = "COM3";
	//<<<<<<<<<<<<<<<<<<<

	//----- CHECK REGISTRY TO FIND MATCHING FDTI DEVICES AND ONLY INCLUDE THOSE COMM PORTS -----
	//(We only show comm ports for our devices that are currently connected)
	//This is the registry path we're interested in (taken from FTDI web site):-
	//HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_VID+PID_PID+Serial_Number\0000\DeviceParameters\PortName

	//Retrieve all the subkeys for the specified key.
	RegistryMainFolder= L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS";

	RegistryKey ^rkey = Registry::LocalMachine;
	rkey = rkey->OpenSubKey(RegistryMainFolder);
	array<String^>^names = rkey->GetSubKeyNames();

	for each (String^ name in names)
	{
		//----- CHECK NEXT FTDI DEVICE IN THE REGISTRY -----
		//This example is based on finding only devices where the FTDI name includes a custom programmed serial number like this:
		//name = VID_VID+PID_PID+Serial_Number

		//Get Serial Number portion
		CharPosn = name->LastIndexOf("+");
		if (CharPosn >= 0)
		{
			SerialNumber = name->Substring(CharPosn + 1);	//Returns rest of string starting at character posn #
			SerialNumber = SerialNumber->Trim();

			if ((SerialNumber->Length == 7) && (SerialNumber->Contains("ABC")))	//Example test of length and contents
			{
				rkey = Registry::LocalMachine;
				rkey = rkey->OpenSubKey(RegistryMainFolder);
				rkey = rkey->OpenSubKey(name);
				rkey = rkey->OpenSubKey(L"0000\\Device Parameters");
				Port = Convert::ToString(rkey->GetValue("PortName"));			//Will be COM1 etc

				for (CheckEachPortCount = 0; CheckEachPortCount < AvailableSerialPorts->Length; CheckEachPortCount++)
				{
					if (AvailableSerialPorts[CheckEachPortCount]->ToString() == Port->ToString())
					{
						//THIS PORT EXISTS SO DEVICE IS CONNECTED - ADD IT TO THE ARRAY OF FOUND DEVICES
						Array::Resize(FoundCommPorts, FoundCommPorts->Length + 1);
						Array::Resize(FoundSerialNumbers, FoundSerialNumbers->Length + 1);
						FoundCommPorts[FoundCommPorts->Length - 1] = Port;
						FoundSerialNumbers[FoundSerialNumbers->Length - 1] = SerialNumber;
						break;
					}
				}
			}
		}

	}
	rkey->Close();

	//ADD EACH OF THE FOUND DEVICES TO THE COMM PORT COMBO BOX
	if (FoundCommPorts->Length)
	{
		Array::Sort(FoundCommPorts, FoundSerialNumbers);		//Sort by port number

		for (Count = 0; Count < FoundCommPorts->Length; Count++)
		{
			cmbCommPort->Items->Add(FoundCommPorts[Count] + " (Serial #: " + FoundSerialNumbers[Count]->Substring(4, 4) + ")");
		}

	}
}
catch(System::Exception^ e)
{

}

Setting Latency Of FTDI Devices


//----- CHECK LATENCY SETTINGS OF FTDI COM PORTS FOR OUR DEVICE -----
//FTDI latency is the time from receiving the last byte before the packet is sen't via USB
//It is 16mS defualt, we want it as fast as possible and FTDI recomends a min value of 2mS (not 1mS)
//Check each of the FTDI ports that is used by our device and modify the value if need be.  On Windows
//Vista and above access permission will not be given by UAC so a message box is displayed informing the user they need to use 'Run As
//Administrator' to allow the applicaiton to update the registry.  To do this they need to log on as an administrator rights user,
//find the application executible in windows explorer, right click and select run as administrator.  Alternatively the values could
//be edited in regedit.
//Tested after setting to 2 and it woudl take between 1mS and 3mS for for the next packet to be sent, implying that the timer in the
//FDTI chip is literally a 1mS incrementing timer, hence the min value of 2mS being recomended.

int CharPosn;
String ^RegistryMainFolder;
String ^SerialNumber;
int Latency;
static bool NotifiedUserCantWriteRegistry = false;

try
{
	//----- CHECK REGISTRY TO FIND FDTI DEVICES -----
	//Retrieve all the subkeys for the specified key.
	RegistryMainFolder= L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS";		//FTDI Path:- HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_VID+PID_PID+Serial_Number\0000\DeviceParameters\

	RegistryKey ^rkey = Registry::LocalMachine;
	rkey = rkey->OpenSubKey(RegistryMainFolder);
	array<String^>^names = rkey->GetSubKeyNames();

	for each (String^ name in names)
	{
		//----- CHECK NEXT FTDI DEVICE IN THE REGISTRY -----
		//name = VID_VID+PID_PID+Serial_Number

		//Out device has a serial number programmed that always begins with "ABC" so look for it

		//Get Serial Number
		CharPosn = name->LastIndexOf("+");
		if (CharPosn >= 0)
		{
			SerialNumber = name->Substring(CharPosn + 1);	//Returns rest of string starting at character posn #

			if (SerialNumber->Contains("ABC"))			//<<<<<< SET STRING TO LOOK FOR IN SERIAL NUMBER
			{
				//THIS IS OUR PRODUCT
				rkey = Registry::LocalMachine;
				rkey = rkey->OpenSubKey(RegistryMainFolder);
				rkey = rkey->OpenSubKey(name);
				rkey = rkey->OpenSubKey(L"0000\\Device Parameters");

				//CHECK IF WE NEED TO CHANGE THE LATENCY TIMER VALUE
				Latency = Convert::ToInt32(rkey->GetValue("LatencyTimer"));
				if (Latency != 2)						//<<<<<<< LATENCY VALUE REQUIRED
				{
					rkey = rkey->OpenSubKey("", true);	//Open as writable
					rkey->SetValue("LatencyTimer", 2);	//<<<<<<< LATENCY VALUE REQUIRED
				}
			}
		}
	}
	rkey->Close();
}
catch(System::Exception^ e)
{
	if (!NotifiedUserCantWriteRegistry)
		MessageBox::Show(L"Unable to modify FTDI latency parameters in Windows registry.\nUSB communications will be slower than normal.\nUse 'Run As Administrator' to allow application to set the required values", L"Need admin permissions", MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
	NotifiedUserCantWriteRegistry = true;
}
USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.