COM Port Error when port is already streaming - c#

I have an application that reads from a COM Port and then does something with the data that it receives. I am currently using a COM Port emulator (Since i don't have the device available for me to use) but I am feeding it a sample of the data. The program seems to work perfectly fine if I open the COMPort before I start transmitting data. However, if I start transmitting before I open the COMPort, and then I open the port, the dataReceived event is never fired and I am never able to get any data. I have even tried to flush the INBuffer as soon as I open the port but am unable to read from it.
My code to open the port is this:
public void setupComPort(string baudRate, string dataBits, string stopBits, string parity, string portName)
{
if (comPort.IsOpen)
comPort.Close();
comPort.BaudRate = int.Parse(baudRate);
comPort.DataBits = int.Parse(dataBits);
comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), stopBits);
comPort.Parity = (Parity)Enum.Parse(typeof(Parity), parity);
comPort.PortName = portName;
// When data is recieved through the port, call this method
comPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
try
{
// Open the port
comPort.Open();
//If there's data in buffer, discard so we can start receiving
//comPort.DiscardInBuffer();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error Opening Port", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
Any help would be appreciated.

Its probably an issue with the emulator. I'll guess the issue will go away when you have the actual hardware. The only other thing I can think to try is setting the ReceivedBytesThreshold to something other than the default (like 10 or something).

Related

Can't access COM port greater than 99 in C#

I have a small issue with a program I am writing in Visual Studio 2022.
I have numerous devices that attach to the USB virtual com port, and because of the way that Windows enumerates the USB to serial chip in the device, I can have com ports listed as well over 100 (576 at last count). These com ports are not connected simultaneously, but one at a time, each enumerating as one higher than the previous port.
My problem is that I can access up to COM99, but when it rolls over to 100, the port will not connect. There is no error message or exception thrown.
The ComboBox will find port 100 (or greater) but the serial port will not connect. I am wondering if the System.IO.Ports Serial function is truncating my port string to "10" for instance.
I should mention that this code works flawlessly up to port 99 (on many different computers). I can see port 100 or greater in the ComboBox, but no success. This should be a simple thing but I'm baffled.
Any help or suggestions gratefully received.
I am using this code for com port connections:
private bool ScanSerial()
{
bool success = false;
//Open the serial port and get the number of the active serial port
serialPortComboBox.Items.Clear();
string[] serialPortNumbers = SerialPort.GetPortNames();
// Iterate each port and add it to the serial port drop down box
foreach (string port in serialPortNumbers)
{
if (!String.IsNullOrEmpty(port))
{
serialPortComboBox.Items.Add(port);
success = true;
}
else
{
MessageBox.Show("No available serial ports", "Serial Ports", MessageBoxButtons.OK);
serialPortInUse = null;
return false;
}
}
// default the highest numbered port as the port to use - the program will try to connect to this port
// if it doesn't find a device, user will have to override the method by selecting from the dropdown and trying again
string lastPort = serialPortNumbers.Max();
serialPortComboBox.Text = lastPort;
label10.Text = lastPort;
serialPortInUse = lastPort;
return success;
}
public bool Connect(string comPort)
{
bool success;
// Baud rate 57600, 8, N, 1 is standard
{
// Allow the user to set the appropriate properties.
_serialPort.PortName = comPort;
_serialPort.BaudRate = 57600;
_serialPort.Parity = Parity.None;
_serialPort.DataBits = 8;
_serialPort.StopBits = StopBits.One;
_serialPort.Handshake = Handshake.None;
_serialPort.Encoding = Encoding.GetEncoding(0);
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
}
try
{
_serialPort.Open();
success = true;
_continue = true;
}
catch (Exception ex)
{
Console.WriteLine("An exception was thrown: \n {0}", ex.ToString());
Console.WriteLine("Press enter to continue.");
Console.ReadLine();
success = false;
}
return success;
}
You can find GetPortNames() source code on github, it iterates over a registry key
https://github.com/dotnet/runtime/blob/b056b7b6a1eca5171e42f697a0b3d3c60d1fc048/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.Win32.cs
There several methods to get the ports. Checkout this post.
How do I get a list of available serial ports in Win32?
Since I guess you are using some kind of vendor specific serialport virtual adapter it make sense to search the registry for a high port e.g COM255 to find a more reliable registry way. I would guess it is an USB PNP device.
Maybe somewhere in HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum

Event handler for read serial port never triggers

Goal:
Trying to write a string to a serial port, read it, then print it to console
Code:
// for waiting until event is detected
private static ManualResetEvent waitHandle = new ManualResetEvent(false);
public Driver()
{
// create new serial port
comPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
// add event handler
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
// configure port
comPort.DtrEnable = true;
comPort.RtsEnable = true;
comPort.ReadTimeout = 3000;
// open port
comPort.Open();
// send string through port
string command = "test \n";
byte[] MyMessage = System.Text.Encoding.UTF8.GetBytes(command);
comPort.Write(MyMessage, 0, MyMessage.Length);
// wait until event is detected
waitHandle.WaitOne();
}
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Write data to buffer and stop wait
Console.WriteLine(comPort.ReadExisting());
waitHandle.Set();
}
Issue:
Write to serial seems to work fine (confirmed by using Serial Port Monitor) but "comPort_DataReceived" never gets called
If I change my code and add
while(true)
{
Console.WriteLine(comPort.ReadExisting());
}
Right after the "comPort.Write(MyMessage, 0, MyMessage.Length);" line so that I'm polling instead of waiting for the event handler then a whole lot of nothing gets written
If I try polling this way
while (true)
{
Byte[] buf = new Byte[2048];
comPort.Read(buf, 0, 2048);
Console.WriteLine(buf.ToString());
}
It just times out (System.TimeoutException: 'The operation has timed out.'
).
I'm not sure where I am going wrong/why I am unable to read from the serial port
Ok, from what I see it looks like there is no device listening on serial port. Then, if you write something to serial port it does not mean that the same data will occur as a received data. This data is outgoing data. If you want to receive data there must be another device connected to that serial port and sending data as a response to your data written.
Turns out it was a hardware issue (no device was writing to serial port) coupled with a misunderstanding (thinking I could write to a serial port and then read what I wrote from within the same program)

