c# Handling handshake RTS/CTS - c#

So just a bit of context I have 2 devices that communicate with each other by rs232 with RTS/CTS and i need to replace one of the devices with my own device and software.
I am trying to achieve this by using the System.IO.Ports.SerialPort library that from what i could gather online this library handles the handshaking by itself if we set the RtsEnable property to "true" and the Handshake property to "RequestToSend" but I am facing some issues receiving data from the device.
When testing my software i am not being able to receive anything from the device but if I change the wiring to simply work as a sniffer between the two original devices I can receive the data properly. From what I can gather it must be something I am doing wrong to handle the handshaking.
Here is the code i am trying:
stationPort = new SerialPort(stationPortNumber, baudRate, parity, dataBits, stopBits);
stationPort.RtsEnable = true;
stationPort.Handshake = Handshake.RequestToSend;
stationPort.DataReceived += StationPort_DataReceived;
stationPort.Open();
private static void StationPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] bytes = new byte[20];
stationPort.Read(bytes, 0, stationPort.BytesToRead);
string hexConvert = BitConverter.ToString(bytes);
Console.WriteLine("Station OUT >>> " + hexConvert);
}
I also double checked the wiring to make sure it was properly connected and also changed the converter because sometimes these are not wired properly so I chose a MOXA UPort 1150 which is more reliable.
With that being said, my question is what am I doing wrong with my implementation?
Am I supposed to do more to guarantee the handshaking?

Possibly, The equipment you are using may be half-duplex.
In that case, in order to communicate with the SerialPort class of C#, it is necessary to set Handshake to None and control the ON/OFF of the RTS signal by the application program itself.
The SerialPort class API does not have that function.
Handshake Enum
When using the communication function of Win32API, communication may be possible by setting the fRtsControl flag to RTS_CONTROL_TOGGLE in DCB.
DCB structure
RTS_CONTROL_TOGGLE 0x03
Specifies that the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low.
In any case, you will need to check the communication specifications of the device.
However, even if you are not sure, it may be better to try the above control a little in C#.
You may also want to try #baddack's comment.
As noted, the fact that the DTR signal (DSR for the other party) is ON may be the basis for determining that communication is possible.
In connection with that, are the signal lines cross-connected?
Are TxD/RxD, RTS/CTS, DTR/DSR cross-connected to each other?
Also check what you need to do with these specifications for your equipment.

Related

C# SerialPort problems with two different versions of a device

I am trying to read data from a device connected via USB.
For creating the trigger the code looks like:
private SerialPort realTimePort;
realTimePort = new SerialPort();
realTimePort.BaudRate = 9600;
realTimePort.PortName = "COM4";
realTimePort.ReadTimeout = 5000;
realTimePort.ReadBufferSize = 32768;
realTimePort.ReceivedBytesThreshold = 1;
realTimePort.BaudRate = 9600;
realTimePort.ReadBufferSize = 4096;
realTimePort.ParityReplace = 63;
realTimePort.Parity = Parity.None;
realTimePort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(realTimePort_DataReceived);
realTimePort.Open();
To read the data, which was sent, the code looks like:
public void realTimePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Do something with the data
}
With one version of the device everything works fine and the trigger starts, when data was sent, but with a newer software-version of the device realTimePort_DataReceived is never triggered.
At first i thought, that the problem might be, that the device never sends data, but then i tried to read the data with "Tera Term" and there i can see exactly, what i am expecting. I also compared the data with "Tera Term", which was sent of the devices with the different software-versions, but it is exactly the same string.
Do you have any ideas, why the event is triggered with the older software-version and not with the newer one?
An employee of the manufacturer of the device already gave me the specification of the SerialPort, because i had this problem, but it didn't help me.
It is hard to reproduce the issue as i am not aware what type of device you are using and what type of data is sends here are some tips you can evaluate a quick check list to ensure the correct data receiving.
1. Play with RTS or DTR port flags for new version device
Basically some new versions of hardware uses flags of SerialPort e.g. DTR (Data Terminal Ready) indicates that your code is ready to receive, and RTS (Request to Send) a request to device to actually send data. for older hardware types it was not mandatory to use these flags although in modern devices its still not but just a standard practice so you should experiment & try enabling these by your code e.g.
realTimePort.RtsEnable = true; //enable this mode
realTimePort.DtrEnable = true; //and also this one
2. Try to read device error stream
It is possible that your new version hardware is sendind data over error stream, the tool you was using utilizes both streams for data read so you can subscrive to error event like.
realTimePort.ErrorReceived += new SerialErrorReceivedEventHandler(sPort_ErrorReceived);
private static void sPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
//process your error, it will give you further hint about why part of your question.
}

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.

Virtual ComPort stops calling DataReceived after some time

