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.