Why text from SerialPort will break into several parts? - c#

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();

Related

C# / GTK# Serial Port Read Issue

So I'm trying to read real time data from the serial port object in C# / Gtk#. I have a product which talks over RF to the computer and every time it gets a command it sends back an ACK. If I use AccessPort and auto send a command every 500ms, I get my ACK. I've ran AccessPort for hours and been able to match every single command to an ACK, so I know this is physically working.
I wrote a small program in C# / Gtk# that send data out the serial port at X ms and has a delegated thread which reads the serial port for any bytes that come back. My problem is that no matter how I write the method for the serial reading, it never actually captures all the bytes that I know are there.
So far this is the "lightest" code I have:
private void readSerial(){
byte readByte = 0x00;
Gtk.Application.Invoke (delegate {
try {
readByte = (byte)serialPort.ReadByte();
Console.WriteLine(readByte.ToString("X2"));
} catch (System.ArgumentException sae) {
Console.WriteLine(sae.Message);
}
});
}
I have assigned that method to a thread in the main function:
writeThread = new Thread (writeSerial);
readThread = new Thread (readSerial);
And I start it when a connect button is pressed, along with the writeThread. The writeThread is working fine as I can see the product execute the correct instruction every X ms ( currently I'm testing at 500ms). The ACK should arrive at the computer every X ms + 35 ms * module ID, so if my end product has a module id of 2 the response would be delayed by 70ms and hence the computer should see it at 570ms or X + 70ms.
Is there a better way to do this? I'm I doing something boneheadedly wrong?
Some other code I've played with was reading 0x0E bytes from the serial port and storing the bytes into a buffer, this also missed a lot of the bytes I know are coming back.
Can anyone offer some help? I do know the readSerial method is actually starting as I do see a 0x00 pop out on the console, which is correct as 0x00 are dispersed among the data I'm looking for.
Figured it out!
I'm not sure what the exact issue was but when I removed the delegation and just used a while(true) look inside that method it worked fine.

Data errors with my serial receive method

I'm taking data from a serial instrument for plotting on a chart. The data stream is 230 kbps, and the serial pipeline is less than 50% full, data arrives about 100 kbps and actually doesn't vary really and rate or quantity.
Having used just a serial terminal program, like Teraterm, on the same computer; I can capture data and prove that both the source of the data as well as the test reception method are fine and I see no errors to the captured data.
The Windows Forms application I'm developing loses data. I've reduced it from receiving, capturing (in parallel), parsing, and plotting, to just receiving and capturing. And have found that I still see lost data in the capture.
I'm not a long experienced Windows person, so therefore may not know of better ways to accomplish the same functions. Here are the actions I'm taking to perform receive actions:
I'm using a System.IO.Ports.SerialPort class.
I modify the .DataReceived event via:
+= new SerialDataReceivedEventHandler(comPort_DataReceive);
I then call the open() method.
Note: I may be doing something incorrect here, I never clear the .DataReceived event with a -= at any point, instead each time I open, the event is added yet again. Nevertheless, these problems occur even when I've only talked to the port once.
Here's my code for the data receive function. RxString is a string.
private void comPort_DataReceive(object sender, SerialDataReceivedEventArgs e)
{
RxString = comPort.ReadExisting();
this.Invoke(new EventHandler(ParseData));
}
private void ParseData(object sender, EventArgs e)
{
// Save to capture file, if capture is enabled
if ((WriteToFileEnabled == true) && (WriteToFileName != null))
{
writeFileHandle.Write(RxString);
}
return;
// Previously would parse and plot data
}
So, how would persons execute a receive in this situation to get this data without losing it?
Follow on questions are things like: How big is the buffer for serial receive, or do I need to worry about that if I have a reasonably responsive application? Flow control is irrelevant, the remote device is going to send data no matter what, so it would be up to my computer to take that data and process it or ignore it. But how would I know if I've lost data or experienced framing errors and stuff? (I ask that last one without having searched much on the SerialPort class structure, sorry.)
Lets assume that your device is sending messages that are 85 bytes in length. The DataReceive event handler may or may not fire once to receive those 85 bytes. Since it might fire more than once your code must account for that. The DataReceive event handler should read the bytes available and append them to a buffer that is processed later.
Also, only one of the events raised by the SerialPort class can execute at a time. In the example assume the handler has to fire three times to receive the 85 bytes. While processing the first part the other two can't execute. If while processing the first part one of the other events, PinChanged or ErrorReceived, are needed they can't be executed either.
My first two experiences with the SerialPort class were a 9600 bps terminal and a 1 Mbps bluetooth device. What worked for the slower did not work for the faster, but when I figured out how to get the faster to work the slower could use the same methodology.
My methodology:
Before opening the serial port I start two other background threads that run in a do loop. The first one(Receive) reads all available bytes from the serial port, adds them to a buffer, and signals the second thread on every read. The second one(Protocol) determines if a full message has arrived, does any byte to string conversion, updates the UI, etc. Depending on the application I may start a third thread that handles errors and pin changes. All of these threads are throttled by a Threading AutoResetEvent.
My DataReceive event handler has one line in it, a Set on the AutoResetEvent that is throttling Receive.
A VB example of this can be found here SerialPort Methodology. Since adopting this methodology I have not had any of the problems that seem to plague other SerialPort users and have used it successfully with speeds up to 2Mbps.

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.

serialport stops to early with receiving

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.

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