serialport stops to early with receiving - c#

Goodday everybody,
My problem is the following:
I am communicating with serialport to a zigbee like apparatus and this is working however when i send the following in the C# app:
(string is "0023000D6F000076CF27431e" (in picture send twice)
I get a part of the answer from the apparatus(read window from picture):
However when i send "0023000D6F000076CF27431e" direct to the port by terminal i get the apparatus to answer this:
This is the complete en correct answer.
And of course i need the last line (with the 0024 part in it).
I think (i am not very good in programming yet) this part recieve's the data:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{// Event for receiving data
string txt = port.ReadExisting();
Thread.Sleep(10);
List<PlugwiseMessage> msg = reader.Read(Regex.Split(txt, "\r\n"));
DataReceived(sender, new System.EventArgs(), msg);
I googled about ReadExisting but it seem that this is te correct way to go????
Or is it not ??
Can someone explain this behaviour to me ?

This is by design. ReadExisting() does what it says, it only returns characters that exist in the serial port read buffer. Serial ports are very slow devices, you normally only get a couple of characters for each ReadExisting() call. This is especially tricky when you use a debugger, that slows your program down a lot, giving the serial port driver time to receive additional characters.
You can use ReadLine() instead, you'll get one line of text from the serial terminal output for each call. That works because the device is sending a linefeed as a line terminator (0x0a in the hex dump). Remove the Sleep() call, that only makes things worse.

Related

Why text from SerialPort will break into several parts?

I used SerialPort to receive text from Handheld Scanner.In addition,the Handheld Scanner is using usb port to connnect with computer but its drivers will make it to a virtual SerialPort.
So I use this code to receive the text:
SerialPort serialPort=new SerialPort("COM7");
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(serialPort.ReadExisting());
}
Well,when I ran the progam,if the barcode is "1234567890",the text what received will break into several parts without rules.Such as:
123
45
7890
Sometimes such as:
123456
7890
Sometimes such as:
1234
567890
What's wrong with this,why the text divide into several without rules?How can I let it combine together but not divide any more?
PS:I tried different brand Handheld Scanner,such as Datalogic QD2430/Honeywell GHD1900,but these problem still here.
Serial port I/O can be thought of as a streaming interface, i.e. You might not receive all the data in a single callback.
When you see:
12
34
567890
...I suspect what is happening is that your callback is being called three times with 3 Console.WriteLine calls. Hence your output looks broken.
Typically you need to read all the bytes until some terminator is reached, which depends on the device. You will need to buffer the data received until then. Until then, depending on the nature of the app, you might not be able to process the request.
Configure your scanner that after each scan it should add a carriage return and then just get the result like this
var result = serialPort.ReadLine();

Try/Catch blocks the application [duplicate]

I am trying to read data from a scale RS232 interface. It sends a continuous ASCII string stream through the Serial Port which I am having trouble getting. I just want to get one line of the data that it is sending out. I guess I assumed that I would use Readline to get the data, but it just locks up the PC when I run it. I think it is trying to get all of the data and won't stop until the data stops? Here is the code I'm using:
private void button1_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM4";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
//opening the serial port
serialPort1.Open();
string str = serialPort1.ReadLine();
MessageBox.Show(str);
serialPort1.Close();
}
Can you help me to determine how to get just one line of the output data and close the connection?
SerialPort.ReadLine is defined to block "up to the first occurrence of a NewLine value", where NewLine defaults to a line feed. Are you sending a linefeed in your stream? Note that a linefeed character (ASCII 0x0A) is different that a carriage return (ASCII 0x0D) that you might be sending.
You can redefine the NewLine if needed, or if a line ending doesn't feel right, you can read up to a given string with SerialPort.ReadTo. You can also set a read timeout.
You might prefer to read a given number of bytes from the port, rather than a line, with one of the SerialPort.Read overloads.
If none of this applies, make sure that you're actually sending data where you think you are - bring up HyperTerminal/TeraTerm/your favorite serial terminal, configure it with the same serial port settings as you've used above, and make sure you see the data you expect to see.
An ideal solution would be to spawn a worker thread to actually read from the serial port (thus, the thread can be blocked all day long without impeding on your main application thread). Once data has been received, it can broadcast an event noting that data has been received and what that data is. The thread would communicate with the main application thread through the event.

Is it not possible for two timer_tick events to work in parallel in reading the same data but performing different tasks?

