While loop Does not finish even when statement goes false - c#

I'm writing a WinForm application to control an encoder engine via serial port. The protocol is quite simple, I send the 1st command to ask engine moving, and the 2nd command to confirm it's been in new position, and so on for other places. Here is my code for this:
string dataRead ="";
serialPort1.Write("P.1=2950\r\n"); //Location register (2950)
serialPort1.Write("^.1\r\n"); //Moving command
while (dataRead.Contains("Px.1=2950") == false)
{
serialPort1.Write("?96.1\r\n"); //Ask for current location
respond3 = serialPort1.ReadExisting();
dataRead = string.Concat(dataRead, respond3);
}
//Keep moving to 710 after stop at 2950
serialPort1.Write("P.1=710\r\n"); //Location register (710)
serialPort1.Write("^.1\r\n"); //Moving command
The problem is, when I debug my app, it's stuck in the while-loop. But if I break all, and then continue again, it will pass. The respond3 is used to get output from the engine. Whenever it gets a correct respond, the while-loop will finish.

The problem with this code is how ReadExisting works. The important part is:
Reads all immediately available bytes, based on the encoding, in both the stream and the input buffer of the SerialPort object.
Emphasis mine.
When you're debugging, the IO port has more time to read data, so you'll get a long string in your input like so:
"?96.1\r\n?96.1\r\n?96.1\r\n?96.1\r\nPx.1=2950\r\n"
However, when you're not debugging the code runs faster, and you will get: "?" followed by "9" etc.
As such the immediately available string will never match the string "Px.1=2950" and your loop will never stop.
What you probably want to use, given the newline delimited string you are using, is the ReadLine method.

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)

How to properly read line using sockets through asynchronous callback

