Serial Port Communication on the same Windows machine not working - c#

Excuse me, quick question:
I have this hardware setup:
Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4"
And I followed MSDN SerialPort Class and MSDN SerialPort.ReadLine() to build this routine:
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
SendSerialPort.Open();
ReceiveSerialPort.Open();
SendSerialPort.WriteLine("Test");
var message = ReceiveSerialPort.ReadLine(); // control stops here
SendSerialPort.Close();
ReceiveSerialPort.Close();
Console.WriteLine(message);
However, when I tend to ReadLine(), my control stops and just waits. I did not expect that.
I am expecting to receive the string Test and assign it to my var message. Could you please tell me what am I doing wrong here?
EDIT:
I tested my hardware using the Serial Port Utility Application and it worked just fine.

I've altered from the example you linked:
To actually have both ports running to read and write back and forth you will actually need to implement threading for reading and writing for both.
It can be a good idea to use a timer.
public static void Main()
{
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
Thread readThread = new Thread(Read);
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
SendSerialPort.Open();
ReceiveSerialPort.Open();
bool _continue = true;
readThread.Start();
Console.Write("Name: ");
name = Console.ReadLine();
Console.WriteLine("Type QUIT to exit");
while (_continue)
{
message = Console.ReadLine();
if (stringComparer.Equals("quit", message))
_continue = false;
else
SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message));
}
readThread.Join();
SendSerialPort.Close();
}
public static void Read()
{
while (_continue)
{
try
{
string message = ReceiveSerialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
Usually there will be a beginning and end value within the written data to tell the other port that the message is finished and also for the ports to validate that they are reading data they should be, usually with commands of what to do with that data. (out of scope for this question).
Also lacking and important is the intialisation of your ports.
I prefer to use the default constructor (preference only)
SerialPort Constructor ()
And then set any values like so:
_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
All the constructors will give these values:
This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1.
Even the handshake has a default value. If you look at the source code.
private const Handshake defaultHandshake = Handshake.None;

The problem with your code is in this line
var message = ReceiveSerialPort.ReadLine();
You block your code to wait for a line, if the line never arrives it will remain here forever or the value set to ReadTimeout
So why does the line never arrive?
The problem can be an error in WriteLine("Test");, you should handle errors, or it can be that your in are blocking your code ReadLine() before the WriteLine("Test") manage to come through, you could insert a Thread.Sleep(100) between, but this is not really improving the code.
Note: Your code will also work as is sometimes, depending on these race conditions.
This synchronized / blocking reading from serial ports seems simple in code just one line; but it creates a lot of negative side effects in your communication protocol's.
A much better solution (considering that you like to Read / Write data from a microcontroller) is to either use a thread as Yvette suggested or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) which I would prefer.
The asynchronously reading will throw an event when something is incoming on the serial port. The basic idea of this programming strategy is to not do step programming but expecting what ever result and then handle it correctly.
In communications protocol with asynchronously reading the AutoResetEvent is very useful, hence you send something, then you start the AutoResetEvent, if asynchronously the expected result is arriving you will set this event and your code can continue, if it does not arrive the AutoResetEvent will timeout and you can handle this.

It cannot block when there is data available. What you sent either got stuck in the transmit buffer, got lost due to a wiring mistake, triggered an error or was ignored. If it works with another program then a wiring mistake can't be the problem.
Do keep in mind that just setting the Baudrate is not enough, you must also use set the DataBits, Parity and Stopbits properties to match the device settings. A mismatch can trigger an error, the kind you can only see when you write an event handler for the ErrorReceived event. Never skip that event, confounding problems can occur if you never check.
And above all the Handshake property must be set correctly. The proper value depends on how the ports are wired together, it is too common to not connect them. Start by setting it to Handshake.None so a wrong state for the DSR and CTS signals can't block reception and a wrong state for the DTR and RTS signals can't block transmission. Beware that it is common for another program to enable hardware handshaking, a mismatch is guaranteed to cause communications to stall.
If you use synchronous reads instead of the DataReceived event then you should in general deal with the possibility that a device is not responding. Either because it is powered off, not connected at all or malfunctioning. Use the ReadTimeout property for that so your program cannot hang. Aim high, 10000 milliseconds is a reasonable choice.
Beware the randomness of this problem, putzing around with another program can easily get the port configured correctly and now it will suddenly work. And beware that starting a thread accomplishes nothing, it will now be that thread that gets stuck and the Join() call will deadlock.

Related

Replicate PuTTY's raw connection with sockets

I am working with a heat cell with which i can only communicate through Ethernet. When trying to connect to it using sockets, I am stuck on waiting for the Receive() method to end.
I've checked the connection using PuTTY in raw mode and it worked just fine, I was able to send and receive messages.
This led me to believe that I needed to use some kind of raw communication as well, hence why I tried to use SharpPCap and the like. Using this, I am able to read from the cell (although I am faced with a few issues that aren't related to this post).
However, since I'm not very experienced with networking, I was wondering if there was a way to obtain the same results as when I used PuTTY's raw mode but using only Sockets ?
I've come accross this question that was left unanswered, apart from the fact that the author was advised not to use SocketType.Raw.
Below is the example from MSDN documentation that I adapted for my tests. It is supposed to send a request and then listen for the answer.
static void Main(string[] args)
{
System.Net.IPAddress host = System.Net.IPAddress.Parse("10.0.0.3");
int port = 2049;
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(host, port);
if (socket.Connected)
{
string request = "99997¶1¶1\\r";
var byteSent = Encoding.Default.GetBytes(request);
var byteReceived = new byte[256];
socket.Send(byteSent, byteSent.Length, 0);
int bytes = 0;
do
{
bytes = socket.Receive(byteReceived, byteReceived.Length, 0); // this is the line I'm being stuck on
} while (bytes > 0);
Console.WriteLine($"Result : {Encoding.Default.GetString(byteReceived)}");
Console.ReadLine();
}
else
{
Console.WriteLine("Connection Failed");
Console.ReadLine();
}
}
UPDATE
I used WireShark to take a look at what was being sent from my application. Turns out the 'CR' and 'LF' werent sent correctly. But correcting this didn't solve my problem.
I can see the server's answer to my request on WireShark, but still I can't read anything using socket.Receive(). Could it be possible that the server is faster to answer than my machine is to start listening ? I tried setting up the socket.ReceiveTimeout property and put my send/receive instructions in a loop, but still nothing returning from the Receive() statement.
The socket is in blocking mode by default (cf Socket.Blocking). That mean that, for your case, blocking until 256 byte has been read (Without timeout by default Socket.ReceiveTimeout).
You may want to set the Blocking mode to false, or set a Receive timeout in order to not block indefinitly.
Alternatively, you may want also to use async method to avoid blocking the main thread.

How to Properly Read from a SerialPort in .NET

I'm embarrassed to have to ask such a question, but I'm having a rough time figuring out how to reliably read data over a serial port with the .NET SerialPort class.
My first approach:
static void Main(string[] args)
{
_port = new SerialPort
{
PortName = portName,
BaudRate = 57600,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
RtsEnable = true,
DtrEnable = false,
WriteBufferSize = 2048,
ReadBufferSize = 2048,
ReceivedBytesThreshold = 1,
ReadTimeout = 5000,
};
_port.DataReceived += _port_DataReceived;
_port.Open();
// whatever
}
private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var buf = new byte[_port.BytesToRead];
var bytesRead = _port.Read(buf, 0, buf.Length);
_port.DiscardInBuffer();
for (int i = 0; i < bytesRead; ++i)
{
// read each byte, look for start/end values,
// signal complete packet event if/when end is found
}
}
So this has an obvious problem; I am calling DiscardInBuffer, so any data which came in after the event was fired is discarded, i.e., I'm dropping data.
Now, the documentation for SerialPort.Read() does not even state if it advances the current position of the stream (really?), but I have found other sources which claim that it does (which makes sense). However, if I do not call DiscardInBuffer I eventually get an RXOver error, i.e., I'm taking too long to process each message and the buffer is overflowing.
So... I'm really not a fan of this interface. If I have to process each buffer on a separate thread I'll do that, but that comes with its own set of problems, and I'm hoping that I am missing something as I don't have much experience with this interface.
Jason makes some good points about reducing UI access from the worker thread, but an even better option is to not receive the data on a worker thread in the first place.
Use port.BaseStream.ReadAsync to get your data, event-driven, on the thread where you want it. I've written more about this approach at http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport
To correctly handle data from a serial port you need to do a couple of things.
First, don't handle the data in your receive event. Copy the data somewhere else and do any processing on another thread. (This is true of most events - it is a bad idea to do any time-consuming processing in an event handler as it delays the caller and can introduce problems. You also need to be careful as your event is raised on a different thread to your main application)
Secondly, you can't guarantee that you will receive exactly one packet, or a complete packet when you receive data - it may come to you in small fragments.
So the upshot of this is that you should create your own buffer (big enough to hold several packets), and when you receive data, append it to your buffer. Then in another thread you can process the buffer, looking to see if you can decode a packet from it and then consume that data. You may have to skip the end of a partial packet before you find the start of a valid one. If you don't have enough data to build a full packet, then you may need to wait for a bit until more data arrives.
You shouldn't call Discard on the port - just read the data and consume it. Each time you are called, there will be another fragment of data to process. It does not remember the data from previous calls - each time your event is called, it is given a small burst of data that has arrived since you were last called. Just use the data you've been given and return.
As a last suggestion: Don't change any settings for the port unless you specifically need to for it to operate properly. So you must set the baud rate, data/stop bits and parity, but avoid trying to change properties like the Rts/Dtr, buffer sizes and read thresholds unless you have a good reason to think you know better than the author of the serial port. Most serial devices work in an industry standard manner these days, and changing these low-level options is very likely to cause trouble unless you're talking to some unusual equipment and you intimately know the hardware.
In particular setting the ReceivedBytesThreshold to 1 is probably what is causing the failure you've mentioned, because you are asking the serial port to call your event handler with only one byte at a time, 57,600 times per second - giving your event handler only 0.017 milliseconds to process each byte before you'll start to get re-entrant calls.
DiscardInBuffer is typically only used immediately after opening a serial port. It is not required for standard serial port communication so you should not have it in your dataReceived handler.

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

C# waiting for the data on serial port

i am trying to get data from fingerprint scanner through c# application, but before the fingerprint can send, a my whole code executes.
I tried using delay function and System.Threading.Thread.Sleep(1000), so it can get data before the next step executes, but it all seems futile.
Could any one please provide any other option?
I am using "SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)" to get data.
This code works perfectly for me:
port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
port.Open();
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.DataReceived += OnScan;
void OnScan(object sender, SerialDataReceivedEventArgs args)
{
SerialPort port = sender as SerialPort;
string line = port.ReadExisting();
// etc
}
Unfortunately waiting for a serial port data in C# is tricky, there is nothing like poll().
There is SerialPort.DataReceived which takes functions to be called on incoming data. So you assign there a function to trigger an arbitrary event. Your another function — the one to actually wait — should wait for this event.
Below is a simple example, it is commented, but in short: the TestFunc initializes and opens a serial port (in particular assigns the DataReceived). The Proxy() is a function that will be called every time a data arrived, it triggers an event. And WaitForAData() indeed waits for the event that will be triggered by Proxy() when a data appears. Note the lock(){}s, without them surrounding Monitor's functions it won't work properly.
It's just an example, you would probably want to remake WaitForAData() function to trigger an exception in case of timeout. And to add a boolean variable in case if the Proxy() was triggered before you began waiting, then serial port already have data. But I tested it (cause I need such a function now ☺), and it works.
namespace MyNamespace
{
class MySerial
{
///A condition variable that signals when serial has a data
private System.Object SerialIncoming;
public MySerial()
{
SerialIncoming = new Object();
}
/**
* A proxy function that will be called every time a data arrived
*/
private void Proxy(Object unused1, SerialDataReceivedEventArgs unused2)
{
Console.WriteLine("Data arrived!");
lock (SerialIncoming)
{
Monitor.Pulse(SerialIncoming);
}
}
/**
* Waits for a data for the time interval Timeout
* \param Timeout a timeout in milliseconds to wait for a data
* \returns true in if a data did arrived, and false else
*/
public bool WaitForAData(int Timeout)
{
lock (SerialIncoming)//waits N seconds for a condition variable
{
if (!Monitor.Wait(SerialIncoming, Timeout))
{//if timeout
Console.WriteLine("Time out");
return false;
}
return true;
}
}
/* Just a test function: opens a serial with speed, and waits
* for a data for the «Timeout» milliseconds.
*/
public void TestFunc(string serial, int speed, int Timeout)
{
SerialPort ser = new SerialPort(serial);
ser.BaudRate = speed;
ser.DataReceived += Proxy;
ser.Open();
if (WaitForAData(Timeout))
Console.WriteLine("Okay in TestFunc");
else
Console.WriteLine("Time out in TestFunc");
}
}
}
UPDATE: the problem wasted ½ of my day, so I hope I will save someone's time: the code above won't work in mono (but works in MS implementation) because serial port events are not supported as of writing these words.
If this is a Console application, you can use things like Console.ReadLine() etc. after calling the appropriate function of the COM Port component to start listening asynchronously. If this is a WinForms application. The message loop will of course keep showing your current form. In that case you can call asynchronous listening function in the Form_Load event or behind a button click.
The key point here is that you should call the asynchronous version of the listener function. There is no need to use delays or timers in that case.
Why not make a global marker (bool), that marks if you received anything and make a while(!marker) {} loop and you change the marker in the SerialPort_datareceived subrutine?
The thread.sleep might make you miss the SerialPort data sending?
The serial port is working in a separate thread. Therefore the serialPort_DataReceived event is fired from this thread.
So if your program only starts the serial port and then your main exits, you never receive the event. This is true if you have a console application.
When using a forms application, it keeps the form and the main thread alive until the user closes it.

SerialPort ReadLine() after Thread.Sleep() goes crazy

I've been fighting with this issue for a day and I can't find answer for it.
I am trying to read data from GPS device trough COM port in Compact Framework C#. I am using SerialPort class (actually my own ComPort class boxing SerialPort, but it adds only two fields I need, nothing special).
Anyway, I am running while loop in a separate thread which reads line from the port, analyze NMEA data, print them, catch all exceptions and then I Sleep(200) the thread, because I need CPU for other threads... Without Sleep it works fine, but uses 100% CPU.. When I don't use Sleep after few minutes the output from COM port looks like this:
GPGSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
GSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
A,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,18,12,271,24,24,05,020,24,14,04,326,25,11,03,023,*76
A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
as you can see the same message is read few times but cut.
I wonder what I'm doing wrong...
My port configuration:
port.ReadBufferSize = 4096;
port.BaudRate = 4800;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.NewLine = "\r\n";
port.ReadTimeout = 1000;
port.ReceivedBytesThreshold = 100000;
And my reading function:
private void processGps(){
while (!closing)
{
//reconnect if needed
try
{
string sentence = port.ReadLine();
//here print the sentence
//analyze the sentence (this takes some time 50-100ms)
}
catch (TimeoutException)
{
Thread.Sleep(0);
}
catch (IOException ioex)
{
//handling IO exception (some info on the screen)
}
Thread.Sleep(200);
}
}
There is some more stuff in this function like reconnection if the device is lost etc., but it is not called when the GPS is connected properly. I was trying
port.DiscardInBuffer();
after some blocks of code (in TimeoutException, after read.)
Did anyone had similar problem? I really dont know what I'm doing wrong.. The only way to get rig of it is removing the last Sleep.
For all those who have similar problem. The first issue was about overflowing the buffer. I had 4096 size of buffer and the data was just flowing trough it so I was reading corrupted sentences. Now I read all buffer at once and analyze it. First sentence is sometimes corrupted, but the rest is ok.
The second thing was the device issue. Tom Tom MkII sometimes loses connection with the device. I had to restart the GPS and find it again in Bt devices list.
Regards
There's nothing in your post to say how you are doing handshaking.
Normally you would use software (XON/XOFF) or hardware (e.g. RTS/CTS) handshaking so that the serial port will tell the transmitting to stop when it is unable to receive more data. The handshaking configuration must (of course) match the configuration of the transmitting device.
If you fail to configure handshaking correctly, you may get away with it as long as you are processing the data fast enough - but when you have a Sleep, data may be lost.

Categories

Resources