I developed a C# application for reading calls from GSM Modem. I used a timer to read the port regularly and notify me when there is a incoming call.
Now i am trying to use another timer which will write AT+CSQ -To know the signal quality, on the port and read the port for the quality value. In both the timers i used regular expressions to match and separate the data i need. Now the problem is that only my timer2 which is reading the signal quality is only working but not timer reading for incoming calls.
Timer reading signal strength:
private void tmr_sig_quality_Tick(object sender, EventArgs e)
{
if (port.IsOpen)
{
port.WriteLine("AT+CSQ");
string s= port.ReadExisting();
var match= Regex.Match(s,#"\+CSQ: (\d+),(\d+)");
if (match.Success)
{
progressBar1.Value = int.Parse(match.Groups[1].Value);
}
}
}
Timer reading incoming calls:
private void timer1_Tick(object sender, EventArgs e)
{
s = port.ReadExisting();
var match = Regex.Match(s, "RING[^\\+]*\\+CLIP:\\s*\"(?<phone>[^\"]*)\",(\\d+),\"([^\"]*)\",(\\w*),\"(\\w*)\",(\\w*)");
if (match.Success && s.Contains("RING"))
{
incall_status.Text = "Incoming Call...." + match.Groups["phone"].Value;
incall_status.Visible = true;
}
}
Why is this happening and solution please?
Two major problems. First is ReadExisting(), that will always return an empty string. Except when you are debugging and stepping through the code line by line. That gives the modem enough time to send the response. But this won't work when you run at full speed, you'll need to make a blocking call that ensures your program waits long enough to get all the returned characters. Use ReadLine() instead.
Second killer problem is that you are mixing commands. Your tmr_sig_quality_Tick() method is likely to read whatever timer1_Tick() was supposed to read. You'll need to re-think this approach. Something like a queue of commands that doesn't advance until the response to a command is received.
Not an actual answer to your question, but a general advice for communicating with a GSM modem:
Keep in mind that you have only one serial port, thus only one communication channel. A GSM modem can send spontaneous events, such as the RING, FAX, VOICE events, so there is no guarantee that when you write AT+CSQ the first reply is what you expect, i.e. the signal quality.
Having two timers like you're intending is not a good idea since you'll eventually end up with the response of one command in timer A when it was expected in B, because A read one of the spontaneous events...etc.
A much better and robust way is to have a worker thread that reads and interprets the incoming data and then distributes that in you application as needed. It can also handle the outgoing data. Use concurrent queues and some signaling mechanism (i.e. AutoResetEvent) for exchanging data with this thread, that way you get a cleaner interface to your hardware device and don't need to worry about timing and such in your application.

Readline from Serial Port locks up

I am trying to read data from a scale RS232 interface. It sends a continuous ASCII string stream through the Serial Port which I am having trouble getting. I just want to get one line of the data that it is sending out. I guess I assumed that I would use Readline to get the data, but it just locks up the PC when I run it. I think it is trying to get all of the data and won't stop until the data stops? Here is the code I'm using:
private void button1_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM4";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
//opening the serial port
serialPort1.Open();
string str = serialPort1.ReadLine();
MessageBox.Show(str);
serialPort1.Close();
}
Can you help me to determine how to get just one line of the output data and close the connection?
SerialPort.ReadLine is defined to block "up to the first occurrence of a NewLine value", where NewLine defaults to a line feed. Are you sending a linefeed in your stream? Note that a linefeed character (ASCII 0x0A) is different that a carriage return (ASCII 0x0D) that you might be sending.
You can redefine the NewLine if needed, or if a line ending doesn't feel right, you can read up to a given string with SerialPort.ReadTo. You can also set a read timeout.
You might prefer to read a given number of bytes from the port, rather than a line, with one of the SerialPort.Read overloads.
If none of this applies, make sure that you're actually sending data where you think you are - bring up HyperTerminal/TeraTerm/your favorite serial terminal, configure it with the same serial port settings as you've used above, and make sure you see the data you expect to see.
An ideal solution would be to spawn a worker thread to actually read from the serial port (thus, the thread can be blocked all day long without impeding on your main application thread). Once data has been received, it can broadcast an event noting that data has been received and what that data is. The thread would communicate with the main application thread through the event.

Improving a SerialPort Connection

Pretty simple question this time around. I have an application that communicates with another copy of the application on another machines. One application sends a pretty constant stream of data, the other receives it.
The code to send data looks like this (where serialPort is an instance of the System.IO.Ports.SerialPorts class in C# .Net 2.0):
private void bgDataWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e){
try{
string tempStr = Convert.ToString(String.Format("{0:0.000000}", data));
serialPort.Write(tempStr); // Write "data" out to 6 decimal places
}
catch (TimeoutException){ }
catch (InvalidOperationException err){ // Port is obstructed or closed
this.Invoke((MethodInvoker)delegate{
MessageBox.Show(this, "Couldn't send wireless data:\n\n" +
err.ToString(), "NanoMETER - Wireless Error (Data)",
MessageBoxButtons.OK, MessageBoxIcon.Error);
Global.remoteEna = false;
serialPort.Close();
usingBT = false;
});
}
}
It's called on a timer. The receive code is even more straightforward:
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
string buffer = serialPort.ReadExisting();
HandleInput(buffer);
}
Data gets sent and handled and it's all fine and dandy, but there's some unwanted choppiness where it's either not reliably sending data at a constant rate, or it's not picking up everything. I'm not sure if this can be fixed in my code, or if it's just the nature of having a few slow machines and a possibly shakey bluetooth connection. Any suggestions?
It's not uncommon for interns to be assigned to converting old code to a newer platform.
There are a few improvements you can make.
1) The following strategy is good when the bytes sent through the port is meant to be interpreted in blocks, such as commands. Do you have some sort of protocol? Something that dictates the format of the message you are sending. For instance, a specific delimiter to indicate the beginning and the length of the upcoming command. This allows you to quickly determine if the command was only half sent, or if there were missing bytes. Even better is to add a CRC at the end.
2) Instead of reading on a timer, base yourself on the events flagged by your serialport object. Here's an example of what i use:
//OnReceive event will only fire when at least 9 bytes are in the buffer.
serialPort.ReceivedBytesThreshold = 9;
//register the event handlers
serialPort.DataReceived += new SerialDataReceivedEventHandler(OnReceive);
serialPort.PinChanged += new SerialPinChangedEventHandler(OnPinChanged);
In the code above, i set a threshhold of 9, you should change that to whatever fits your context. Also, the Pinchanged event is something good to monitor, it will allow you to quickly identify if the cable has been disconnected. There is more on this, regarding CTSChanged but you can look it up if you are interested.
Lastly, if this doesn't help you get a little further, show an example of the problem that occured so the peolpe here can give you more help.

Categories

Resources