Looping through com ports - c#

I am writing an application that will loop through my computer's com ports. The issue I am having is one of the com ports is opened on PC startup by another process which causes an exception to be thrown:
System.InvalidOperationException: 'The port is already open.'
I have successfully handled the exception but it seems to break the foreach loop once it hits the exception and will not continue to the other ports. Am I handling the expectation correctly by having the try catch block inside of the foreach loop?
private void Rescan()
{
bool error = false;
int baud = 115200;
string[] ports = SerialPort.GetPortNames();
foreach (string port in ports)
{
try
{
comPort.PortName = port;
comPort.BaudRate = baud; //convert Text to Integer
comPort.Open();
comPort.DtrEnable = true;
comPort.DataReceived += SerialPortDataReceived;
System.Windows.MessageBox.Show(port.ToString());
}
catch (InvalidOperationException e)
{
System.Windows.MessageBox.Show("");
}
}
}
I know it can be dangerous and poor programing practice to open ALL com ports that are not mine, so my end goal is to open each com port and write some string like "ID_DEVICE" which will then prompt a response from the firmware of the device I am trying to connect to (Arduino). If the com port does not have a proper response then my application will close that specific port and only leave open the ports that had the proper response.

I think John is right, you have to instanciate a new serial port for each port name. If you register an event, don't forget to unsubscribe. F.e. you can store the open comports in an collection to be able to close, deregister the event and dispose the serial port.

Related

C# can fail to open STMicro virtual COM port

I have an issue with opening an STMicro USB virtual COM port.
When I plug the device into my PC, the COM port appears as it should, and the Windows Device Manager indicates it is working properly.
I have a C# program on the PC which selects and opens this port.
However, in about 1 in 10 attempts, the PC program sticks on the port.open() command, and after about half a minute, returns with the error "The semaphore timeout period has expired".
I have written a tiny C# program that does nothing more than open the port. This still gives the behaviour noted.
public partial class Form1 : Form
{
SerialPort port = new SerialPort();
string portName = "COM1"; // Give it a default to start with
public Form1()
{
InitializeComponent();
// Populate the COM port selector combobox with available port names
cmbPortSelect.Items.Clear();
string[] activePorts = SerialPort.GetPortNames();
foreach (string availablePort in activePorts)
{
cmbPortSelect.Items.Add(availablePort);
}
// Declare the serial port
port = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
port.ReadTimeout = 100;
}
private void cmbPortSelect_SelectedIndexChanged(object sender, EventArgs e)
{
if (cmbPortSelect.SelectedIndex != -1)
{ // It will get set to -1 (i.e. no selection) in the catch below - we don’t want this selected item change to do anything
if (port.IsOpen) port.Close();
port.PortName = (string)cmbPortSelect.SelectedItem;
System.Threading.Thread.Sleep(50);
try
{
port.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
cmbPortSelect.SelectedIndex = -1; // Clear the selected item box
}
}
}
}
If instead of using my C# program to open the port, I use the communications program PuTTY, it works every time.
In addition, if I plug in a device with an FDTI USB virtual COM port, it also works every time.
I'm using Windows 7, with the STMicro VCP drivers ver 1.3.1, but the same behaviour occurs with Windows 10 and the generic Microsoft drivers, which STMicro recommend we use.
There is a version 1.5.1 drivers for Windows 7, but when I installed them, it reported that they had installed correctly, but the Device Manager still reported ver 1.3.1.
Has anyone noted any similar behaviour?
That is seemed to be a timing issue. Try to increase your delay from 50 to, say, 200 ms and check the difference. As the doc says: The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly., sadly, there is no actual time specified.

UDP client assigns free port too late

In C#, .Net 4, I have a need to send a UDP message on a port and listen for responses on the same port.
I was using a fixed port, but a customer ran into an issue with that, so I want to use any available port. It seems like I can do that by using 0 for the port number, but it isn't working. Digging into that some more, it appears it doesn't assign the port until it is actually used, so my two bind statements might be going to different ports.
From MSDN:
"If you do not care which local port is used, you can create an
IPEndPoint using 0 for the port number. In this case, the service
provider will assign an available port number between 1024 and 5000.
If you use the above approach, you can discover what local network
address and port number has been assigned by calling the
LocalEndPoint. ... If you are using a connectionless protocol, you
will not have access to this information until you have completed a
send or receive."
Trouble is, I want to set up my send and receive on initialization. If I wait until the first send to set up the receive, I might miss some responses. Is there a better answer than just sending a garbage message to assign the port so I can finish the initialization?
My code:
public bool InitializeSockets()
{
try
{
IPAddress localaddr = LocalIPAddress();
localep = new IPEndPoint(localaddr, 0); //(was port 50000);
//-----------------------------------------------------------------
// set up listener port for responses coming back on the same port
//-----------------------------------------------------------------
listener = new UdpClient();
listener.ExclusiveAddressUse = false;
listener.Client.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, true);
listener.Client.Bind(localep);
detailsOutputText = "Ready to listen on " + localep;
ustate = new UdpState();
ustate.e = localep;
ustate.u = listener;
//------------------------
// set up broadcast port
//------------------------
bcast = new UdpClient();
bcast.Client.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, true);
bcast.Client.Bind(localep);
//-------------------------------
// start listening for responses
//-------------------------------
msgRxCallback = listener.BeginReceive(new AsyncCallback(DiscoveryCallback), ustate);
return true;
}
catch (Exception exc)
{
if (exc is SocketException)
{
// This only catches if another process has opened that port without sharing it
// or if firewall blocks it?
MessageBox.Show("Error opening IP address:Port : " + localep;
}
else
MessageBox.Show(exc.ToString());
return false;
}
}
Thanks
Two options:
Create a configuration file that contains the port number. On initialization, read the config file and use that port number when setting up the clients. Supply a config file with a default port number, and give your customer instructions about how to change it if required.
In your initialization, create a receiver, give it a very short receive timeout, and call Receive. That will cause the port to bind. You can then get the local end point and use that when you create your sender. See Can I set the timeout for UdpClient in C#? regarding setting the receive timeout.

