C# COM port communication problem - c#

I have a C# code which communicates with three different COM ports. The COM ports are actually three serial port to USB converters.
The code each time switches 'off' and 'on' the devices to which it is communicating, then initializes the three com ports, tries to send and read data and then closes the com port. This keeps continuing for a pre-defined number of loops.
My problem is that after about 8 or 9 iterations, the COM port communication stops working. Sometime it throws an error saying the port is closed, sometime it does not throw any exception but it is actually not reading or writing anything from the com port. Some point it was only writing but not reading back the data.
What might be the reason and any tips to debug this problem?
EDIT:
The port abruptly closes or stops working even in the middle of the program as shown below:
SerialPort.Write("ss");
SerialPort.Read("ss"); // FAILS!!
Some part of the code I am using
public string Read(string readCommand)
{
string str = "";
_port.WriteLine("\r");
_port.WriteLine(readCommand + "\r");
Thread.Sleep(0x3e8);
str = _port.ReadExisting();
return str;
}
public void Write(string command)
{
_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
}
public void Initialize()
{
if (_port == null)
{
_port = new SerialPort(this.PortName.ToString(), this.BaudRate, this.Parity, this.DataBits, this.StopBits);
_port.Handshake = this.Handshake;
}
try
{
if (!_port.IsOpen)
{
_port.Open();
if (Read("") == string.Empty)
{
throw new IOException("Device not connected or powered on");
}
}
}
catch (Exception)
{
this.Close();
}
}
Thanks...

_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
That's evil code and bound to throw sooner or later. Windows cannot provide a service guarantee like that. Or for that matter the device itself, especially when you power it on and off. Use SerialPort.ReadTimeout, set it to at least 2 seconds. And make a blocking call, like ReadLine().
catch (Exception)
{
this.Close();
}
That's tops the previous snippet. You have no idea what's going wrong when that runs. And your code will try to use a closed port. Just delete the statements, it does nothing but harm.
Do not close the ports until your program ends. SerialPort uses a background thread to watch for events on the port, that thread needs to shutdown after the Close() call before you can open the port again. How long it takes to shutdown is unpredictable, it could be seconds worst case. There's no point in closing the port, it isn't going to be useful to anything else.

You need to use SetCommTimeouts (not sure what the .NET wrapper is, I gave up on the .NET serial classes long ago and call the Win32 API directly) to force the USB/serial converter to send the data back to your program.
By default it may try to collect a block equal in size to a USB transfer block, for efficiency.

Its tough to tell exactly what the problem might be without see some of the code. My guess would be that you are not waiting long enough for the COM port to close after reopening it. Note from the SerialPort.Close page, that:
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.
Can you just open the COM ports and leave them open until you are done? For example from this post:
using (SerialPort serialPort = new SerialPort("COM1", 9600))
{
serialPort.Open();
while (true)
{
Thread.Sleep(1000);
// serialPort.Write();
Thread.Sleep(1000);
// serialPort.Read();
// break at some point to end
}
serialPort.Close();
}

Related

SerialPort.ReadTo getting data when doing Step Over, but not on normal execution

I'm building a WPF app that has to communicate through a Serial Port. When I send some data to the serial port it is supposed to reply with some data. For example, I send a PIG\r\n and it reply with ACK\r\n. During a normal execution of the code, I send a command to get me some data from a third device connect to the second (which is attached to my serial port) I don't get any reply, only a timeout exception. However, when I try to debug the code (using step over) it works as expected.
I have try to do Step over short than the Timeout (30s) and still gets the problem.
I have create a console application to test my code and it works fine on it. So, I'm assume there are some problems on WPF, But I don't know where to look.
My Read function
public ComandoFactory Ler()
{
try
{
string Mensagem = sp.ReadTo("\r\n");
var comando = new ComandoFactory(Mensagem.Substring(0,3), Mensagem.Substring(3));
return comando;
}
catch (TimeoutException e)
{
return new ComandoFactory("ERR", "TIMEOUT");
}
catch(ArgumentOutOfRangeException e)
{
return new ComandoFactory("ERR", "ARGUMENT");
}
}
ReadTo should return something, instead of giving a Timeout.
Any help is welcome. Thanks
I fixed this by creating a small wait between the Write and read operation. 100 ms did the trick and the code is working now. However, I know this is not the best solution. #Baddack idea of using DataReceived is probably better and I'll try when I can.

