Detecting when SerialPort is ready for next command - c#

I have a piece of hardware that I'm connecting to using the .NET SerialPort class over RS232.
According to its documentation it doesn't support any type of flow control.
I can write queries and commands to the device, for the queries it'll respond immediately to a read, and if echo is on for the device and I have to do a read after writing a command then the command writes work fine too. The commands and responses are a maximum of 7 characters.
However if echo is off and I write 2 commands in quick succession the second one isn't carried out, unless I put in a Thread.Sleep(15) between the writes, presumably replicating the time it takes to do the ReadLine when echo is on.
I can't necessarily guarantee that echo will be on, and explicitly turning it on isn't really an option either, so I basically need to handle the behaviour as I find it.
The SerialPort is set up as follows:
SerialPort _serialPort = new SerialPort
{
PortName = "COM1",
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
ReadTimeout = 5000,
WriteTimeout = 5000,
NewLine = "\x0D"
};
And I'm using WriteLine and ReadLine to communicate with it.
Sleeping the thread feels like a hack, and I haven't found an alternative with all my googling.
So, have I missed something, is there some way I can check when the next command write to a serialport can be carried out or is Thread.Sleep pretty much my lot?

http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx
Set handshake property to RTSCTS and handle the PinChanged event when CTS becomes true?
Lines marked ‘Output’ in the table can be set by the serial port to a high or low state (True or > > False) and the ‘Input’ lines can be read as high or low. You can use the PinChanged event to be > > notified when one of the input pins changes. The Handshake property can be set to use RTS/CTS > > > (uses hardware control lines) or XON/XOFF (uses software) or both.
Control Line Name DB9 Pin SerialPort Property I/O
DTR Data Terminal Ready 4 DtrEnable Output
RTS Request to Send 7 RtsEnable Output
CTS Clear to Send 8 CtsHolding Input
DSR Data Set Ready 6 DsrHolding Input
CD (or DCD) Data Carrier Detect 1 CDHolding Input

Unfortunately due to the lack of support in my system for flow control Thread.Sleep seems to be the solution.
I've set up my code so that it checks to see if echo is on and then if it is it just uses the ReadLine, and if it's off then it uses a Thread.Sleep(15).
It feels nasty, but it works reliably, so I'm just having to go with that.

I was just having a similar problem. Using a low baud rate I was attempting to write commands to the port too fast (apparently the "write" command returns before the write is finished).
I solved this by modifying the "Serial Port Ready?" function I call before each command. I added a while loop to sleep for 5ms while the "BytesToWrite" property was greater than zero. Worked fine after that.

Related

C# Serial Port Receive Only Ever Giving me a Single Character

