I'm writing a C# program that sends some simple commands to Arduino. via USB serial virtual port.
Sometimes happen that the program hangs, even if the code is protected by a try/catch block.
When I saw the problem the problem seem to be in closing the port.
The function is very simple:
void Send() {
try {
Debug.WriteLine("SR1 "+rel+" "+status);
_serialArduino.Open();
Debug.WriteLine("SR2");
_serialArduino.WriteLine(string.Format("switch {0} {1}\n", rel, Convert.ToSByte(status)));
Debug.WriteLine("SR3 '"+_serialArduino.ReadLine()+"'");
_serialArduino.Close();
Debug.WriteLine("SR4");
Thread.Sleep(400);
} catch (Exception e) {
LogManager.Write(string.Format("ERR SwitchRel({0}, {1}) - {2}", rel, status, e.Message));
}
}
I read about a problem during the Close function but in this case no DataReceived event handler is defined (==null).
Any idea?
* Edited to add some details *
After days of debugging and log analysis I discovered the following:
I'm working on a device running Win7Embedded Standard
The application is written in C#
after some time (or maybe caused from something unknown, so far) the port connecting Arduino disappeared from the list of the enumerated ports
the program initially reports on my log 'Device disconnected' and then 'Port COM9 does not exist' messages
The device manager reports COM9 on the 'Ports' tree (!!)
If I shut the program and re-run it, it reports 'COM9 does not exist' and if I list the ports the COM9 does not appear
My guess is that the usbser driver is in a mess.
The only solution, so far, is reset the board.
Is there a way to reset the driver without reboot and check if it returns in a known state?
Or maybe is the DotNet Framework that does not detect the port ?
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.
I wrote a simple program that makes a port range open by listening on the ports specified. I noticed, that it takes different time on Windows and on Linux for this program to open all ports from port 1 to port 65535.
On Linux it takes about 2 seconds opening all of the ports. On Windows it's closer to half an hour (I did not measure the exact number of minutes, because I never waited for it to finish).
Is Windows objectively slower in this regard, and if yes, why and can I do anything to make this run faster?
Note, that while tests were run on very different hardware, it probably does not matter, given that the timing differs in orders of magnitude.
// This is a very basic TCP port listener that allows you to listen on a port range
// If you run this program outside of firewall and run a port scanner inside a firewall
// pointing to the ip address where this program runs, the port scanner will be able you
// to tell which exactly ports are open on the firewall
// This code will run on Windows, but most importantly also on linux.
// DigitalOcean.com has all ports for their VMs open by default. So spin a new VM,
// copy pln.cs in your (root) home folder and then run:
// sudo apt-get update
// sudo apt-get install mono-complete -y
// mcs pln.cs
// ulimit -n 66000
// ./pln.exe 1 65535
// Now you can use the VM ip address to determine open ports on your firewall
// Note that this is a dev utility, and is aimed to be minimal - no input validation,
// no error handling. In case of a error stack trace is dumpled to console
using System;
using System.Net;
using System.Net.Sockets;
namespace PortListener
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Usage: pln.exe startPort [endPort]");
Listen(args);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex);
}
}
private static void Listen(string[] args)
{
int startPort = int.Parse(args[0]);
int endPort = int.Parse(args[1]);
Console.WriteLine("Started binding...");
for (int i = startPort; i <= endPort; i++)
{
if (i % 100 == 0 && Environment.OSVersion.Platform != PlatformID.Unix)
{
Console.WriteLine("Binding port " + i);
}
TcpListener listener = new TcpListener(IPAddress.Any, i);
try
{
listener.Start();
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
{
Console.WriteLine("Port " + i.ToString() + " already in use");
continue;
}
if (ex.SocketErrorCode == SocketError.AccessDenied)
{
Console.WriteLine("Access denied to port " + i.ToString());
continue;
}
throw;
}
listener.BeginAcceptSocket(DoAcceptSocketCallback, listener);
}
Console.WriteLine("Finished binding. Ctrl-C to stop.");
Console.ReadLine();
}
private static void DoAcceptSocketCallback(IAsyncResult ar)
{
TcpListener listener = (TcpListener) ar.AsyncState;
listener.EndAcceptSocket(ar).Close();
Console.WriteLine("Connection on port " + ((IPEndPoint) listener.LocalEndpoint).Port.ToString());
listener.BeginAcceptSocket(DoAcceptSocketCallback, listener);
}
}
}
Update 1, so this is apparently has nothing to do with .net as such. If we capture a diagnostic trace as described here or here, we will see something like this:
This tells us that winsock listen call takes in vicinity of 400 milliseconds. Any idea why?
This question describes similar problem, and some people can reproduce that and some cannot. My guess would be that it depends on Windows/SP version. I'm running Windows 10. Long time ago, there was a rate limiting issue for half-open connection, which caused many people grief, because they could not run their torrents as efficiently. This might be caused by something similar, although it does not look like this is related to that old issue.
Update 2 - tested on Windows 7 machine, and it worked very fast (comparable to linux timings). Apparently something changed since then?
So, yeah. Bad driver.
The difference between a pc where there is no delay and when there are big delays, is that the one where there is no delays, does not have a lot of crap installed.
Download a tool that allows viewing installed drivers, and try to guess which ones are causing slowdown. You can use Autoruns from sysinternals suite (see drivers tab) or Nirsofts DriverView or InstalledDriversList.
If you use the latter one, sort driver list by the group column and look at NDIS and/or network. It's most likely one of them.
So when I got started I measured how long it takes to open ports from 1 to 10000 on my machine. Then I removed drivers one by one and took measurements again. The results are below:
All Crap installed - 226 seconds
Same as above but removed Networx Traffic monitor - 9 seconds
Same as above but removed TeamViewer remote assistance - 7 seconds
Same as above but removed Checkpoint VPN client - 0 seconds
Note, just switching off these programs do not help. The drivers need to be removed/disabled to see an improvement.
So no need to blame Windows. There are a lot of other software vendors out there to choose from ;)
I have an issue when there is an exception in a block of code that uses a lock. I am reading and writing to a serial port and there are several different threads that need access to the same serial port. This is managed by a lock. I have no issues except if the serial port stops working. This can happen since the software controls an RF transmitter and occasionally the rf can cause usb to serial ports to stop functioning. If you then attempt to write to the port you will get a write timeout. I tried handling this from a try - catch exception handler. However, the program locks hard at that point and has to have the task killed. I am not sure if this is coming from the exception or the message box I am trying to display since it could result from a background thread. Here is the code:
lock (_object)
{
try
{
if (portOpened)
{
port.Write(data);
}
else
{
MessageBox.Show("The radio is not connected. Please select a ComPort in the settings dialog");
}
}
catch (Exception x) //this will capture a write exception.
{
MessageBox.Show("The program is unable to write to the serial port. Select OK to close the program";
Application.Exit();
}
finally
{
}
}
Thanks for any help
If you want to force to exit the app, Application.Exit is not a good candidate, as it simply pushes the Close request on message queues of all threads, but does not force anything. If you want to stop app at any cost, use Environment.Exit(exitCode), or may be even better Environment.FailFast, with specified exception so it will be logged into the system's log: convenient for future investigations.
I am developing a C# WinForms Windows application that runs from the tray. I need to provide some reasonable level of error handling and instruction to the user. In order to test if I am able to open a serial port for communication, I wish to have a way to test if it is already open or if it is unopenable for whatever reason.
I came up with this:
if (SerialPort.GetPortNames().Select((n) =>
n.ToUpperInvariant()).Contains(mycomportname))
{
// Port found, check to see if we can use it by test-opening
using (var sp = new SerialPort(mycomportname))
{
// Check to see if we can open this port
try
{
if (sp.IsOpen) throw new Exception("Serial port is already open");
sp.Open();
sp.Close();
}
catch (Exception ex)
{
throw new Exception("Serial port is in use");
}
}
}
else
{
// ...
}
commManager.PortName = mycomportname;
if (commManager.OpenPort())
{
// .. always returns false because causes UnauthorizedAccessException on open
}
For some reason the serial port does not seem to be fully released by the 'using' statement. The UnauthorizedAccessException does not occur when I delete the using statement and the statements inside it. How do I write robust error-tolerant serial port opening code?
The MSDN article for SerialPort warns about this explicitly, albeit vaguely. SerialPort uses a worker thread to generate events like DataReceived and ErrorReceived. That thread gets started when you call Open() but it needs time to exit again after you call Close() or Dispose(). The physical port is in use until that happens. Exactly how long that takes is unpredictable. Usually within a millisecond but the worst-case is seconds when the machine is heavily loaded. Your code only waits for a nanosecond so you'll always get an exception.
The approach otherwise just doesn't make sense. Once you opened the port and got no exception then just keep it open. No point in closing it again and reopening it. Which is the simple solution.
And never do this kind of port scanning when GetPortNames() returns more than one port. The odds that the first one will open are very high, the odds that it is the right one are low. Murphy ensures that fifty-fifty odds turn into 1%. You always need to provide a config file so the user can pick the correct one. Only consider doing the port scanning when you populate a combobox with choices in a config helper window. Only skimp on this if you are in control over the machine configuration, that's pretty rare.
To start I am coding in C#. I am writing data of varying sizes to a device through a socket. After writing the data I want to read from the socket because the device will write back an error code/completion message once it has finished processing all of the data. Currently I have something like this:
byte[] resultErrorCode = new byte[1];
resultErrorCode[0] = 255;
while (resultErrorCode[0] == 255)
{
try
{
ReadFromSocket(ref resultErrorCode);
}
catch (Exception)
{
}
}
Console.WriteLine(ErrorList[resultErrorCode[0] - 48]);
I use ReadFromSocket in other places, so I know that it is working correctly. What ends up happening is that the port I am connecting from (on my machine) changes to random ports. I think that this causes the firmware on the other side to have a bad connection. So when I write data on the other side, it tries to write data to the original port that I connected through, but after trying to read several times, the connection port changes on my side.
How can I read from the socket continuously until I receive a completion command? If I know that something is wrong with the loop because for my smallest test file it takes 1 min and 13 seconds pretty consistently. I have tested the code by removing the loop and putting the code to sleep for 1 min and 15 seconds. When it resumes, it successfully reads the completion command that I am expecting. Does anyone have any advice?
What you should have is a separate thread which will act like a driver of your external hardware. This thread will receive all data, parse it and transmit the appropriate messages to the rest of your application. This portion of code will give you an idea of how receive and parse data from your hardware.
public void ContinuousReceive(){
byte[] buffer = new byte[1024];
bool terminationCodeReceived = false;
while(!terminationCodeReceived){
try{
if(server.Receive(buffer)>0){
// We got something
// Parse the received data and check if the termination code
// is received or not
}
}catch (SocketException e){
Console.WriteLine("Oops! Something bad happened:" + e.Message);
}
}
}
Notes:
If you want to open a specific port on your machine (some external hardware are configured to talk to a predefined port) then you should specify that when you create your socket
Never close your socket until you want to stop your application or the external hardware API requires that. Keeping your socket open will resolve the random port change
using Thread.Sleep when dealing with external hardware is not a good idea. When possible, you should either use events (in case of RS232 connections) or blocking calls on separate threads as it is the case in the code above.