I have a library that is connected to some network service using TCP sockets and randomly receives a data from it. I need to process these data line by line and for that I have 2 options:
Create a new thread (I don't want to do that) in which I have never ending loop which calls StreamReader.ReadLine() (I don't want to spawn new threads as this is a library and threads should be fully under control of main program)
Using async callback which gets called every time some data arrives to stream buffer. I currently use this option, but I am having troubles getting lines only. I hacked out this simple solution:
// This function reset the callback after it's processed
private void resetCallback()
{
if (this.networkStream == null)
return;
if (!string.IsNullOrEmpty(this.lineBuffer) && this.lineBuffer.EndsWith("\n"))
{
this.processOutput(this.lineBuffer);
this.lineBuffer = "";
}
AsyncCallback callback = new AsyncCallback(OnReceive);
this.networkStream.BeginRead(buffer, 0, buffer.Length, callback, this.networkStream);
}
// This function gets called every time some data arrives to buffer
private void OnReceive(IAsyncResult data)
{
if (this.networkStream == null)
return;
int bytes = this.networkStream.EndRead(data);
string text = System.Text.Encoding.UTF8.GetString(buffer, 0, bytes);
if (!text.Contains("\n"))
{
this.lineBuffer += text;
}
else
{
List<string> parts = new List<string>(text.Split('\n'));
while (parts.Count > 0)
{
this.lineBuffer += parts[0];
if (parts.Count > 1)
{
this.processOutput(this.lineBuffer + "\n");
this.lineBuffer = "";
}
parts.RemoveAt(0);
}
}
this.resetCallback();
}
As you can see I am using very nasty solution where I am basically checking in every "packet" of data that are received on buffer:
Whether data in buffer are whole line (ends with new line)
Whether data in buffer contains more than 1 line (new line is somewhere in middle of data, or there are more than 1 new line)
Data in buffer contains only a part of a line (no new line in text)
The problem here is that callback function can be called any time when some data are received, and these data can be a line, part of a line, or even multiple lines.
Based on the new line I am storing data in another buffers and when I finally get a new line, I process it somehow.
This is actually working just fine, but I am still wondering if there isn't a better solution that is more clean and doesn't require such a hacking in order to read the stream line by line without using threads?
Please note commenter Damien_The_Unbeliever's point about the issue with partial UTF8 characters. As he says, there's nothing in TCP that would guarantee that you only receive whole characters; a sequence of bytes in the stream can be interrupted at any point, including mid-character.
The usual way to address this would be to using an instance of a Decoder (which you can retrieve from the appropriate Encoding subclass, e.g. Encoding.UTF8.GetDecoder()). A decoder instance will buffer characters for you, returning only whole characters as they are available.
But in your case, there is a much easier way: use the TextReader.ReadLineAsync() method.
For example, here's an asynchronous method which will process each line of text read from the stream, with the returned task for the method completing only when the stream itself has reached the end (i.e. graceful closure of the socket):
async Task ProcessLines()
{
using (StreamReader reader = new StreamReader(
this.networkStream, Encoding.UTF8, false, 1024, true))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
this.processOutput(line);
}
}
// Clean up here. I.e. send any remaining response to remote endpoint,
// call Socket.Shutdown(SocketShutdown.Both), and then close the
// socket.
}
You would call that (preferably awaiting the result in another async method, though that would depend on the exact context of the caller) from wherever you call resetCallback() now. Given the lack of a good, minimal, complete code example a more specific explanation than that can't be provided.
The key is that, being an async method, the method will return as soon as you call ReadLineAsync() (assuming the call doesn't complete immediately), and will resume execution later once that operation completes, i.e. a complete line of text is available and can be returned.
This is the standard idiom now in C# for dealing with this kind of asynchronous operation. It allows you to write the code practically as if you are doing everything synchronously, while the compiler rewrites the code for you to actually implement it asynchronously.
(As an aside: you may want to consider using the usual .NET conventions, i.e. Pascal casing, for method names, instead of the Java-style camel-casing. That will help readers more readily understand your code examples).

How to open SerialPort only when data received, not all the time, in C#?

I have written the function DataReceivedHandler, and it works perfectly, but the port should be kept open to read coming data. On my project, the port should be keept available so other pages can use it if there isn't any data coming from Arduino. How can I open it only when the data received?
private static void DataReceivedHandler( object sender,SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = "";
System.Threading.Thread.Sleep(1000);
indata = sp.ReadExisting();
// Console.WriteLine("Data Received:");
if (indata == "kitchen_light_on\r\n")
f1.update_flag("kitchen_light", 1);
else
if(indata == "kitchen_light_off\r\n")
f1.update_flag("kitchen_light", 0);
}
You need one SerialPort object which stays open and is shared by all the various pages.
Note that the System.IO.Ports.SerialPort class is designed badly, and you've fallen into one of its traps. You can never compare the result of ReadExisting() to anything, because you might get part of your data now and part later. You first have to concatenate together an entire message and then you can process it. Or you might get multiple messages at once, in which case you'll need to split them apart before processing.
I fully agree with Ben. If your goal is to make sure to get the complete message and nothing dirty attached to it for your Windows program to understand what to do, I would recommend to use header and tail identifiers, something like >hereYourMessage< and/or to make your messages from the Arduino much shorter.
You can then recognize a complete message taking the characters/number or whatsoever between the >< and strip them out to pass the message to get fired.

C# "using" SerialPort transmit with data loss

I'm new to this forum, and I have a question that has been bothering me for a while.
My setup is a serial enabled character display connected to my pc with a usb/uart converter. I'm transmitting bytes to the display via the serialPort class in a separate write buffer thread in a C++ style:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
s.Write(b,0,b.Length);
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
Assuming the serial port is already opened, this works perfectly and transmits all the data to the display. There are though no exception handling at all in this snippet. Therefore I was looking into implementing a typical C# feature, the 'using' statement and only opening the port when needed, like so:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
using(s){ //using the serialPort
s.Open();
s.Write(b,0,b.Length);
s.Close();
}
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
The problem with this function is, that it only transmits a random amount of the data, typically about one third of the byte-array of 80 bytes. I have tried different priority settings of the thread, but nothing changes.
Am I missing something important, or do I simply close the port too fast after a transmit request?
I hope you can help me. Thanks :)
No, that was a Really Bad Idea. The things that go wrong, roughly in the order you'll encounter them:
the serial port driver discards any bytes left in the transmit buffer that were not yet transmitted when you close the port. Which is what you are seeing now.
the MSDN article for SerialPort.Close() warns that you must "wait a while" before opening the port again. There's an internal worker thread that needs to shut down. The amount of time you have to wait is not specified and is variable, depending on machine load.
closing a port allows another program to grab the port and open it. Serial ports cannot be shared, your program will fail when you try to open it again.
Serial ports were simply not designed to be opened and closed on-the-fly. Only open it at the start of your program, close it when it ends. Not calling Close() at all is quite acceptable and avoids a deadlock scenario.
I think you're missing the point of the using block. A typical using block will look like this:
using (var resource = new SomeResource())
{
resource.DoSomething();
}
The opening happens at the very beginning. Typically as part of the constructor. But sometimes on the first line of the using block.
But the big red flag I see is that the closing happens automatically. You don't need the .Close() call.
If the successful operation of your serial device is dependent on the calls to Thread.Sleep then perhaps the thread is being interrupted at some point, sufficient to make the data transmission out of sync with the device. There would most likely be ways to solve this but the first thing I would do is try to use the .NET SerialPort class instead. The Write method is very similar to what you want to do, and there are C++ code examples in those articles.