C# Application will not Receive Serial Data Stream

I am developing a C# Windows Forms Application to communicate via a Bluetooth Connection with a Raspberry Pi Model 3. This connection is mimicked through a virtual serial port on the client machine. I am able to start a bluetooth connection within the C# program but I cannot receive any data from the program. When I use the program Putty, I can see that the data is transmitting on COM Port the way that I would like it to.
I also discovered a weird sort of glitch with the C# program. If i have the COM Port open on Putty and then start the C# program, an error will occur with the port.open() command since the port is reserved. So then if I close Putty and continue the C# application the data will stream perfectly to the program. Has anyone encountered this issue before? I've been at a bit of a loss for a few days now. The Code in my program is shown below:
using System;
using System.IO.Ports;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;
using System.Threading;
namespace GUIfromPI
{
static class Program
{
//PC BT USB adapter
private static BluetoothEndPoint EP = new BluetoothEndPoint(BluetoothAddress.Parse("##:##:##:##:##:##"), BluetoothService.BluetoothBase); //addressing the usb adapter used on the PC (endpoint)
private static BluetoothClient BC = new BluetoothClient(EP);
//Pi BT Adapter
private static BluetoothDeviceInfo BTDevice = new BluetoothDeviceInfo(BluetoothAddress.Parse("##:##:##:##:##:##")); //addressing the BT adapter on the Rasperry Pi
// private static NetworkStream stream = null;
public static SerialPort mySerialPort = new SerialPort(); //Bluetooth module mimics serial protocol by streaming data through the COM5 port in the host80 computer
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Executing Program...");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (BluetoothSecurity.PairRequest(BTDevice.DeviceAddress, "1234"))//MY_PAIRING_CODE))
{
Console.WriteLine("PairRequest: OK");
if (BTDevice.Authenticated)
{
Console.WriteLine("Authenticated: OK");
BC.SetPin("1234");//pairing code
//BC.BeginConnect(BTDevice.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), BTDevice);
}
else
{
Console.WriteLine("Authenticated:No");
}
}
else
{
Console.WriteLine("PairRequest: No");
}
//mySerialPort = new SerialPort("COM5");
SerialThreadFunction();
}
public static void SerialThreadFunction()
{
mySerialPort.PortName = "COM10";
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DtrEnable = true;
mySerialPort.RtsEnable = true;
mySerialPort.ReadTimeout = 100000;
mySerialPort.Open();
//mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
string mydata = "hello";
while (true)
{
Console.WriteLine(mySerialPort.ReadLine());
mydata = mySerialPort.ReadLine();
}
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received: ");
Console.Write(indata);
}
}
}
UPDATE: I just discovered that declaring my Bluetooth Endpoint, client, and device are interfering with reading off of my serial port. Since the bluetooth connection was already initialized previously, I was able to see the data on the port. Now for why it does this?
Okay, it seems you are not doing anything wrong. Inherently .NET cannot handle multiple ownership of the same port. When you declare your SerialPort instance and connect to say... COM11... You have given ownership of COM11 solely to your SerialPort instance. In order to have access to COM11 you will now need to provide a reference to that specific SerialPort object which has ownership of COM11.
In your case you are opening PuTTY and then running your program. Once PuTTY obtains access to the port, your program will not be able to do so. This is completely standard in the .NET framework. Now, there are other ways that you can get multiple accesses to a COM port, but I think that's outside the scope of this question. Here's a software that will allow you to run an application and sniff traffic over the port at the same time... Free Serial Port Monitor. You can get this for free, and there is a better version for purchase that does all kinds of magic.
Here is a little algorithm for ensuring your port is opened properly, you may want to take this... modify it a little bit... and use it as the Connect method on your BluetoothClient class.
SerialPort port = null;
string error = string.Empty;
bool success = false;
int tries = 5;
foreach(var name in System.IO.Ports.SerialPort.GetPortNames())
{
// try each port until you find an open one
port.Name = name;
// there is always a chance that the port is open
// if trying some operations back-to-back
// give it a few extra tries if necessary
for (int i = tries; i > 0; --i)
{
try
{
// avoid the exception by testing if open first
if (!port.IsOpen)
{
port.Open();
success = true;
return;
}
}
catch (UnauthorizedAccessException e)
{
// sometimes the exception happens anyway, especially
// if you have multiple threads/processes banging on the
// ports
error += e.Message;
}
}
}
In addition to all of this, you may want to watch that your Bluetooth classes are not claiming ownership of the port when you need to read it. That may be what's interfering with reading the port. You really should create one single class and call it say BluetoothClient or something, and have that single class be responsible for all the interactions with the SerialPort reference. This way you ensure that whether you want to send/receive on the port you will always have ownership.