IO operation aborted error thrown while reading serial port

We are trying to read data written by an external device (weighing scale in this case) connected to serial port using .Net serial port class.
First we initialize the serial port as below:
InitializeSerialPort()
{
if ((serialPort != null) && (serialPort.IsOpen))
{
serialPort.Close();
serialPort.Dispose();
serialPort = null;
}
serialPort = new SerialPort("COM2", 9600, Parity.None, 8,
StopBits.One) { Handshake = Handshake.None };
serialPort.DataReceived += serialPort_DataReceived;
serialPort.NewLine = "\r";
}
We are using background worker thread to poll the device on continuous interval by sending a command(understood by the weighing scale) on the serial port. As soon as we send the command the device connected to serial port reacts with a response output. We call ReadLine API of SerialPort class to get the data present on the serial port written by the device in the DataReceived event as shown in the code snippet below :
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
data = serialPort.ReadLine();
}
catch(System.IO.IOException ex)
{
//since serial port reading threw an error so there is no value to be parsed hence exit the function.
return;
}
//if no error then parse the data received
}
I'm using System.IO.Ports.SerialPort class of .Net framework 4.0. I can see a number of people posting this issue on other forums but with no specific resolution. Some of them terming .Net Serial port class as buggy which has not been fixed by Microsoft till date. One of the forums where this error is mentioned is here
I also tried the solution posted here but of no help. I need some input if any one else has come across this issue or its resolution.
We were able to solve this problem by locking the code inside serialPort_DataReceived method.
Object lockObject = new Object();
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock(lockObject)
{
try
{
data = serialPort.ReadLine();
}
catch(System.IO.IOException ex)
{
//since serial port reading threw an error so there is no value to be parsed hence exit the function.
return;
}
}
//if no error then parse the data received
}
We had set the polling interval to poll the device connected on serial port as 10 seconds. Possibly the entire code present inside serialPort_DataReceived method was sometimes taking more than 10 seconds. We were not able to exactly establish this fact as it was not happening every time may be.
So we locked the entire piece of code inside serialPort_DataReceived method using lock keyword in C# to ensure that the new execution for new data received from serial port doesn't start unless the older reading hasn't finished. The issue got resolved after implementing this code on trial and error basis. Hope this helps others as well if they come across such an issue.

Connect to a device through a serial port and send a command, but nothing is returned

I need to connect to a sensor through a serial port and read some data off it. I connect to it and send the command, but nothing is returned from the device, instead a Timeout exception is thrown. Similar questions here on stackoverflow use the OnDataReceived event, i tried that and it did not work. The parameters i used to initialize and the command i send work as expected on Putty.
-- what am i missing here
void Read()
{
SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
try
{
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Encoding = new ASCIIEncoding();
serialPort.ReadTimeout = 1000;
serialPort.WriteTimeout = 900;
serialPort.Open();
serialPort.WriteLine("TEMP");
MessageBox.Show("Reading");
MessageBox.Show(serialPort.ReadLine());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
serialPort.Close();
}
}
Thank you
serialPort.Handshake = Handshake.XOnXOff;
Maybe that's correct, it is pretty unusual. But real devices almost always pay attention to the hardware handshake signals, in addition to an Xon/Xoff flow control protocol. The DTR (Data Terminal Ready) and RTS (Ready To Send) signals have to be turned on before the device is convinced that it is connected to a real computer. A program like Putty will always turn them on, your program does not.
Add these two required lines:
serialPort.RtsEnable = true;
serialPort.DtrEnable = true;
And ensure that the serialPort.NewLine property correctly matches the end-of-message character used by the device. Temporarily use ReadExisting() instead to avoid getting bitten by that detail, don't leave it that way.
I would suggest that the problem is with the encoding you're using. To check if that's the problem use a sniffer of your choice to see that the bytes transferred on your application are the same as on putty.
Only be sure that you're actually trying to read the bytes when using a sniffer because if you don't they won't be shown on the output.
If that doesn't show you anything you can try to change your ReadLine() method to ReadByte() to ensure that there's no problem with the reading type that you're using.
Serial port sniffers
http://www.serialmon.com/
virtual-serial-port.org/products/serialmonitor/?gclid=CInI2ZPL_bsCFaxr7Aod8S4A8w
www.hhdsoftware.com/device-monitoring-studio

GPS serial port searcher

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;
}

Categories

Resources