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;
}
Feel free to comment if you can add help to this page or point out issues and solutions you have found. I do not provide support on this site, if you need help with a problem head over to stack overflow.

Comments

Your email address will not be published. Required fields are marked *