C# socket blocking with zero data

I have implemented C# tcp-ip client (both synchronous & async reading socket).
After each SocketException, I'm automatically reconnecting connection with server.
Then I have tested communication of client with ncat in windows. Here, if I kill ncat, it throws SocketException in C# client and everything works as I imagine.
But then I have tested it with ncat in linux - here communication works OK, but if I kill ncat server (the same settings like at Windows - ncat -l -k -p xxxx), huge amount of empty data (zero B) is received in callback (or waiting on socket in sync version) and no exception is thrown.
One thing is that Windows / Unix version of ncat can have different behavior. But still I need to solve this weird behavior for any version of tcp-ip server.
/* ------------------------------------------------------------------------- */
public void WaitForData()
{
try
{
if (callback == null)
callback = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.thisSocket = socket;
m_result = socket.BeginReceive
(packet.dataBuffer, 0, 256,
SocketFlags.None, callback, packet);
}
catch (SocketException ex) { ///reconnecting }
}
/* ------------------------------------------------------------------------- */
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[256];
}
/* ------------------------------------------------------------------------- */
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
int iRx = theSockId.thisSocket.EndReceive(asyn);
char[] chars = new char[iRx];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
string szData = new string(chars);
szData = szData.Replace("\n", String.Empty);
processMessage(szData);
WaitForData();
}
catch (ObjectDisposedException) { }
catch (SocketException ex) { ///reconnecting }
}
Thank you!
Solved
In OnDataReceived callback, I check amount of incoming data, so I do:
if (iRx == 0)
throw new SocketException(Convert.ToInt16(SocketError.HostDown));
TCP receiver can never get the exact status of the remote connection. Killing the process will send FIN (receive is zero) or RST(get exception) depending on the TCP/IP stack implementation. There are other condition where the application are completely unaware of the connection breakage. Suppose if the remote system is forcefully reset or the cable wire is unplugged or the IP address is changed, there is no way you can get to know the connection broken until you send some data. If your application need to know the status of the connection, it can send some dummy data every 1 minute to make sure the connection alive.

Working with SerialPortĀ“s DataReceived Event

Im trying to read the output of a device on a COM port on my PC.
Im wrote a C# program to do so.
Using PuTTY, I can see the output Im expecting from my device.
The problem is that the function SerialPort.ReadExisting(); in my DataReceived function gives my a completely different string.
What is the proper way to read from a COM port using SerialPort?
Also, the strings I get from SerialPort.ReadExisting(); are fragments of the string I sent to the device.
Below is the code that initializes the SerialPort.
SerialPort port;
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = port.ReadExisting();
}
void init_serialport(object sender, EventArgs e)
{
if (port != null)
{
port.Close();
}
port = new SerialPort( /* ... */ );
port.BaudRate = 9600;
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = StopBits.One;
port.Handshake = Handshake.RequestToSend;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
try
{
port.Open();
}
catch (Exception ex)
{
// ...
}
}
the strings I get from SerialPort.ReadExisting(); are fragments of the string I sent to the device.
I'd have a look at SerialPort.ReceivedBytesThreshold.
"Gets or sets the number of bytes in the internal input buffer before a DataReceived event occurs."
I would first take a look at the Read method of the port object, look at the raw bytes and verify that they match your expectations, which would then narrow down the problem to the encoding on the conversion to string.
More information on this is provided here.
You received fragments because SerialPort.Existing() executes and completes in less time then it takes for your sending device to send the entire string.
You need to repeat the call continuously or until you received the end of string character if the string has one.

Categories