none
Serial Port failure on PC RRS feed

  • Question

  • I have been using the .NET framework for Serial communication for years with no problem, but a few weeks ago my Serial port started failing when used from a .NET application. 

    I recently change from .NET 2.0 to 3.5, but the code had run for a while on 3.5 before the problem arose. 

    Using a native C++ application the COM-port works as it should.

    I have attempted to change back to .NET 2.0, however the error also exist here. When the application is run on other computers (same OS and type) it works fine.

    I have written a simple application (.NET 2.0):

    SerialPort sp = new SerialPort("COM12", 115200, Parity.None, 8, StopBits.One);

    sp.Open();
    byte[] t = new byte[1024];
    sp.Read(t, 0, 1024);

    Which throws an I/O Exception: "The I/O operation has been aborted because of either a thread exit or an application request."

    With stach trace: 

       at System.IO.Ports.SerialStream.EndRead(IAsyncResult asyncResult)
       at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
       at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count)
       at System.IO.Ports.SerialPort.Read(Byte[] buffer, Int32 offset, Int32 count)

    The application is a simple Console application.

    I use a Lenovo X220 with Windows 7 (64bit) and an USB <-> COM device (TU-S9). However as the device works fine on a native C++ application, I find it unlikely that the problem should be with the driver.

    I have found another post mentioning something similar here:

    http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvb/thread/3e64f562-e74b-4213-8019-e69f54fc0d74/

    However there is no clear description of what the problem is or how to fix it. Do I need to uninstall the .NET framework? The Operating system?

    I have also located this:

    http://zachsaw.blogspot.dk/2010/07/net-serialport-woes.html

    However when I perform a read-back of the fAbortOnError flag the flag is not set, and therefore should not need to be cleared. 

    I look forward to hear back with respect to this error

    Thank you in advance

    Wednesday, April 3, 2013 1:17 PM

Answers

  • It is possible you are getting an overrun error in the UART because the computer is running slow.  You ca try stopping some service to see if that fixes the error.  Maybe going into safe mode and running the code will prove my theory.  YOu may also want to compile on another computer and then run the executable from the computer that is giving the problem.  This should determine if the Net Library is the culprit.

    jdweng

    Wednesday, April 3, 2013 6:15 PM
  • Yeah, you are right, Read is a blocking call.  Even so it should not, in general, be called unless one has tested BytesToRead to assure that there is data available.  And, if you call Read, one should test the return value to determine the number of bytes actually read, if that is of concern.  Also, Read should not be called immediately after Open to assure that any latency associated with the Open has been passed. 

    For example, some serial Bluetooth, serial WiFi, or other devices that use Virtual Serial port device drivers may not have completed all operations required to complete the communication "association" and the Read can cause an exception.  I have seen "issues" that require as much as 1000 mS before the port can actually be used.

    BTW, suggesting AsyncRead is not appropriate (IMO).  It may not be supported.  You can set the ReadTimeout to permit a failure to read and thus trap a timeout exception.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, April 3, 2013 7:51 PM
  • The only time that I have seen the error that you report was due to a poorly written USB serial port device driver.  You may want to revisit the idea that I suggested earlier.  Don't attempt to read data until there is data present... And, double-check to verify that the hardware you are using is "decent."  I have seen USB adapters that worked correctly only on x86 (32-bit) hardware, but that failed on x64 systems.

    If you are using specialized hardware, such as devices that use a wireless connection, you may need to respect the latency imposed by the connection method after Open.  As I mentioned in another reply, I have observed that some devices require as much as 1000 mS to complete the connection.

    I have a suggestion.  Download the free .NET Enhanced SerialPort dll from my homepage.  It includes code for both the Enhanced SerialPort and the built-in SerialPort.  See if that code has any issues with your serial port device.  Now, I cannot say "100% of the time" that this code will work... But, in my experience, if it does not work, the cause is in the hardware or device driver.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, April 3, 2013 8:02 PM

