I want to detect a connected usb device (FT232R USB UART, Virtual com port driver). This usually worked fine, but due to an windows update my device is detected as FTDI_DEVICE_UNKNOWN. Strange behaviour is, that when I first plug in my device and then start the software, everything works fine. If I first start the software and then plug in the device, it it not detected. I tried to use CyclePort to reconnect the device, but this fails with status FT_OTHER_ERROR. The device is detected and displayed in both cases in the windows device manager. Drivers were already updated and also installed manually.
Any ideas as to what is causing this?
Here is my code:
List<string> pcdSerials = new List<string>();
FTDI ftdi = new FTDI();
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
ftStatus = ftdi.GetNumberOfDevices(ref ftdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
return pcdSerials;
}
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
ftStatus = ftdi.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
return pcdSerials;
}
foreach (var info in ftdiDeviceList)
{
if (info.Type == FTDI.FT_DEVICE.FT_DEVICE_UNKNOWN)
{
if (ftdiDeviceList.Count() == 1)
{
// The effect of this function is the same as disconnecting then reconnecting the device from USB.
// Possible use of this function is in situations where a fatal error has occurred and it is difficult, or not possible, to recover without unplugging and replugging the USB cable. This function can also be used after re-programming the EEPROM to force the FTDI device to read the new EEPROM contents which previously required a physical disconnect-reconnect.
ftStatus = ftdi.CyclePort();
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
// Port has been cycled. Close the handle.
ftStatus = ftdi.Close();
}
else
{
// FT_CyclePort FAILED!
}
break;
}
}
if (info.Description != "FT232R USB UART")
continue;
if (info.Type != FTDI.FT_DEVICE.FT_DEVICE_232R)
continue;
pcdSerials.Add(info.SerialNumber);
}
return pcdSerials;
This NOT an answer, but a comment. Being new to Stack overflow it wouldn't let me simply add a comment to your question, or I don;t know what I am doing. :)
I am having what sounds like the same issue. I wrote a wrapper class over 10 years ago that has worked fine until the new FTDI driver 2.12.36.1 was updated on client's computers. FTDI released driver version 2.12.36.2 on 6/17/2021 and I was hoping that it would resolve the issue but it did not.
What I have found is that calling FT_CreateDeviceInfoList does return the correct number of devices connected. Then I call FT_GetDeviceInfoDetail to obtain the device type, description, and FTDI serial number. The device type comes back as value 0x03 which is FT_Device_Unknown and the description and serial number appear to come back empty. I use the FTDI serial number to open the device by its serial number. Without a valid serial number, I cannot open the device. I have used this method as outlined as the preferred method by FTDI for years with no issues until now.
Hopefully someone else can chime in with an answer as I have a lot of customers who are unable to connect to my product with their PCs.
I am going to reach out to FTDI support to see if they can shed some light on this problem. I will post back here if I hear something back.
I came across the same problem just recently. If you run FT_prog you can replicate this by removing the dongle and putting it back. FT_prog takes a second or so to recognise the device again.
I put the checking code in a loop with a 1 second wait and it now finds the dongle on the second attempt reliably.
Related
I have ZKTeco Biometrics device which is connected with a C# windows application using This tutorial (C# ZKTeco Biometric Device Getting Started).
It is working fine but after sometime, my application becoming failed to ping the device. As below code suggested, I am trying to ping the device after every 25 seconds.
private void TimerCheckPingAndCloseAttendanceForm() {
timerCheckPingAndCloseAttendanceForm = new Timer();
timerCheckPingAndCloseAttendanceForm.Tick += new EventHandler(CheckPingAndCloseAttendanceForm);
timerCheckPingAndCloseAttendanceForm.Interval = 25000;//25 seconds.
timerCheckPingAndCloseAttendanceForm.Start();
}
private void CheckPingAndCloseAttendanceForm(object sender, EventArgs e) {
string ipAddress = tbxDeviceIP.Text.Trim();
if (UniversalStatic.PingTheDevice(ipAddress) == false) {
//CloseAttendaceListForm();
IsDeviceConnected = false;
string infoString = "Application started on " + applicationStartDateTime.ToString() + " and ping failed on " + DateTime.Now.ToString() + " then, app closed while device ip is "+ ipAddress;
File.AppendAllText("ConnectionLog.txt", infoString + Environment.NewLine);
Application.Exit();
//timerCheckPingAndCloseAttendanceForm.Tick -= new EventHandler(CheckPingAndCloseAttendanceForm);
}
}
And when I am trying to ping the command from cmd the device show destination host is unreachable. But whenever I restart the device, the ping working fine. I don't know where is the problem? Either the network problem or its coding issue?
Note: I am doing a ping on regular time interval, because on Disconnected Event is not working. I am assuming ping failed meaning is the device has disconnected with the application.
First of all : Thank you for going through my article
You are doing it the wrong way.
Trying to ping the device after every 25 seconds is unnecessary.
The only job of the UniversalStatic.PingTheDevice method is to check if the device is presumably active, the first time you connect with the device.
If you want to check the status of the device i.e IsDeviceConnected, All you need to do is register to the device OnDisConnected event provided by the SDK.
It seems the code here at line number 57 has already done the OnDisConnected event registration for you.
All you need to do now is set your IsDeviceConnected to false when the objCZKEM_OnDisConnected method in the ZkemClient.cs class is called upon by the device itself.
Sample snippet :
In the ZkemClient.cs class file, between line number 81-84
void objCZKEM_OnDisConnected()
{
IsDeviceConnected = false; // <-- Add this line
}
Now, Every time you try to make a call to the device, All you need to do is check for the value of your IsDeviceConnected.
Not having the actual code and the hardware setup, this answer is a bit of a shot in the dark, but here goes …
Since it works initially, this is not a hardware configuration or network configuration issue. Yet it says that after a while the destination (reader) becomes unavailable. This is probably not a network keepalive issue because you are pinging every 25 sec. Looking at the code that you referenced, it shows opening a connection and hooking up callbacks, and making a call to a hardware feature.
My guess would be maybe you are opening the connection each ping and not closing the connection, then after a number of attempts the hardware jams because there are too many open connections. Just a guess. If this is the problem then to fix it, either close the connection or, better, keep the connection open and re-use it.
Alternative possibility would be that the router(s) between your code and the device are detecting too many pings and blocking the connection as a possible DOS attack. If this is the problem then to fix it, configure the router to allow the traffic.
This sounds like the device misbehaving. The error "destination host is unreachable" corresponds to an ICMP packet, same type of packet as ping but different job, being sent by your router saying "I have no idea which device has that IP". This normally happens when the device stop responding to ARP, which basically asks "who has this IP?" and expects a machine to respond "I have it" with its MAC address. The router constantly refreshes its ARP table, forgetting old values.
So when you boot the device it is 'happy', responding to ARP and responding to pings; however, something happens and it at least stops responding to ARP (probably something more wrong with it). Depending on its architecture it could be loaded down doing other stuff and unable to respond, or it could just be locked up.
Try slowing down other actions to the device (if your polling it for information other than ping, do it slower) and also see if you can get status from the device via another output (does it have a uart?).
OPTION 1
Since that restarting the device fixes your problem for a period of time, check that the IP that you are using is not in use on another device/computer/element_of_the_network.
ZKTeco devices come with the IP 192.168.1.201 configured by default. Configure a different static IP and avoid using DHCP (it´s well known that using DHCP in ZKTeco devices isn´t a good choice since they don´t refresh automatically the IP after rebooting the system or any network change).
Make sure that the IP is not in use and that nobody else will use it.
OPTION 2
Another thing that It may be the cause of your problem, is that you are using zkemkeeper in a different part of your application (or into a different application) and you are not closing the oppened connections properly... That may be blocking all network activity from the device. To close the connection just make sure that you call this sdk method after performing all the necessary actions:
sdk.Disconnect();
It looks like a code issue. While investigating UniversalStatic.PingTheDevice(ipAddress), its found that its calling System.Net.NetworkInformation.Ping.Send setting DontFragment = true. Reference: https://github.com/zaagan/BioMetrix/blob/master/BioMetrixCore/Utilities/UniversalStatic.cs#LC51. The timeout for the ping is set to 120 milli seconds. This tries to send 32 bytes of data to the given IP.
Following is the snippet taken from https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.ping.send?view=netframework-4.7.2 would answer the root-cause of your issue
If the DontFragment property is true and the total packet size exceeds the maximum packet size that can be transmitted by one of the routing nodes between the local and remote computers, the ICMP echo request fails. When this happens, the Status is set to PacketTooBig.
So when you restart your device, possibly, the data travelling on the network gets lost. Hence it started working till the packets reaching its limit.
Few suggestions:
Try calling System.Net.NetworkInformation.Ping.Dispose in PingTheDevice before returns
Increase the timeout from 120 milliseconds to seconds.
Increase the timerCheckPingAndCloseAttendanceForm.Interval to 1 min.
Check the return code of the System.Net.NetworkInformation.Ping.Send and find the associated failure meaning
Please share your findings if the above suggestions do not help you finding the root-cause.
you try this code for ping the device,
try
{
IPAddress ipAddress = IPAddress.Parse(ipAdd);
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(ipAddress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
return true;
else
{
return false;
}
}
catch (Exception)
{
return false;
}
Thanks.
My selected characterstic property returns Indicate but still WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue) does not return Success status
This is the piece of code:
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);//writes cccd to the ble device to enable indication or notification
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);//writes cccd to the ble device to enable indication or notification
if (status == GattCommunicationStatus.Success)
{
AddValueChangedHandler();
rootPage.NotifyUser("Successfully subscribed for value changes", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser($"Error registering for value changes: {status}", NotifyType.ErrorMessage);
}
It always goes in else condition.I have put Indicate property True but still it does not work.
Please help, any suggestions?
Thanks
Does the characteristic support Writing?
GattCharacteristicProperties properties = characteristic.CharacteristicProperties;
if (properties.HasFlag(GattCharacteristicProperties.Write) || properties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse))
{
//writing is supported..
}
If it does:
MSDN
There are four statuses:
Access Denied
Device Unreachable
Success
Protocol error
As you have not posted the status, I can't give you a precise answer... If it's Protocol Error, you need to provide more information on the device.
Try this:
Access Denied: Retry, by getting the characteristic without using the Bluetooth Cache
var characteristics = await selectedService.GetCharacteristicsForUuidAsync(characteristicUuid, BluetoothCacheMode.Uncached);
selectedCharacteristic = characteristics[0];
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);
Then retry writing.
Device Unreachable: The connection was lost. Either the device is too far away or you need to reconnect. Recreate the device object and retry.
BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceId);
.....
One thing to be aware of, that's not well documented, is that the peripheral needs to have a writable Gatt CCCD Characteristic Descriptor with a very specific UUID (00002902-0000-1000-8000-00805f9b34fb) to be technically compliant. Android and iOS will not fail if the peripheral is non-compliant, but UWP currently will throw this exception. There does not appear to be any way to get UWP to work with a non-compliant device.
If you are making a peripheral, be aware that no matter what UUID's you use for anything, the CCCD needs be the 2902 UUID. Otherwise you'll get this UWP exception.
I'm trying to figure out which serial port belongs to an Arduino.
Since the SerialPort class does not reveal any information about
the underlying hardware, I'm trying to use LibUsbDotNet instead.
Using the following code to get a list of all devices:
UsbDevice.ForceLibUsbWinBack = true;
var devices = UsbDevice.AllDevices;
I can then either iterate over all of them or search for the Arduino specifically:
var deviceFinder = new UsbDeviceFinder(0x2341, 0x8036);
var arduino = devices.Find(deviceFinder);
This actually works and I get an instance of UsbRegistry,
but I'm unable to open the device or determine through which serial port it is exposed.
USBDevice arduinoUsbDevice;
usbRegistry.Open(out arduinoUsbDevice);
Since this doesn't work arduinoUsbDevice remains null.
I then tried using the DeviceNotifier class which raises an event whenever
a device is added or removed from the system:
var notifier = DeviceNotifier.OpenDeviceNotifier();
notifier.OnDeviceNotify += (s, e) =>
{
WriteLine(e.Device?.Name ?? "no device");
WriteLine(e.Device?.IdProduct ?? 0);
WriteLine(e.Device?.IdVendor ?? 0);
WriteLine(e.EventType);
WriteLine(e.Object);
WriteLine(e.Port?.Name ?? "");
};
Now whenever I connect the Arduino to the computer, the event is raised twice.
As if two separate devices are being connected,
but only one of them is ever returned by UsbDevice.AllDevices:
` \\?\USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
32822
9025
DeviceArrival
FullName:USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Vid:0x2341
Pid:0x8036
SerialNumber:7&533912d&0&2
ClassGuid:a5dcbf10-6530-11d2-901f-00c04fb951ed
no device
0
0
DeviceArrival
[Port Name:COM5]
COM5
The first time the event is raised for the device we could find before as well.
The second time it is raised with e.Device set to null but
with e.Port set to COM5, which is the information I'm after.
So the problem is I can only get this information when the Arduino is connected
after the software has been started and even then linking the two events is
kind of a guessing game.
Is there any way of getting the information without having to rely
on the events raised by the DeviceNotifier class?
I'm aware I could use System.Management and WMI queries, but
these are not available on Linux and MacOS, which is why I'm using
LibUsbDotNet instead.
The native library I'm using is libusb-1.0
I try to search my serial port of my GPS on my tablet (Windows CE).
I know that this is on "COM 3" but I want the program to find this by itself. I mean run in a loop (for) on all ports and search for this.
My question is which "if" I need to write to tell the program "this is my GPS port".
Thank you all.
Gps as i know works with a physical or virtual serial com port (ie com via usb). Since only one application can open a com port at a time there should be no program using gps while searching for the gps-port.
You already gave the answer "loop (for) on all ports and serche for".
Note the example below is an untested scetch how it could work. Feel free to update this wiki page to fix possible errors and add missing functionality.
public string FindGpsPort()
{
foreach(string portname in System.IO.Ports.SerialPort.GetPortNames())
{
// using to make shure that the testport is closed after test
using (SerialPort testport = new SerialPort(){PortName = portname})
{
// maybe neccessary to set baudrate, parity, ... of com port
testport.Open();
// to do if error or exception this is not the
// gps port or some software already uses the gps-port
// to do: read some data from port and verify if it is GPS-Data
// if valid return portname ;
}
}
// All com ports tried but not found. throw exception or return error code
return null;
}
I'm using the .NET TWAIN code from http://www.codeproject.com/KB/dotnet/twaindotnet.aspx?msg=1007385#xx1007385xx in my application.
When I try to scan an image when the scanner is not plugged in, the application freezes.
How can I check if the device is plugged in, using the TWAIN driver?
Maybe I'm taking the question too literally, but using the TWAIN API, it is not possible to check if a device is plugged in i.e. connected and powered on. The TWAIN standard does define a capability for this purpose called CAP_DEVICEONLINE, but this feature is so poorly conceived and so few drivers implement it correctly that it is useless in practice.
The closest you can get is this: Open the device (MSG_OPENDS): Almost all drivers will check for device-ready when they are opened, and will display an error dialog to the user. There is no TWAIN mechanism for suppressing or detecting this dialog Some drivers will allow the user to correct the problem and continue, in which case you (your app) will never know there was a problem. Some drivers will allow the user to cancel, in which case the MSG_OPENDS operation will fail, probably returning TWRC_CANCEL but maybe TWRC_FAILURE
A few TWAIN drivers will open without error even though the device is off-line. Such a driver may return FALSE to a query of CAP_DEVICEONLINE. Such a driver will probably do the device-online check when you enable the device with MSG_ENABLEDS, and then if the device is not on-line, you get the error dialog to the user, and so on as above.
Aside and IMPO: WIA is 'more modern' but also much less comprehensive for scanning than TWAIN, and in my experience unusable for multipage scanning from a document feeder. WIA's designers and maintainers seem not to understand or care about scanners other than low-end consumer flatbeds. It's good for cameras.
I started of with the same source code that you downloaded from CodeProject, but moved most of the code in MainFrame.cs that initiates the scanning to a Scanner class. In order to check for scan errors I call the following method in stead of calling Twain.Acquire directly:
enum AcquireResult
{
OK = 0,
InitFailed = 1,
DeviceIDFailed = 2,
CapabilityFailed = 3,
UserInterfaceError = 4
}
private void StartScan()
{
if (!_msgFilter)
{
_parent.Enabled = false;
_msgFilter = true;
Application.AddMessageFilter(this);
}
AcquireResult ar = _twain.Acquire();
if (ar != AcquireResult.OK)
{
EndingScan();
switch (ar)
{
case AcquireResult.CapabilityFailed:
throw new Exception("Scanner capability setup failed");
case AcquireResult.DeviceIDFailed:
throw new Exception("Unable to determine device identity");
case AcquireResult.InitFailed:
throw new Exception("Scanner initialisation failed");
case AcquireResult.UserInterfaceError:
throw new Exception("Error with the Twain user interface");
default:
throw new Exception("Document scanning failed");
}
}
}
I usually initiate the scan event on a seperate thread in order for the app not to freeze while scanning is in progress.
just add this code on your TwainCommand (cmd)
case TwainCommand.Null:
{
EndingScan();
tw.CloseSrc();
Msgbox("There is no device or the scannning has been cancelled.");
break;
}
this will appear if the systems detect no device or the scanning has been cancelled.
You can check in the registry. In:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{6bdd1fc6-810f-11d0-bec7-08002be2092f} each scanner that's ever been detected is enumerated there in the subkeys.
Starting with 0000, go through and check if the CreateFileName value is blank or has data.
If it has data, it's a connected scanner, if it's blank, it's not connected.
i try do this but dont work good with TWAIN mybe try WIA
mybe try this:
on buton run scanner
timer1.Interval = 30000;
switch (cmd)
{
case TwainCommand.TransferReady:
{
..........
}
default:
{
timer1.Start();
break;
}
on event timer tick
{
EndingScan();
tw.CloseSrc();
}