SerialPort ReadLine() after Thread.Sleep() goes crazy - c#
I've been fighting with this issue for a day and I can't find answer for it.
I am trying to read data from GPS device trough COM port in Compact Framework C#. I am using SerialPort class (actually my own ComPort class boxing SerialPort, but it adds only two fields I need, nothing special).
Anyway, I am running while loop in a separate thread which reads line from the port, analyze NMEA data, print them, catch all exceptions and then I Sleep(200) the thread, because I need CPU for other threads... Without Sleep it works fine, but uses 100% CPU.. When I don't use Sleep after few minutes the output from COM port looks like this:
GPGSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
GSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
A,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,18,12,271,24,24,05,020,24,14,04,326,25,11,03,023,*76
A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
as you can see the same message is read few times but cut.
I wonder what I'm doing wrong...
My port configuration:
port.ReadBufferSize = 4096;
port.BaudRate = 4800;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.NewLine = "\r\n";
port.ReadTimeout = 1000;
port.ReceivedBytesThreshold = 100000;
And my reading function:
private void processGps(){
while (!closing)
{
//reconnect if needed
try
{
string sentence = port.ReadLine();
//here print the sentence
//analyze the sentence (this takes some time 50-100ms)
}
catch (TimeoutException)
{
Thread.Sleep(0);
}
catch (IOException ioex)
{
//handling IO exception (some info on the screen)
}
Thread.Sleep(200);
}
}
There is some more stuff in this function like reconnection if the device is lost etc., but it is not called when the GPS is connected properly. I was trying
port.DiscardInBuffer();
after some blocks of code (in TimeoutException, after read.)
Did anyone had similar problem? I really dont know what I'm doing wrong.. The only way to get rig of it is removing the last Sleep.
For all those who have similar problem. The first issue was about overflowing the buffer. I had 4096 size of buffer and the data was just flowing trough it so I was reading corrupted sentences. Now I read all buffer at once and analyze it. First sentence is sometimes corrupted, but the rest is ok.
The second thing was the device issue. Tom Tom MkII sometimes loses connection with the device. I had to restart the GPS and find it again in Bt devices list.
Regards
There's nothing in your post to say how you are doing handshaking.
Normally you would use software (XON/XOFF) or hardware (e.g. RTS/CTS) handshaking so that the serial port will tell the transmitting to stop when it is unable to receive more data. The handshaking configuration must (of course) match the configuration of the transmitting device.
If you fail to configure handshaking correctly, you may get away with it as long as you are processing the data fast enough - but when you have a Sleep, data may be lost.
Related
Serial Port Communication on the same Windows machine not working
Excuse me, quick question: I have this hardware setup: Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4" And I followed MSDN SerialPort Class and MSDN SerialPort.ReadLine() to build this routine: SerialPort SendSerialPort = new SerialPort("Com3", 9600); SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600); SendSerialPort.Open(); ReceiveSerialPort.Open(); SendSerialPort.WriteLine("Test"); var message = ReceiveSerialPort.ReadLine(); // control stops here SendSerialPort.Close(); ReceiveSerialPort.Close(); Console.WriteLine(message); However, when I tend to ReadLine(), my control stops and just waits. I did not expect that. I am expecting to receive the string Test and assign it to my var message. Could you please tell me what am I doing wrong here? EDIT: I tested my hardware using the Serial Port Utility Application and it worked just fine.
I've altered from the example you linked: To actually have both ports running to read and write back and forth you will actually need to implement threading for reading and writing for both. It can be a good idea to use a timer. public static void Main() { SerialPort SendSerialPort = new SerialPort("Com3", 9600); SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600); StringComparer stringComparer = StringComparer.OrdinalIgnoreCase; Thread readThread = new Thread(Read); // Set the read/write timeouts _serialPort.ReadTimeout = 500; _serialPort.WriteTimeout = 500; SendSerialPort.Open(); ReceiveSerialPort.Open(); bool _continue = true; readThread.Start(); Console.Write("Name: "); name = Console.ReadLine(); Console.WriteLine("Type QUIT to exit"); while (_continue) { message = Console.ReadLine(); if (stringComparer.Equals("quit", message)) _continue = false; else SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message)); } readThread.Join(); SendSerialPort.Close(); } public static void Read() { while (_continue) { try { string message = ReceiveSerialPort.ReadLine(); Console.WriteLine(message); } catch (TimeoutException) { } } } Usually there will be a beginning and end value within the written data to tell the other port that the message is finished and also for the ports to validate that they are reading data they should be, usually with commands of what to do with that data. (out of scope for this question). Also lacking and important is the intialisation of your ports. I prefer to use the default constructor (preference only) SerialPort Constructor () And then set any values like so: _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate); _serialPort.Parity = SetPortParity(_serialPort.Parity); _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits); _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits); _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake); All the constructors will give these values: This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1. Even the handshake has a default value. If you look at the source code. private const Handshake defaultHandshake = Handshake.None;
The problem with your code is in this line var message = ReceiveSerialPort.ReadLine(); You block your code to wait for a line, if the line never arrives it will remain here forever or the value set to ReadTimeout So why does the line never arrive? The problem can be an error in WriteLine("Test");, you should handle errors, or it can be that your in are blocking your code ReadLine() before the WriteLine("Test") manage to come through, you could insert a Thread.Sleep(100) between, but this is not really improving the code. Note: Your code will also work as is sometimes, depending on these race conditions. This synchronized / blocking reading from serial ports seems simple in code just one line; but it creates a lot of negative side effects in your communication protocol's. A much better solution (considering that you like to Read / Write data from a microcontroller) is to either use a thread as Yvette suggested or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) which I would prefer. The asynchronously reading will throw an event when something is incoming on the serial port. The basic idea of this programming strategy is to not do step programming but expecting what ever result and then handle it correctly. In communications protocol with asynchronously reading the AutoResetEvent is very useful, hence you send something, then you start the AutoResetEvent, if asynchronously the expected result is arriving you will set this event and your code can continue, if it does not arrive the AutoResetEvent will timeout and you can handle this.
It cannot block when there is data available. What you sent either got stuck in the transmit buffer, got lost due to a wiring mistake, triggered an error or was ignored. If it works with another program then a wiring mistake can't be the problem. Do keep in mind that just setting the Baudrate is not enough, you must also use set the DataBits, Parity and Stopbits properties to match the device settings. A mismatch can trigger an error, the kind you can only see when you write an event handler for the ErrorReceived event. Never skip that event, confounding problems can occur if you never check. And above all the Handshake property must be set correctly. The proper value depends on how the ports are wired together, it is too common to not connect them. Start by setting it to Handshake.None so a wrong state for the DSR and CTS signals can't block reception and a wrong state for the DTR and RTS signals can't block transmission. Beware that it is common for another program to enable hardware handshaking, a mismatch is guaranteed to cause communications to stall. If you use synchronous reads instead of the DataReceived event then you should in general deal with the possibility that a device is not responding. Either because it is powered off, not connected at all or malfunctioning. Use the ReadTimeout property for that so your program cannot hang. Aim high, 10000 milliseconds is a reasonable choice. Beware the randomness of this problem, putzing around with another program can easily get the port configured correctly and now it will suddenly work. And beware that starting a thread accomplishes nothing, it will now be that thread that gets stuck and the Join() call will deadlock.
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.
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.
How can I read from a socket repeatedly?
To start I am coding in C#. I am writing data of varying sizes to a device through a socket. After writing the data I want to read from the socket because the device will write back an error code/completion message once it has finished processing all of the data. Currently I have something like this: byte[] resultErrorCode = new byte[1]; resultErrorCode[0] = 255; while (resultErrorCode[0] == 255) { try { ReadFromSocket(ref resultErrorCode); } catch (Exception) { } } Console.WriteLine(ErrorList[resultErrorCode[0] - 48]); I use ReadFromSocket in other places, so I know that it is working correctly. What ends up happening is that the port I am connecting from (on my machine) changes to random ports. I think that this causes the firmware on the other side to have a bad connection. So when I write data on the other side, it tries to write data to the original port that I connected through, but after trying to read several times, the connection port changes on my side. How can I read from the socket continuously until I receive a completion command? If I know that something is wrong with the loop because for my smallest test file it takes 1 min and 13 seconds pretty consistently. I have tested the code by removing the loop and putting the code to sleep for 1 min and 15 seconds. When it resumes, it successfully reads the completion command that I am expecting. Does anyone have any advice?
What you should have is a separate thread which will act like a driver of your external hardware. This thread will receive all data, parse it and transmit the appropriate messages to the rest of your application. This portion of code will give you an idea of how receive and parse data from your hardware. public void ContinuousReceive(){ byte[] buffer = new byte[1024]; bool terminationCodeReceived = false; while(!terminationCodeReceived){ try{ if(server.Receive(buffer)>0){ // We got something // Parse the received data and check if the termination code // is received or not } }catch (SocketException e){ Console.WriteLine("Oops! Something bad happened:" + e.Message); } } } Notes: If you want to open a specific port on your machine (some external hardware are configured to talk to a predefined port) then you should specify that when you create your socket Never close your socket until you want to stop your application or the external hardware API requires that. Keeping your socket open will resolve the random port change using Thread.Sleep when dealing with external hardware is not a good idea. When possible, you should either use events (in case of RS232 connections) or blocking calls on separate threads as it is the case in the code above.
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.