I am currently stuck at a problem which I cant find any answer for. I am controlling a device that is attached to the computer via a Virtual-ComPort (USB). For this communication I use the SerialPort class in System.IO.Ports.
This is how I initialize the port:
SerialPort SerialPort = new SerialPort();
SerialPort.BaudRate = BaudRate;
SerialPort.DataBits = 8;
SerialPort.Parity = Parity.None;
SerialPort.PortName = SerialPortName;
SerialPort.StopBits = StopBits.One;
SerialPort.ReceivedBytesThreshold = 9;
SerialPort.WriteTimeout = 1500;
SerialPort.ReadTimeout = 1500;
SerialPort.DataReceived += dataReceivedHandler;
SerialPort.Open();
I set the received Threshold to 9 because I know that all the data I can receive is 9 bytes long and I want to minimize the number of callbacks. Can this cause any harm?
This does work really well in 99,99% of all cases. But after a random amount of time/commands (typically after several thousand operations) I don't get a callback when data is send to the PC. The DataReceived handler is just not called in these cases. I checked this by adding a Debug.WriteLine("Callback received!") at the very beginning of the dataReceivedHandler.
I am sure the data is send by the device I like to control. What is the cause of this seemingly "random" behavior and how can I fix it?
I am grateful for any suggestions.
Best
Nano
Using ReceivedBytesThreshold is a convenience, but it only works when the Sun is shining and you've got a stiff breeze in your back. You are skipping the things you need to do to ensure it can work:
You need to implement flow control so there is no scenario where the device can overflow the input buffer. Even though modern machines are plenty fast enough to support a high baudrate, they cannot guarantee that they are always fast enough. Losing the processor for many hundreds of milliseconds is very possible. You should always set the Handshake property so this can never happen. The proper value depends on what the device supports, always start with Handshake.RequestToSend if you don't know.
Never checking for errors is pretty much a guarantee that you cannot diagnose a mishap like this. Implementing the ErrorReceived event handler is not optional. It is the only way you can diagnose mishaps, like a UART or device driver input buffer overflow, the kind that cause data loss and cause the kind of trouble you are trying to troubleshoot.
ReceivedBytesThreshold always gives you a synchronization problem. You have to make sure that you start listening at just the right time, in between two chunks of 9 bytes. That is of course pretty hard to do if you have no control over the startup order of your program vs the device, you rarely do. A decent protocol always gives you a way to synchronize, typically with a dedicated byte value that indicates the start of a message. Once you have that, the value of the ReceivedBytesThreshold completely disappears.
Start with the ErrorReceived event so you know when things go wrong. Shopping for another USB emulator also ought to be high on your list of possible workarounds, drivers for them are generally pretty cruddy.

SerialPort.DataReceived with USB TO COM cable act different then physical com

My C# desktop class library communicates with COM serial port.
The com is not real com, it is a USB to COM cable connected to USB to COM on another computer, the other computer uses a simulator to send data.
This solution works fine and then port opens successfully:
serialPort.Open();
if (serialPort.IsOpen)
{
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
var length = serialPort.BytesToRead;
byte[] buffer = new byte[length];
serialPort.Read(buffer, 0, length);
for (int i = 0; i < buffer.Length; i++)
{
System.IO.File.AppendAllText(#"c:\TestLogging.txt", string.Format("[Time = {0}] Data was received from serial port !", DateTime.Now)); }
}
The simulator send data all the time, and I receive the data in my class, BUT i dont receive it all the time, i see printing of 1 line every 30 seconds - although it suppose to print all the time!
What is weird - If i place break point in the line var length = .. then i see a the prints for the time i was halting on the break.. the data transferred seems to be "cached" and when i hit "Play" I receive the data but only for the time i was pausing the process.
I think you're too late registering the DataReceived eventhandler there. You should register to it before you open the port:
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
serialPort.Open();
if (serialPort.IsOpen)
{
}
Try connecting your machines using HyperTerminal and check if the communication works. If it does, then it's your application's fault (double-check serialport settings). Otherwise it's probably the cable or the port itself.
Are you sure you're not getting any faulty data? Have you subscribed to SerialPort.ErrorReceived event handler? If you catch some SerialError.Frame errors there, then you probably have a faulty cable or the port is broken, or there are some conditions that are jamming the comunication (not vary likely but it can happen, for example if there is some strong source of power near by, for example an inverter).
OK, what is the problem ?
I am using USB to COM cable, and not true COM port.
The behavior of data receiving event from SerialPort is different.
I listen and catch the data event, but instead of getting array of bytes (as in real COM) - I receive every time a single byte (array in size of 1)..
Meaning: On DataReceived event when working with USB to COM port: i get this: 1-1-1-1-1-1 each DataReceived event give me 1 byte.
Real physical COM .DataReceived event give me: 5-30-42 etc.. Array of bytes
So my solution when working on USB to COM ports (some might call it "virtual COM port") I need to check if serialPort.BytesToRead is bigger then X, then i actually do
if (serialPort.BytesToRead > 2) //I dont want to get it 1-1-1.. want to get it atleast 2-2-2-2
serialPort.Read(buffer, 0, length);
Since serialPort.BytesToRead will tell me how many bytes are in current chunk, and Read. in my terms will get the buffer and clean it.

In C# how could I listen to a COM (Serial) Port that is already open?

I am using a program that talks to my COMM port, but I have made another program that I want to "sniff" the comm port messages and perform it's own actions against those messages in addition. Is this possible in .NET c#?
There are third party libraries/tools/products that expose the traffic f you are interested.
Here is one I used for serial port emulation - but I think it provides something you can use:
http://com0com.sourceforge.net/
If you have control over the first program that talks to you COMM port, why not change the program to pass data received from the port to the 2nd program of yours via remoting or any other type of IPC. Better still if you can write a proxy program that connected to the COMM port, and have 2 of the other program talk to this proxy to get the communication done.
Another idea is, if you need to sniff only incoming data, you can get a Y-cable (splitter) and connect to 2 COMM port, each program connects to each COMM port. But you need to make sure the 2nd program is not trying to transmit. In some cases you might need a splitter which only connects the RX pin for the 2nd output. Let me know if you need the diagram.
If you don't have 2 COMM, you can easily get a USB-Serial Converter for less than USD10.
It is possible to sniff traffic from the serial port
However there doesnt seem to be a "COMPortSniffer" Control
A valid technique used by sysinternals is presented there
It seems to rely on Win32 programming however, I dont think such a thing is possible directly with C#
the code project (http://www.codeproject.com/Articles/75770/Basic-serial-port-listening-application) that has a great tutorial on this.
It shows how to read data coming in from a serial port, and from that you should be able to read the data.
A short snippet:
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
NewSerialDataRecieved(this, new SerialDataEventArgs(data));
}

Categories

Resources