Fastest way of getting FTDI USB Serial Port Number - serial-port

I have a device using USB Serialport and, during the form load, I get the port number using below code. Actually, I googled and modified it.
ManagementClass processClass = new ManagementClass("Win32_PnPEntity");
ManagementObjectCollection Ports = processClass.GetInstances();
List<string> FTDIPorts = new List<string>();
int i = 0;
foreach (ManagementObject property in Ports)
{
string name = (string)property.GetPropertyValue("Name");
var manu = property.GetPropertyValue("Manufacturer");
if (name != null && name.ToString().Contains("USB") && name.ToString().Contains("COM") && Manu.ToString() == "FTDI")
{
FTDIPorts.Add(name.Substring(name.LastIndexOf("COM") + 3, 1));
}
}
It works, but it takes over 6 to 10seconds to get the port number! Are there any faster way of getting Serial Port number provided by specific manufacturer(for example, FTDI usb serial port)?
I am able to get the serial port number by searching registry "\HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM". However, it does not give manufacturer information but only port number.

Related

Why does serial.available does not work in this code snippet?

I have a processing sketch which needs to set up 2 connections with USB devices. I cannot tell in advance which device is USB0 and which is USB1. (not that I am aware off atleast)
One of the devices awnsers with hello the other one does not answer at all. Therefor I have written code with a simple timeout. In the setup I check continously if there are bytes to read. But both a while and an if statement yield incorrect results
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
if(millis() > 5000 ) {
println("timeout occured");
println(dccCentral.available());
break;
}
}
These lines are in setup. The text "timeout occured" is always printed. Underneath it, the result of dccCentral.available() is printed. This number is 12 which is correct.
regardless, if dccCentral.available() prints 12 at that time. The first if-statement:
if( dccCentral.available() >= 5) break;
should already have break'ed out of the while loop before this time-out should occur. The while-loop itself should also quit itself when 5 or more bytes are received.
Why do both these lines
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
fail?
Personally I try to avoid while loops unless there isn't another way (e.g. inside a thread) and that is avoid both logic pitfalls and messing with the lifecycle of other objects that might need a bit of time to initialise.
If you send strings from Arduino and also use println() you could init the port to easily catch that using Serial's bufferUntil() in conjuction with serialEvent() to finally readString().
Once you start getting data in, you could:
use references to the serial ports you're after and a couple of extra ones until you know which port is which
use a boolean "toggle" to only handle the "hello" once
if the hello was received, you can use the serialEvent() Serial argument to assign dccCentral and by process of elimination assign the other port
Here's a commented sketch to illustrate the idea:
import processing.serial.*;
// be sure to set this to the baud rate your device use with Arduino as well
final int BAUD_RATE = 115200;
// reference to Serial port sending "Hello" (when that get's detected)
Serial dccCentral;
// reference to the other Serial port
Serial otherDevice;
// temporary references
Serial usb0;
Serial usb1;
// 'toggle' to keep track where the hello was received and handled or not (by default initialised as false)
boolean wasHelloReceived;
void setup(){
usb0 = initSerial("/dev/ttyUSB0", BAUD_RATE);
usb1 = initSerial("/dev/ttyUSB1", BAUD_RATE);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
background(0);
text("wasHelloReceived: " + wasHelloReceived + "\n"
+"dccCentral: " + dccCentral + "\n"
+"otherDevice: " + otherDevice , 10 ,15);
// do something with the devices once they're ready (e.g. send a message every 3 seconds)
if(millis() % 3000 == 0){
if(dccCentral != null){
dccCentral.write("ping\n");
}
if(otherDevice != null){
otherDevice.write("pong\n");
}
}
}
void serialEvent(Serial port){
try{
String serialString = port.readString();
// if the received string is not null, nor empty
if(serialString != null && !serialString.isEmpty()){
// for debugging purposes display the data received
println("received from serial: " + serialString);
// trim any white space
serialString = serialString.trim();
// check if "hello" was received
if(serialString.equals("hello")){
println("hello detected!");
// if the dccCEntral (hello sending) serial port wasn't assigned yet, assign it
// think of this as debouncing a button: setting the port once "hello" was received should happen only once
if(!wasHelloReceived){
// now what dccCentral is found, assign it to the named reference
dccCentral = port;
// by process elimiation, assign the other port
// (e.g. if dccCentral == usb0, then other is usb1 and vice versa)
otherDevice = (dccCentral == usb0 ? usb1 : usb0);
/*
the above is the same as
if(dccCentral == usb0){
otherDevice = usb1;
}else{
otherDevice = usb0;
}
*/
wasHelloReceived = true;
}
}
}
}catch(Exception e){
println("error processing serial data");
e.printStackTrace();
}
}
Note the above code hasn't been tested so it may include syntax errors, but hopefully the point gets across.
I can't help notice that USB0/USB1 are how serial devices sometimes show up on Linux.
If you're working with a Raspberry Pi I can recommend a slightly easier way if you're comfortable with Python. The PySerial has a few tricks up it's sleeve:
You can simply call: python -m serial.tools.list_ports -v which will list ports with extra information such as serial number of the serial converter chipset. This could be useful to tell which device is which, regardless of the manufacturer and USB port used
Other than the serial port name/location, it supports multiple ways (URLs) of accessing the port with a very clever: hwgrep:// will allow you to filter a device by it's unique serial number
Here's a basic list_ports -v output for two devices with the same chipset:
column 1
/dev/ttyUSB9
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94O21P LOCATION=1-2.2
column 2
/dev/ttyUSB8
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94MKCI LOCATION=1-2.1.4
To assign the devices using serial you would use something like:
"hwgrep://FT94O21P"
"hwgrep://FT94MKCI"
Update
It might help to step by step debug the system and try one port a time.
The idea is to get the bit of code reading the expected serial string tight.
Here's a basic example that should simply accumulate one char at a time into a string and display it:
import processing.serial.*;
Serial port;
String fromSerial = "";
void setup(){
size(300,300);
port = initSerial("/dev/ttyUSB0", 115200);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
if(port != null){
if(port.available() > 0){
char inChar = port.readChar();
fromSerial += inChar;
if(inChar == '\n'){
println("newline encountered");
println(fromSerial.split("\n"));
}
}
}
background(0);
text("from serial:" + fromSerial, 10,15);
}
If the data from dccCentral comes in a expected: great, the code can be simplfied and right conditions applied to filter the device in the future,
otherwise it should help pin point communication issues getting the "hello" in the first place (which would be 6 bytes ("hello"(5) + '\n') if sent with Serial.println() from Arduino)
Regarding Python, no problem at all. Should the idea help in the future you can check out this answer. (AFAIK Processing Serial uses JSSC behind the scenes)