C# "using" SerialPort transmit with data loss

I'm new to this forum, and I have a question that has been bothering me for a while.
My setup is a serial enabled character display connected to my pc with a usb/uart converter. I'm transmitting bytes to the display via the serialPort class in a separate write buffer thread in a C++ style:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
s.Write(b,0,b.Length);
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
Assuming the serial port is already opened, this works perfectly and transmits all the data to the display. There are though no exception handling at all in this snippet. Therefore I was looking into implementing a typical C# feature, the 'using' statement and only opening the port when needed, like so:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
using(s){ //using the serialPort
s.Open();
s.Write(b,0,b.Length);
s.Close();
}
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
The problem with this function is, that it only transmits a random amount of the data, typically about one third of the byte-array of 80 bytes. I have tried different priority settings of the thread, but nothing changes.
Am I missing something important, or do I simply close the port too fast after a transmit request?
I hope you can help me. Thanks :)
No, that was a Really Bad Idea. The things that go wrong, roughly in the order you'll encounter them:
the serial port driver discards any bytes left in the transmit buffer that were not yet transmitted when you close the port. Which is what you are seeing now.
the MSDN article for SerialPort.Close() warns that you must "wait a while" before opening the port again. There's an internal worker thread that needs to shut down. The amount of time you have to wait is not specified and is variable, depending on machine load.
closing a port allows another program to grab the port and open it. Serial ports cannot be shared, your program will fail when you try to open it again.
Serial ports were simply not designed to be opened and closed on-the-fly. Only open it at the start of your program, close it when it ends. Not calling Close() at all is quite acceptable and avoids a deadlock scenario.
I think you're missing the point of the using block. A typical using block will look like this:
using (var resource = new SomeResource())
{
resource.DoSomething();
}
The opening happens at the very beginning. Typically as part of the constructor. But sometimes on the first line of the using block.
But the big red flag I see is that the closing happens automatically. You don't need the .Close() call.
If the successful operation of your serial device is dependent on the calls to Thread.Sleep then perhaps the thread is being interrupted at some point, sufficient to make the data transmission out of sync with the device. There would most likely be ways to solve this but the first thing I would do is try to use the .NET SerialPort class instead. The Write method is very similar to what you want to do, and there are C++ code examples in those articles.

C# serial port problem - too simple to fail, but