All replies

  • It is possible the cable was changed or a wire in a cable broke.  First try disabling the Handshaking and see if that clears the error.  A serial port should never close on its own unless handshaking is enabled.

                SerialPort sp = new SerialPort("COM12", 115200,   Parity.None, 8, StopBits.One);
                sp.Handshake = Handshake.None;
                sp.RtsEnable = false;
                sp.DtrEnable = false;
                sp.Open();
                byte[] t = new byte[1024];
                sp.Read(t, 0, 1024); 


    jdweng

    Wednesday, April 3, 2013 4:33 PM
  • Thank you for the suggestion. Unfortunately the Default values of Handshake, RtsEnabled and DtrEnabled are the same values you suggest giving the.

    I attempted the code you wrote just to be sure, and it fails in the same way.

    With respect to broken wires etc. I can mention that I can reproduce the error without attaching anything to the serial cable. I that case the Read should block, but instead the exception is thrown, as shown above. 

    Also, I have written a small test program that uses P/Invoke with CreateFile, SetCommState and ReadFile to use the serial port (the same port with the same USB<->Serial device attached) and when I execute the read with P/Invoke from within the same application as the above code snippet it works perfectly. And naturally it also works when I apply some data to the serial port. 

    I can use this small home-made managed Serial Port abstractions, but I would like to use the built-in serial port in .NET, as this is the one that is supported by the .NET framework, and therefore the one that is known and supported, and I therefore very much look forward to reading about a solution. 

    I imagine that the .NET SerialPort implementation uses the same win32 kernel functions as I have used for my P/invoke test, though certainly more completely and efficiently.

    Thank you in advance.

    Wednesday, April 3, 2013 5:24 PM
  • Also, Read() is not a blocking operation, so you cannot read 1024 bytes of data until there are 1024 (or more) bytes available.  This will not happen immediately after Open; there will be some delay.

    So, you have to wait until SerialPort.BytesToRead >= 1024.  You can simply wait in a loop, if you want a blocking read, until ByteToRead >= 1024 is satisfied (include a timeout, so that the loop has a way to exit if there is no data).

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, April 3, 2013 5:25 PM
  • Dick : you are wrong about blocking

    Read/Write - Synchronous - blocking

    AsyncRead/AsyncWrite - ASynchronous - non blocking

    This has nothing to do with the current problem.  Read should not return with an error when handshaking is off  and 8 bith no parity is used.  the error is probably a hardware error with a cable or serial board inside the computer not being seated. Sometimes problems like this are due to conflicts I/O assignments inside the computer.   I would try a different computer and see if you get the same results.


    jdweng

    Wednesday, April 3, 2013 5:35 PM
  • Thank you Joel for the description of Asynchronous vs Synchronous. As mention in the beginning of the thread I have not been able to reproduce the problem on other computers, and my first thought was a HW or driver error.

    However, as I mention, the same driver and HW works perfectly when accessed from outside .NET, including via P/Invoke. The Windows COM drivers for the Serial Port, as well as the underlying drivers must therefore work correctly, and it is only when accessed via the .NET SerialPort class that the problem occurs and only on my development PC. 

    I am wondering if anyone has experience anything similar or can explain why .NET SerialPort specifically fails when the native SerialPort do not. Based on the stack trace shown above one gets the impression that the Asynchronous Begin/End read is used also for Synchronous reads. There can be plenty of good reasons why the implementation is this way, and the pattern:

    1. BeginRead

    2. Wait read done

    3. EndRead

    is perfectly allowed, however this does not explain the I/O exception. My only thought is there is some kind of global setting that .NET consults that has somehow changed on my computer and causes this problem. Any thoughts?
    Wednesday, April 3, 2013 6:07 PM
  • It is possible you are getting an overrun error in the UART because the computer is running slow.  You ca try stopping some service to see if that fixes the error.  Maybe going into safe mode and running the code will prove my theory.  YOu may also want to compile on another computer and then run the executable from the computer that is giving the problem.  This should determine if the Net Library is the culprit.

    jdweng

    Wednesday, April 3, 2013 6:15 PM
  • Yeah, you are right, Read is a blocking call.  Even so it should not, in general, be called unless one has tested BytesToRead to assure that there is data available.  And, if you call Read, one should test the return value to determine the number of bytes actually read, if that is of concern.  Also, Read should not be called immediately after Open to assure that any latency associated with the Open has been passed. 

    For example, some serial Bluetooth, serial WiFi, or other devices that use Virtual Serial port device drivers may not have completed all operations required to complete the communication "association" and the Read can cause an exception.  I have seen "issues" that require as much as 1000 mS before the port can actually be used.

    BTW, suggesting AsyncRead is not appropriate (IMO).  It may not be supported.  You can set the ReadTimeout to permit a failure to read and thus trap a timeout exception.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, April 3, 2013 7:51 PM
  • The only time that I have seen the error that you report was due to a poorly written USB serial port device driver.  You may want to revisit the idea that I suggested earlier.  Don't attempt to read data until there is data present... And, double-check to verify that the hardware you are using is "decent."  I have seen USB adapters that worked correctly only on x86 (32-bit) hardware, but that failed on x64 systems.

    If you are using specialized hardware, such as devices that use a wireless connection, you may need to respect the latency imposed by the connection method after Open.  As I mentioned in another reply, I have observed that some devices require as much as 1000 mS to complete the connection.

    I have a suggestion.  Download the free .NET Enhanced SerialPort dll from my homepage.  It includes code for both the Enhanced SerialPort and the built-in SerialPort.  See if that code has any issues with your serial port device.  Now, I cannot say "100% of the time" that this code will work... But, in my experience, if it does not work, the cause is in the hardware or device driver.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, April 3, 2013 8:02 PM
  • Thank you Dick and Joel. I have written some tests to try and analyse what you suggest:

    1. Add a 1s delay between open and the first Read (this is left in the remaining tests as well)
    2. Set the ReadTimeout to 1s (it is by default Infinite) on another PC and compare the exception
    3. Poll the BytesToRead every 100ms and only read if there is data to read
    4. Use the BaseStream.BeginRead, which is actually the way it is used in the final code.

    The results are as follow:

    1. Same I/O Exception is thrown immediately when Read is called. ReadTimeout is verified to be -1 (infinite).
    2. It is a different exception that is thrown, one that indicates a timeout occured
    3. This works correctly, though the code is very ugly - it must be possible to avoid the polling.
    4. The callback is called immediately even when there is no data to read and the EndRead throws the same exception.

    The code for the async implementation is:

    IAsyncResult r = null;
    r = sp.BaseStream.BeginRead(t, 0, 1024, delegate(IAsyncResult ar)
    	{
    		int i3 = sp.BaseStream.EndRead(ar);
    		Console.WriteLine("Received: " + i3);
    	}, null);
    r.AsyncWaitHandle.WaitOne();


    When I ran test 2 on my computer I also got a timeout error. I then tried to change the timeout to 1 hour (3600000), but I get an instant timeout (same exception as on the other PC, but not the I/O Exception the Timeout exception).

    I must therefore be able to conclude that the problem is not with the serial port at all, but with the implementation of the timeout. This fits well with the polling success as the timing is never used if there is data to read.

    I would very much appreciate any help you can give me with respect to this problem in the Asynchronous part of the SerialStream implementation, and possibly a workaround that does not involve polling every 100ms.

    I have downloaded the ".NET Enhanced SerialPort" from your website and run the test with that one and I get exactly the same error, so I imagine that that the EnhancedSerialPort also use the SerialPort (or BaseStream Async read) and therefore suffer from the same problem.

    Thank you in advance.

    Thursday, April 4, 2013 7:51 AM
  • How many bytes does BytesToRead return before you attempt to do any reading of the port?
    Thursday, April 4, 2013 9:27 AM
  • You shouldn't have to use timeouts or aync method.  A serial port in therory should stay open forever and not give any errors.  The code you adding is a CLUDGE.  The root cause of the problem is you are getting an over run error in the operating system (or UART) because the PC is running slow or some process is blocking the program from reading the serial port.

    Try as an experiment putting the SEND to the serial port just before the read.  Also open the port just before the SEND to flush any old data that may be in the receive buffers.


    jdweng

    Thursday, April 4, 2013 9:34 AM
  • Thank you for your reply Joel and John. First John, I use the following code:

    while (true)
    {
      if (sp.BytesToRead > 0)
      {
        int i2 = sp.Read(t, 0, 1024);
        Console.WriteLine("Received: " + i2);
        break;
      }
      System.Threading.Thread.Sleep(100);
    }
    

    and this code do not fail, neither on my development PC or on other PC's, I am just not a big fan of polling if there is an asynchronous alternative.

    Joel, the design you do not like has worked perfectly for a long time and also it is the recommended way to read asynchronously from a stream in .NET 3.5 and older, as I understand it.

    If you have a suggestion for how to design the asynchronous read from a serial port I would be happy to read it. The application needs to monitor the serial port and if any data is received it need to give a call-back.

    Also, since the SerialPort is unable to support the ReadTimeout and instead report an instant timeout immediately after calling Read, regardless of what is written in ReadTimeout (other than -1), there must be a problem with ReadTimeout. What other purpose than awaiting data for a certain amount of time can the ReadTimeout have. And ReadTimeout is implemented in SerialPort, not in the BaseStream.

    I have experimented with adding a send just before the read, but the exception is the same as without the send.

    I look forward to hearing your proposal for a workaround and hopefully a more permanent solution to the problem with the asynchronous read

    Thursday, April 4, 2013 10:41 AM
  • I have nothing wrong with using the Async method and have used it plenty of times before to solve similar problems.  I don't like polling and adding timeouts which can cause other problems.  Also I don't like adding delays to solve problems.  My best guess know is something changed on the PC timing (like virus checker and other services) that isn't allowing the PC to keep up with the data 115200 data rate causing overflow errors.  The Synchronous read is blocking and should be able to handle the data rate.  What is really happening that after you send the command to the I/O device you aren't getting back to the UART fast enough to start reading the data before an overflow occurs.

    A serial port should be a master/slave interface.  You application should be the master and the I/O device shojld be the slave.  So your interface should look like the following

    PC - Master                                                                       I/O Device Slave

    Send Command followed by return   ---------------------->  Read to return and Process Command

    Read Response to return                 <--------------------   Send Response followed by return

    Send Command followed by return   ---------------------->  Read to return and Process Command

    Read Response to retuurn                 <--------------------   Send Response followed by return

    Send Command followed by return   ---------------------->  Read to return and Process Command

    Read Response to retuurn                 <--------------------   Send Response followed by return

    Your code is simply opening the interface and reading data.  The UART buffer isn't large enough to capture 1024 bytes of data and you end up with an overfolow.  the Master and Slave devices need to be synchronized and the return character makes sure the master and slave waits until all the data is received.  If you are sending binary data then instead of the return character you must send the byte count and read until all the data is received.


    jdweng

    Thursday, April 4, 2013 12:20 PM
  • Thank you Joel for the clarification. I have also come to the conclusion that something must have changed on the computer. I often work with UART drivers in embedded devices so I am not unfamiliar with the interface and real time requirements.

    My problem is how to identify what is wrong. What I know is that when I use the SerialPort.BaseStream.BeginReceive() with a timeout > 0 then the method times out immediately and an Exception is thrown when EndReceive is called. When I use SerialPort.Read then an I/O Exception is thrown if there is pending on the UART (in the OS UART buffer).

    I also know that if I use a polling approach where I every 100ms test if there is anything to read, and if so perform the read then the code works. 

    I also know that if I use a blocking read via unmanaged code (P/Invoke) then no exception occurs and the code works as expected.

    This tells me that the underlying win32 abstraction and the driver works correctly and it is something with the .NET implementation.

    I ran a test with a Socket (NetworkStream) where both blocking read and Asynchronous read works correctly, and I therefore believe that it is the SerialPortStream that is causing the problem. 

    If you still believe it is the underlying (native) UART implementation then why do the unmanaged code work correctly? If it is a timing issue with .NET why does the P/Invoke implementation work correctly? If it is a buffer overflow issue why does the .NET polling implentation work, it is a lot slower than blocking read, as data is only read every 100ms? Also, if it is an issue with the amount of data requested, why does the synchronous read when there is data to be read work just fine with a 1024 byte buffer, also when there is far less than 1024 bytes to be read?

    I have presently implemented a dual solution where a flag indicates if a polling or asynchronous approach should be used, so I can use a home-made SerialPortPollingStream on my developement PC, and the real implementation on all the other ones. 

    However this is not a solution, just a suppression of the symptoms, so I am very interested in finding out what the actual problem is. Any suggestions on how to debug this problem, or test to run to identify the cause are very welcome.

    Thank you in advance

    Tuesday, April 9, 2013 6:17 PM
  • Here are my opinions.

    1. You should not use Base Stream Async methods.  These add extra processing to do what is already available using the built-in serial port methods.  There can be reasons to move command/response off the UI thread, into a background thread (I have examples of this in my book), but often, you simply can do this in a loop in the UI thread.   Moving the protocol handling to a background thread does not improve raw communication performance.  However, it can improve overall application performance.  Such background processing comes at a cost -- it is more complex to code and debug, and threading has its own built-in overhead.
    2. Any speed higher than 9600 bps (and sometimes even at that speed) can demand that you employ hardware (RTS/CTS) handshaking/flowcontrol.  If you do not employ flowcontrol, you can experience data loss through Overrun, and RXOver errors (these two errors are distinct; one caused by insufficient buffering - ReadBufferSize being too small, and the other indicates a receive FIFO overrun -- the FIFO was not processed by the Windows serial port device driver before data was lost).  The likelihood of these errors depends on many things.  Hardware speed (CPU), processor load from system services and other application execution, and serial port device design.  Very high performance systems may demand hardware support, such as the deep receive FIFOs provided by some serial port hardware (FIFOs as deep as 256 bytes are available in hardware, and some enhanced USB serial port devices offer even deeper Virtual Serial Port FIFOs via a sophisticated device driver).
    3. The more complex your receive code, the more likely that you will experience hard-to-find performance issues.  You may need to step back and look at the design to tackle such issues.  Since a command/response protocol is, in essence, a polling process, you should not disdain the use of a looping mechanism to implement it.  Looping allows you to determine that a timeout failure has happened much more efficiently than any other implementation, both in raw speed, and reduced processor overhead.

    To reiterate, these are just my opinions. But, they are based on years of experience with a lot of production systems.

    While you are at it, double-check to make sure that the connected system has not changed in some critical way.  I've had the experience of thinking that application code was the source of a problem, when in fact, a system that had been running for years simply broke.  For example, if the connected system has a fault in its own serial port UART or associated drivers (hardware or software), you may spend a lot of time fixing the wrong problem.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Friday, April 12, 2013 5:03 PM
  • Thank you Dick for your opinions, which I agree with fully. 

    Unfortunately the issue with the serial port cannot be explained with the above, because:

    1 and 3. I can reproduce the problem with a simple console application containing only the code shown above, namely open the port and perform a blocking read with nothing attached to the serial port. Then the exception is thrown immediately. I do not use the BaseStream for this example (see beginning of thread). I have reproduce this on .NET 2.0, 3.5 and 4.0, but if I use unmanaged code (C++) and do the same then the program does as expected, it opens the port and blocks because there is nothing to read, as there is no connected system. 

    2. As there is no data to read the buffer cannot overflow.

    I think the problem is something with the underlying implementation of the .NET SerialPort. When I use the unmanaged CreateFile etc. it works. 

    My guess is that something on my computer has changed. Like when WireShark puts the Network card into promiscuous mode, maybe something has altered a setting for my serial port, causing it to fail in .NET (perhaps because .NET uses a functionality that the unmanaged code ignores). 

    I tried to look more at the SerialPort And SerialStream, but apart from the fact that it uses Async for everything when the OS version is different from PlatformID.Win32Windows, which apparently is XP. Looking further it can be seen that the exception seems to come from the native code with an hr of -2146232800 (0x80131620). Unfortunately I am unsure what this means. The HR (HRESULT) is found using Marshal.GetHRForException(ex).

    My guess is still a change in the win32 Serial Port configurations which results in an error in the .NET implementation of the Serial Port, perhaps because it uses some parameters that the simple native implementation I have tested ignores. 

    Any ideas what this error means or how to debug/fix it? The error seems to come from UnsafeNativeMethod.ReadFile which returns 0 and a GetLastWin32Error then return the error (which is OR'ed with -2147024896).

    Thank you in advance.

    Friday, April 12, 2013 6:48 PM