Parse output from a process that updates a single console line

Greetings stackoverflow members,
in a BackgroundWorker of a WPF Frontend i run sox (open source console sound processing tool) in a System.Diagnostics.Process. In that same way i use several other command line tools and parse their output to poulate progress bars in my frontend.
This works fine for the other tools but not for Sox since instead of spamming new lines for each progress step, it updates a single line on the console by only using carriage returns (\r) and no line feeds (\n). I tried both asynchronous and synchronous reads on process.StandardError.
Using async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); in combination with process.BeginErrorReadLine(); doesn't produce any individual status updates because for some reason the carriage returns do not trigger ReadLine, even though the MSDN docs suggest that it should. The output is spit out in one chunk when the process finishes.
I then tried the following code for synchronous char by char reads on the stream:
char[] c;
var line = new StringBuilder();
while (process.StandardError.Peek() > -1)
{
c = new char[1];
process.StandardError.Read(c, 0, c.Length);
if (c[0] == '\r')
{
var percentage = 0;
var regex = new Regex(#"%\s([^\s]+)");
var match = regex.Match(line.ToString());
if (match.Success)
{
myProgressObject.ProgressType = ProgressType.FadingAudio
//... some calculations omitted for brevity
percentage = (int) Math.Round(result);
}
else
{
myProgressObject.ProgressType = ProgressType.UndefinedStep;
}
_backGroundWorker.ReportProgress(percentage, myProgressObject);
line.Clear();
}
else
{
line.Append(c[0]);
}
}
The above code does not seem to read the stream in realtime but will stall output for a while. Then it spams a small chunk and finally deadlocks half-way through the process.
Any hints towards the right direction would be greatly appreciated!
UPDATE with (sloppy?) solution:
This drove me crazy because nothing i tried on the C# side of things seemed to have any effect on the results. My original implementation, before changing it 15 times and introducing new dependencies, was fine.
The problem is with sox and RedirectStandardError alone. I discovered that after grabbing the sox source code and building my own version. First i removed all output of sox entirely except for the stuff i was really interested in and then changing the output to full lines followed by a newline \n . I assumed that this would fix my issues. Well, it didn't. I do not know enough c++ to actually find out why, but they seem to have tempered with how stdio writes to that stream, how it's buffered or do it in such a special way that the streamreader on the c# side is not flushed until the default 4096 byte buffer is full. I confirmed that by padding each line to at least 4096 byte. So in conclusion all i had to do was to manually flush stderr in sox.c after each fprintf(stderr, ...) call in display_status(...):
fflush(stderr);
Though, I'm not sure this is anywhere close to an elegant solution.
Thanks to Erik Dietrich for his answer which made me look at this from a different angle.
The situation you describe is a known problem - for a solution including source code see http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx
It solves both problems (deadlock and the problem with \n)...
I've had to deal with a similar issue with a bespoke build tool in visual studio. I found that using a regex and doing the parsing in the same thread as the reading is a problem and the output processing grinds to a halt. I ended up with a standard consumer producer solution where you read lines from the output and stick them onto a Queue. Then have the queue be dequeued and processed on some other thread. I can't offer source code but this site has some fantastic resources: http://www.albahari.com/threading/part2.aspx
It's a little kludgy, but perhaps you could pipe the output of the uncooperative process to a process that does nothing but process input by characters, insert line feeds, and write to to standard out... So, in terms of (very) pseudo-code:
StartProcess("sox | littleguythatIwrote")
ReadStandardOutTheWayYouAleadyAre()
Could be that just moves the goalposts (I'm a lot more familiar with std in/out/err in the NIX world), but it's a different way to look at the problem, anyway.

Categories