Ok, this should be dirt simple. I'm trying to read charactes from a serial device. It's such that if I send a space character, it echos back a string of numbers and EOL. That's it.
I'm using Unity 3.3 (.Net 2.0 support), and the 'serial port' is a Prolific serial-to-USB adaptor. BTW: Using Hyperterminal, it all works perfectly, so I know it's not driver nor hardware.
I can open the port ok. It seems I can send my space with port.Write(" "); But if I even TRY to call ReadChar, ReadByte, or ReadLine (like polling), it freezes up until I unplug the USB, and my console output shows nothing (exceptions were caught).
So instead I set up a DataReceviedHandler, but it's never called.
I've read some posts where people have done just this type of thing with Arduinos etc. (this is not an Arduino but hey), using nothing more than ReadLine. Their code does not work for me (and no answers thus far from those authors).
So, any tips? Do I need to use a different thread? If you know any Unity (Mono) coding, any tips along those lines greatly appreciated.
This code a mashup from http://plikker.com/?p=163 and http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx#Y537
using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
public class SerialTest : MonoBehaviour {
SerialPort stream;
void Start () {
try {
stream = new SerialPort("COM3", 9600);
stream.Parity = Parity.None;
stream.StopBits = StopBits.One;
stream.DataBits = 8;
stream.Handshake = Handshake.None;
stream.DataReceived += new SerialDataReceivedEventHandler(DataReceviedHandler);
stream.Open();
Debug.Log("opened ok"); // it DOES open ok!
} catch (Exception e){
Debug.Log("Error opening port "+e.ToString()); // I never see this message
}
}
void Update () { // called about 60 times/second
try {
// Read serialinput from COM3
// if this next line is here, it will hang, I don't even see the startup message
Debug.Log(stream.ReadLine());
// Note: I've also tried ReadByte and ReadChar and the same problem, it hangs
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
private static void DataReceviedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender; // It never gets here!
string indata = sp.ReadExisting();
Debug.Log("Data Received:");
Debug.Log(indata);
}
void OnGUI() // simple GUI
{
// Create a button that, when pressed, sends the 'ping'
if (GUI.Button (new Rect(10,10,100,20), "Send"))
stream.Write(" ");
}
}
Events are not implemented in Mono SerialPort class, so you won't get any notifications, you have to perform (blocking) read explicitly. Other possible problem - I'm not sure how Unity Behaviours work, are you certain all methods accessing the SerialPort are invoked on the same thread? And you are not disposing you port object, this will also cause problems.
Make sure that you are opening the right port, using correct settings. Here is an example of how you could configure it:
serial = new SerialPort();
serial.ReadBufferSize = 8192;
serial.WriteBufferSize = 128;
serial.PortName = "COM1";
serial.BaudRate = 115200;
serial.Parity = Parity.None;
serial.StopBits = StopBits.One;
// attach handlers
// (appears to be broken in some Mono versions?)
serial.DataReceived += SerialPort_DataReceived;
serial.Disposed += SerialPort_Disposed;
serial.Open();
I recommend the open source RealTerm terminal, it has a rich set of features and can help you debug. Try writing a byte manually using such software, and if it works, then the problem is in your program. Otherwise it might be a driver problem (but more likely it isn't).
[Edit]
Calling SerialPort.ReadLine is actually supposed to block the thread until SerialPort.NewLine is received. Also ReadChar and ReadByte will hang until at least one byte is received. You need to make sure that you are actually receiving characters from the other side, and you won't be receiving them if your app is stuck and cannot send the space.
Since I never used Unity, I am not sure how Update is called, but I am presuming it's fired on a foreground thread in regular intervals (otherwise your app wouldn't freeze).
The example that you linked (Arduino and Unity example) shows that Arduino is sending the data continuously, and that is why their Update method is constantly receiving data (no space character needs to be sent towards the device). If they unplug the device, their app will hang just as well.
Well, maybe not, because in .NET 1.1, default value for ReadTimeout was not infinite, like it is in .NET 2.0.
So, what you can do is:
a. Set the ReadTimeout property to a reasonable value. Default in .NET 2.0 is InfiniteTimeout, which doesn't suit your needs. Cons: your update method will still hang for a while on each call, but not infinitely.
b. Someone said that events are not implemented in MONO SerialPort, so I guess using DataReceived only is not an option.
c. Move your sending logic to the Update method also, so that you don't read data at all, until it's time to read it:
private volatile bool _shouldCommunicate = false;
void Update ()
{
if (_shouldCommunicate) // this is a flag you set in "OnGui"
{
try {
stream.Write(" ");
Debug.Log(stream.ReadLine());
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
}
void OnGUI() // simple GUI
{
if (GUI.Button (new Rect(10,10,100,20), "Send"))
_shouldCommunicate = true;
}
Note that, if your device is not sending data, it will also block at stream.ReadLine(), so make sure your ReadTimeout is set to a reasonable value. You will also want to stop sending at some point, but I leave that to you.
d. Send the space in OnGui like you are doing now, but always check if there is data in your buffer before reading it:
void Update () { // called about 60 times/second
try {
// call our new method
Debug.Log(ReadLineNonBlocking());
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
private StringBuilder sb = new StringBuilder();
string ReadLineNonBlocking()
{
int len = stream.BytesToRead;
if (len == 0)
return "";
// read the buffer
byte[] buffer = new byte[len];
stream.Read(buffer, 0, len);
sb.Append(ASCIIEncoding.ASCII.GetString(buffer));
// got EOL?
if (sb.Length < 2 ||
sb[sb.Length-2] != '\r' ||
sb[sb.Length-1] != '\n')
return "";
// if we are here, we got both EOL chars
string entireLine = sb.ToString();
sb.Length = 0;
return entireLine;
}
Disclaimer: this is directly out of my head, untested, so there may be some syntax errors which I am sure you will handle.
Maybe your problem is the configuration of the serial port. It is important not only to check for BaudRate or StopBits. Also you should configure DTR, RTS, Handshake, everything. This is important cause maybe another program set some ugly values and the configuration must be explicitly set at every start or some settings of the old connection can run you into trouble.
Also maybe take a look into one of these tools:
com0com
Serial Port Monitor
They can help you to stub your serial interface or to take a deeper look into the connection. Also maybe try to talk to your serial device by using HyperTerminal or some similar tool that's proven to work.
Had similar problem with Mono, upgrading to 2.6.7 helped.
Do not mix data event and blocking read. What do you expect to happen if data arrives? That both the read method and the event should get the same received data?
You should also read about:
CTS: http://en.wikipedia.org/wiki/RS-232_RTS/CTS#RTS.2FCTS_handshaking
DTR: http://en.wikipedia.org/wiki/Data_Terminal_Ready
Small serial port tutorial describing all states: http://www.wcscnet.com/Tutorials/SerialComm/Page1.htm
The standard c# System.IO.Pots.SerialPort sucks big time. I suggest to give RJCP.DLL.SerialPortStream library a try. Synchronous read/write is super easy with this delightful library too, no need to jump through the loops with delegate and listeners.

RasConnectionNotification after computer resumes from sleep

I've got a project called DotRas on CodePlex that exposes a component called RasConnectionWatcher which uses the RasConnectionNotification Win32 API to receive notifications when connections on a machine change. One of my users recently brought to my attention that if the machine comes out of sleep mode, and attempts to redial the connection, the connection goes into a loop indicating the connection is already being dialed even though it isn't. This loop will not end until the application is restarted, even if done through a synchronous call which all values on the structs are unique for that specific call, and none of it is retained once the call completes.
I've done as much as I can to fix the problem, but I fear the problem is something I've done with the RasConnectionNotification API and using ThreadPool.RegisterWaitForSingleObject which might be blocking something else in Windows.
The below method is used to register 1 of the 4 change types the API supports, and the handle to associate with it to monitor. During runtime, the below method would be called 4 times during initialization to register all 4 change types.
private void Register(NativeMethods.RASCN changeType, RasHandle handle)
{
AutoResetEvent waitObject = new AutoResetEvent(false);
int ret = SafeNativeMethods.Instance.RegisterConnectionNotification(handle, waitObject.SafeWaitHandle, changeType);
if (ret == NativeMethods.SUCCESS)
{
RasConnectionWatcherStateObject stateObject = new RasConnectionWatcherStateObject(changeType);
stateObject.WaitObject = waitObject;
stateObject.WaitHandle = ThreadPool.RegisterWaitForSingleObject(waitObject, new WaitOrTimerCallback(this.ConnectionStateChanged), stateObject, Timeout.Infinite, false);
this._stateObjects.Add(stateObject);
}
}
The event passed into the API gets signaled when Windows detects a change in the connections on the machine. The callback used just takes the change type registered from the state object and then processes it to determine exactly what changed.
private void ConnectionStateChanged(object obj, bool timedOut)
{
lock (this.lockObject)
{
if (this.EnableRaisingEvents)
{
try
{
// Retrieve the active connections to compare against the last state that was checked.
ReadOnlyCollection<RasConnection> connections = RasConnection.GetActiveConnections();
RasConnection connection = null;
switch (((RasConnectionWatcherStateObject)obj).ChangeType)
{
case NativeMethods.RASCN.Disconnection:
connection = FindEntry(this._lastState, connections);
if (connection != null)
{
this.OnDisconnected(new RasConnectionEventArgs(connection));
}
if (this.Handle != null)
{
// The handle that was being monitored has been disconnected.
this.Handle = null;
}
this._lastState = connections;
break;
}
}
catch (Exception ex)
{
this.OnError(new System.IO.ErrorEventArgs(ex));
}
}
}
}
}
Everything works perfectly, other than when the machine comes out of sleep. Now the strange thing is when this happens, if a MessageBox is displayed (even for 1 ms and closed by using SendMessage) it will work. I can only imagine something I've done is blocking something else in Windows so that it can't continue processing while the event is being processed by the component.
I've stripped down a lot of the code here, the full source can be found at:
http://dotras.codeplex.com/SourceControl/changeset/view/68525#1344960
I've come for help from people much smarter than myself, I'm outside of my comfort zone trying to fix this problem, any assistance would be greatly appreciated!
Thanks! - Jeff
After a lot of effort, I tracked down the problem. Thankfully it wasn't a blocking issue in Windows.
For those curious, basically once the machine came out of sleep the developer was attempting to immediately dial a connection (via the Disconnected event). Since the network interfaces hadn't finished initializing, an error was returned and the connection handle was not being closed. Any attempts to close the connection would throw an error indicating the connection was already closed, even though it wasn't. Since the handle was left open, any subsequent attempts to dial the connection would cause an actual error.
I just had to make an adjustment in the HangUp code to hide the error thrown when a connection is closed that has already been closed.

Socket closing automatically

Is there a reason why a Socket should close by itself, after 2h? I am receiving data every second from this socket, and writing back some tiny "keep-alive" data every 30s.
Before sending, I check if socket is still connected using the following method:
public bool IsSocketReadyForWriting(Socket s)
{
try
{
if (!s.Connected)
{
Log.Info("Socket.Connected was false");
return false;
}
// following line will throw if socket disconnected
bool poll = s.Poll(2000, SelectMode.SelectWrite);
if (!poll)
{
try
{
// if poll is false, socket is closed
Log.Info("poll is false");
this.Close();
}
catch { }
return false;
}
Log.Debug("still connected");
return true;
}
catch (Exception ex)
{
Log.Error("Error while checking if socket connected", ex);
return false;
}
}
Everything works fine for about 2h, then suddenly Socket.Poll returns false, and the Socket gets closed.
Is there a setting which controls this, or am I doing something really wrong?
[Edit]
Forgot to mention: I control both server and client side of the link. These are both C# apps, one of them creates a listening socket, the other one opens a connection and sends data. They communicate without problems for 2h (no memory leaks and stuff), then the socket closes.
When this happens, I can reconnect the socket again easily, but I am just wandering if anyone knows why could be the reason for this.
By default a TCP socket is writable when there's at least one byte of space available in the socket send buffer. To reverse that - the socket is not writable when there's enough unacknowledged data sitting in the "output queue".
That said, pull out wireshark or whatever Microsoft provides for packet sniffing and see what's going on on the wire. Are your heartbeat chunks getting ACK-ed? Does the receiver window stay open or does it go to zero? Or are you just getting explicit RST or a FIN from some intermediate switch?
One way to mitigate temporary clogged pipe is to increase the send buffer size, which is kind of tiny by default on Windows - 8192 iirc. See the setsockopt (.NET probably has a version of that) and the SO_SNDBUF option.
Could be the server that is closing the connection? Do you have control over it?

Categories