arduino and esp8266 - how to get AT command response into variable

So i have my arduino and esp8266 wifi module. Everything is connected correctly and sending data to arduino lets me control connection via AT commands.
My skletch looks like this:
void setup()
{
Serial.begin(9600);
Serial1.begin(9600);
}
void loop()
{
if (Serial.available() > 0) {
char ch = Serial.read();
Serial1.print(ch);
}
if (Serial1.available() > 0) {
char ch = Serial1.read();
Serial.print(ch);
}
The code above lets me send commands and see response from esp. In spite of different response time and different answers I need to store response in variable when wifi module such a response creates. Unfortunatelly I cant do this because of Serial1.read() grabing only one char from Serial1.available() buffer instead of full buffer.
I tried approach like this:
if (Serial1.available() > 0) {
while (Serial1.available() > 0) {
char ch = Serial1.read();
Serial.print(ch);
response = response.concat(ch);
}
} else {
String response = "";
}
So as long ther eis something in a buffer it is sent to response variable that concatens last char with itself. And later it can be searched via indefOf command for "OK" marker or "ERROR". But that doesnt work as intended :( It for example may print my variable 8 times (dont know why).
I need full response from wifi module to analaze it for example to make the led on in my arduino board if proper command comes from wifi network, but also send some data if i press button on arduino to the network. Any ideas would be appreciated.
Kalreg.
Try this rather:
String response = ""; // No need to recreate the String each time no data is available
char ch; // No need to recreate the variable in a loop
while (Serial1.available() > 0) {
ch = Serial1.read();
response = response.concat(ch);
}
// Now do whatever you want with the string by first checking if it is empty or not. Then do something with it
Also remember to clear the buffer before you send a command like I suggested in your previous question: how to get AT response from ESP8266 connected to arduino

USB/IP emulated device not listed by libusb

There's USB/IP tool which allows share access USB devices over TCP/IP network. USB device connected to Linux PC which running TCP server and Windows PC running VHCI driver which connects to Linux.
This approach makes possible to emulate any USB device without hardware at all. All you need is write TCP server which will handle USB requests. (like here)
But the problem with it that emulated device is not really correct. When you try to list connected USB devices using libusb you'll get an error 'unlisted ancestor for..' since emulated device has no parent in device-tree.
From other hand some tools like Zadig show emulated device.
Exactly problem discussed here and no real solution provided.
So question is it bug in USB/IP windows driver? Can anybody experienced with Windows drivers development helps? What's a deal about parent device? Why it is so important?
Any hint will be very very appreciated! Thanks a lot in advance for any help
UDPATE : technically problem is that parent of emulated device (USB/IP enumerator) not recognized by libusb as HUB. This makes emulated devices ignored due-to NULL parent. So question is how to patch USB/IP driver to be visible by libusb as normal USB HUB
The problem was that USB/IP windows driver v0.2.0.0 does not reply on IRP_MN_QUERY_CAPABILITIES IRPs. It dispatch only IRP_MN_QUERY_CAPABILITIES targeted on emulated devices, but not to bus driver itself.
I have added IRP_MN_QUERY_CAPABILITIES processing to USB/IP driver and now it is detected by libusb as normal USB HUB device.
UPD:
in pnp.c inside method
NTSTATUS Bus_FDO_PnP (
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in PIO_STACK_LOCATION IrpStack,
__in PFDO_DEVICE_DATA DeviceData )
I have added new 'case' inside switch (IrpStack->MinorFunction) :
case IRP_MN_QUERY_CAPABILITIES:
{
status = _PDO_QueryDeviceCaps(DeviceData, Irp);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
Bus_DecIoCount(DeviceData);
return status;
}
UPD2: and also this:
NTSTATUS _PDO_QueryDeviceCaps(__in PFDO_DEVICE_DATA DeviceData, __in PIRP Irp)
{
PIO_STACK_LOCATION stack;
PDEVICE_CAPABILITIES deviceCapabilities;
DEVICE_CAPABILITIES parentCapabilities;
PAGED_CODE();
stack = IoGetCurrentIrpStackLocation(Irp);
deviceCapabilities = stack->Parameters.DeviceCapabilities.Capabilities;
if (deviceCapabilities->Version != 1 || deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
{
return STATUS_UNSUCCESSFUL;
}
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
if (deviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0)
deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
if (deviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0)
deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
if (deviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0)
deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
deviceCapabilities->DeviceWake = PowerDeviceD1;
deviceCapabilities->DeviceD1 = TRUE; // Yes we can
deviceCapabilities->DeviceD2 = FALSE;
deviceCapabilities->WakeFromD0 = FALSE;
deviceCapabilities->WakeFromD1 = TRUE;
deviceCapabilities->WakeFromD2 = FALSE;
deviceCapabilities->WakeFromD3 = FALSE;
deviceCapabilities->D1Latency = 0;
deviceCapabilities->D2Latency = 0;
deviceCapabilities->D3Latency = 0;
deviceCapabilities->EjectSupported = FALSE;
deviceCapabilities->HardwareDisabled = FALSE;
deviceCapabilities->Removable = TRUE;
deviceCapabilities->SurpriseRemovalOK = TRUE;
deviceCapabilities->UniqueID = FALSE;
deviceCapabilities->SilentInstall = FALSE;
deviceCapabilities->Address = 1;
deviceCapabilities->UINumber = 1;
return STATUS_SUCCESS;
}

8051 micro controller to transmit data to ZigBee

My problem is that I do not know how to transmit an AT command from 8051 micro controller to ZigBee serially. Any tips on how I can do that?
But for the time being, I shall try to transmit a string of data using array from the micro controller to the computer and see using hyper terminal. Currently I can only transmit a character 'A' continuously from 8051 to hyper terminal on the computer.
Sending a string via any 8051 should look the same.
First, initialize the serial port the good way (assume it's ok if you can send 'A').
Then, you have to initialize either a table or a pointer.
UC *ucText = "Hello World";
UC ucText[] = "Hello World";
Create a single function which input parameter is a UC variable (ucSend can be 'A' or anything) and transmit only once when called
void vTx232 (UC ucSend)
{
while (TI); //While last TX not done
SBUF = ucSend; //Character into TX buffer
}
Then, a second function to transmit a string which calls the above function. The input string is the variable you created earlier.
void vTxString (UC *ucpString)
{
while (*ucpString!= 0x00) //While string not at it's end
{
vTx232(*ucpString); //Send the actual string character
ucpString++; //Increments string
}
}

Possible to get network MAC address in .NET Metro app?

I have the requirement to get get the MAC address of the network interface in my Metro UI app. As far as I can tell, this is simply not supported in the .NET 4.5 for Metro application API. Am I wrong?
You can't retrieve the MAC Address per say, but you do can retrieve hardware specific information to identify a machine.
Here's a complete msdn article discussing the subject: Guidance on using the App Specific Hardware ID (ASHWID) to implement per-device app logic (Windows)
Be careful to use just the information you need and not the complete id, as it might change based on information that are useless to you (such as the Dock Station bytes for instance).
Here's a code sample of a computed device id based on a few bytes (CPU id, size of memory, serial number of the disk device and bios):
string deviceSerial = string.Empty;
// http://msdn.microsoft.com/en-us/library/windows/apps/jj553431
Windows.System.Profile.HardwareToken hardwareToken = Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null);
using (DataReader dataReader = DataReader.FromBuffer(hardwareToken.Id))
{
int offset = 0;
while (offset < hardwareToken.Id.Length)
{
byte[] hardwareEntry = new byte[4];
dataReader.ReadBytes(hardwareEntry);
// CPU ID of the processor || Size of the memory || Serial number of the disk device || BIOS
if ((hardwareEntry[0] == 1 || hardwareEntry[0] == 2 || hardwareEntry[0] == 3 || hardwareEntry[0] == 9) && hardwareEntry[1] == 0)
{
if (!string.IsNullOrEmpty(deviceSerial))
{
deviceSerial += "|";
}
deviceSerial += string.Format("{0}.{1}", hardwareEntry[2], hardwareEntry[3]);
}
offset += 4;
}
}
Debug.WriteLine("deviceSerial=" + deviceSerial);
You are restricted from accessing low-level networking information from a Metro Style application, therefore this is not possible with the stock SDK. This is by design.
private void getDeviceInfos()
{
Profiles = Windows.Networking.Connectivity.NetworkInformation.GetConnectionProfiles();
Adapter = Profiles[0].NetworkAdapter;
Guid AdapterId = Adapter.NetworkAdapterId;
}
IReadOnlyList<Windows.Networking.Connectivity.ConnectionProfile> Profiles;
Windows.Networking.Connectivity.NetworkAdapter Adapter;

Resources