Question Withdrawn. I found out that I was sending incorrect ASCII patterns and THIS was my problem versus any problems with the receiver. Receiving a single character was merely the echo back of my wrong command
Summary:
C# form app. Serial 38400:N81 no flow control. Talking to a custom device.
If I use Teraterm, everything's fine.
The device I attach to gives simple, immediate responses:
Type 'v' you get a version string "v1.34 02-18-16 17:22" where the v in that is the local echo of the typed command. There are other status commands which are similar, once a character is received by the device, it replies immediately.
In my C# application I have pretty much exactly what you see in this guide under the example:
https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived%28v=vs.110%29.aspx
Differences are that I'm at 38400 versus 9600 and I also do not set up the Handshake or the RtsEnable.
I've done this before so feeling stupid as to some obvious problem here. And I did do a bit of searching/following similar question links too.
Instead of receiving the version string, I receive one character '6'.
For a different command I also receive one character '8'. The notable thing here is that while '6' is part of my version string, '8' is never in the response for that other command.
Any suggestions on how I'd debug the ReadExisting() call?
I fully understand that a received string may arrive in fragments. The issue is that I always only ever receive the one character and nothing else. The event handler never sees any additional data. When I re-issue my version command I get the same '6' back I get before.
My event handler where I'm trying to test the receiver:
private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Debug.WriteLine("Data Received: ");
Debug.Write(indata);
}
Under the debugger, indata.Length is 1.
Teraterm Port Settings:
I was suggested to look for errors and here's the code:
public event SerialErrorReceivedEventHandler ErrorReached;
protected virtual void OnReceiveError(SerialErrorReceivedEventArgs e)
{
SerialErrorReceivedEventHandler handler = ErrorReached;
if (handler != null)
{
handler(this, e);
}
Debug.WriteLine("Serial error");
}
I saw no errors.
Further comments were that the receiver needs to be run more than once. It is, when I issue a 'v' (just the v) I should see the version and 's' should give me status. Again, both work fine on Teraterm. I get 686868 if I issue vsvsvs or other matching patterns if I type like vvsss, I'll get 66888 in reply.
Other point is controlling this device if I issue r and s for run and stop, there is a LED on it which goes solid red (from intermittent flashing to indicate that it's running. I see it run and stop per my commands. So I know that I'm talking to the device in a proper/coherent fashion. Just still have troubles seeing valid receive data.
Some suggestions to try:
You're reading a string from the port, so if the data can't be readily interpreted as a string you may only get a fragment before it stops converting. Read into a byte array to be sure you are really seeing the data that you receive. Even if you think you should get a string, this lets you see what you are actually receiving.
Check your port settings. Symptoms of the wrong baud rate or encoding are frequently that you receive a reduced number of (possibly random, possibly repeatable) bytes of "garbage". This would be consistent with receiving characters that should not be in the response, and the string terminating early.
Remove all configuration options from your port, apart from setting the baud rate. Very few devices use anything other than 8n1 and attempting to set options can often screw the port up. If that doesn't work then start seeing additional options only if you have to.
Make sure you only open the port once and keep it open till you have finished talking to the device. (Repeatedly opening and closing the port I'd really five by accident, and would flush the data in it, interfering with your attempts to read)

SerialPort DataReceived event called or maybe sometimes with 7 data bits [duplicate]

I am working out with serial com port.
I have insert this code in my program.
I able to send data to the devices and fail to read data from the devices.
In debug mode, i only able to get serialport.BytesToRead = 0.
May i know why this will happen??
while (serialport.BytesToRead > 0)
{
int byte_count = serialport.BytesToRead;
byte[] buffer = new byte[byte_count];
int read_count = serialport.Read(buffer, 0, byte_count);
string echo = ASCIIEncoding.ASCII.GetString(buffer, 0, read_count);
echo = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine(echo);
}
First use another program, like Putty or HyperTerminal to verify that the device and connection is in working order and to double-check that you are using the correct port, baudrate, parity, stopbits and databits. If you can't get anything out of the device with such a program then it won't work either using your own code.
Next focus on the handshaking. A common mistake is to leave it at none and then not turn on the DtrEnable and RtsEnable signals. A device won't send anything when it thinks that you're offline. SysInternals' PortMon utility can be handy, it shows you what's going on at the device driver level.
When to you read from the SerialPort? Are you trying to read right after you send? In that case you might try to read before there is actually anything to read from the port.
You should use the DataReceived event to read data.
Note that this event might trigger before all data is received, so you might have to retrieve the data over several calls of DataReceived until you get all the data you are supposed to.

Serial port in .Net (C#)

what should i do to wait until all the data sent to serial port
to test this condition assume the code bellow:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
And it indicate that .Net is not waiting until all chars to be send!
just to mention the code below does not work:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
while (SerialPortObj.BytesToWrite>0)
{
Thread.Sleep(1);
Console.WriteLine(SerialPortObj.BytesToWrite);
};
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
i am working on an special protocol that is depends on baud rate change over and use some thing like the follow:
->[Send Some Bytes (Baud300)]
<-[Receive Another Bytes (Baud9600)]
so i want to send some chars by write method and wait until it finish and right after finishing i try to change baud , so i could understand the received bytes
is there any idea?
In the first place the serial port is stateless. So you can never really by sure when the right point in time is reached for a baud rate change. Due to the fact that you are going to implement your own special protocol you must have control of both sides of the communication (sender/receiver). So in that case i strongly recommend to also set the Handshake property to RequestToSend and checking of the DtrEnable property.
Also you should use two buffers (received/outgoing) on each site of the communication which are watched by their own task/thread. If you push something into the outgoing buffer, the task check if sending is possible (CtsHolding, DsrHolding) and if yes, change the baudrate and push that data onto the wire. Wait till the holding properties are set back and then change the baudrate to the other value. The incoming thread is quite simple in this case. It simply waits for the DataReceived event cause the change of the baudrate is done by the outgoing task.
If you use hardware handshake (which i strongly recommend in your case), then be sure that your serial port supports it correctly. Most of the USB-to-Serial-Adapters don't work very well with anything else then 19200-8-N-1. So before you think you didn't code it right or the SerialPort class is buggy try to find two machines with a real serial port (or one machine with two ports for testing).
Try to store your data in a variable and when a specific condition apear (can be set by you), send the value of the variable to the serial port
Do it in hardware?
You might try to use two serial adaptors, configured as 300/9600. Tx on one and rx on the other. You would need a 'funny cable' with pins 2/3 split out to different D-types, but that should work.

C# .Net Serial DataReceived Event response too slow for high-rate data

I have set up a SerialDataReceivedEventHandler, with a forms based program in VS2008 express. My serial port is set up as follows:
115200, 8N1
Dtr and Rts enabled
ReceivedBytesThreshold = 1
I have a device I am interfacing with over a BlueTooth, USB to Serial. Hyper terminal receives the data just fine at any data rate. The data is sent regularly in 22 byte long packets. This device has an adjustable rate at which data is sent. At low data rates, 10-20Hz, the code below works great, no problems. However, when I increase the data rate past 25Hz, there starts to recieve mulitple packets on one call. What I mean by this is that there should be a event trigger for every incoming packet. With higher output rates, I have tested the buffer size (BytesToRead command) immediatly when the event is called and there are multiple packets in the buffer then. I think that the event fires slowly and by the time it reaches the code, more packes have hit the buffer. One test I do is see how many time the event is trigger per second. At 10Hz, I get 10 event triggers, awesome. At 100Hz, I get something like 40 event triggers, not good. My goal for data rate is 100HZ is acceptable, 200Hz preferred, and 300Hz optimum. This should work because even at 300Hz, that is only 52800bps, less than half of the set 115200 baud rate. Anything I am over looking?
public Form1()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(Display_Results));
}
private void Display_Results(object s, EventArgs e)
{
serialPort1.Read(IMU, 0, serial_Port1.BytesToRead);
}
Did you try to ajust time latency on the USB serial converter? I had the same problem with a FTDI USB to serial converter. I use an oscilloscope to see my IN and OUT data coming from the device and I could see that the computer was always slow to respond. By default, time latency on the device is set to 16 ms. I changed it to 2 ms and it makes a big difference. Go to your USB Serial Converter in the Device Manager and in the advanced settings, change Latency time to 2 ms. It should works. Try it.
Why do you Invoke() the call to DisplayResults?
This will push it to the MessageLoop, an unnecessary delay.
It would be better if DataReceived() pushed data onto a (thread-safe) queue for decoupled processing.
I also think you could run into problems with split packages.
You could try setting ReceivedBytesThreshold = 22, which will result in the event being fired when there are at least 22 bytes to read. Note that it will be at least 22. There may be more.
I don't think I would personally do this though, because what happens if your packet size changes in the future, for example to 12 bytes? You would end up with 12 bytes in the buffer but not firing the event at all.
Far better to leave it set to 1, which will fire the event when at least 1 byte is available. Then push all received bytes into a list or a queue as Henk has already posted.
Note that the DataReceivedEvent has no knowledge of what you consider a packet of data to be of course. It just fires when there are bytes available. It is up to the developer to assemble these bytes into a meaningful message or packet.
The problem lies in the received data handler.
I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.
using System.Threading;
Thread readThread = new Thread(Read);
readThread.Start();
Hope someone else doesn't need to spend 3 hours fixing this.

How to Read Device Data From serial port

I have one device which sends data on COM port say on COM13. Now i want to read that data and display it in the RichTextBox or in any text control.
I have written the application with the help of IO and IO.Ports but comport.DataRecived event does not fire, even though device is sending data on that port.
I have some software on which i define the port number and it successfully display data, which insure me that data is receiving on the Port but i am unable to receive.
Is there any way i can read data?
comm.Parity = cboParity.Text;//None
comm.StopBits = cboStop.Text;//One
comm.DataBits = cboData.Text;//8
comm.BaudRate = cboBaud.Text;//9600
comm.DisplayWindow = rtbDisplay;//Null
comm.PortName = "COM13";
comm.OpenPort();
cmdOpen.Enabled = false;
cmdClose.Enabled = true;
cmdSend.Enabled = true;
public bool OpenPort()
{
if (comPort.IsOpen)
{
comPort.Close();
}
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
comPort.PortName = _portName;
comPort.Open();return true;
}
This normally comes from a wrong configuration of a serial port. It is not enough to simple open a serial port and waiting for some data to come in. You have also to set all the SerialPort.Properties to a correct value for your wanted connection.
Some of the common ones are BaudRate, DataBits or Parity, but to be really sure you have to set all of them. Even such things as RtsEnable or ReadTimeout.
You have to set the all, cause the configuration state will be saved from the port itself. So if one application opens such a port, makes some changes to the configuration and closes it, the next application that opens the port starts with this configuration, till it change it.
Update
Seems to be a problem i can't see from here. ;-))
The only advice i can give you is to use a Monitor tool, to better understand what your other application really does and what comes on the wire. Additionally you can set up two virtual com ports to test reading and writing on one machine (even within the same application), to have a better control about when will which data be send.
Have you read the documentation for the DataReceived event?
From MSDN:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
The snippet you've posted is quite rough, but I'd set the ReceivedBytesThreshold property to one. This ensures the event firing when at least one byte is present in the incoming buffer.
Cheers
Use PortMon to capture the working software, and then capture your software; then compare the traces. Pay particularly close attention to all the configuration parameters, making sure they are the same (as Oliver mentioned).

Categories