Unknown Error?

Dec 10, 2013 at 5:02 PM
With a new Bluetooth GPS, I am encountering some unknown errors when I try to open the serial port that is outputting NMEA sentences.

After the .createFile call in the Open method, when the handle is found to be invalid, the WinIOError method is called (see below). The errors I am encountering and returned by Marshal.GetLastWin32Error() are numbered 1008 and 121. Neither of these are handled explicitly in this method and so I am wondering what they actually indicate?

From googling, I found the following list:
http://msdn2.microsoft.com/en-us/library/ms681381.aspx

Which indicates that a 1008 error is:
ERROR_NO_TOKEN1008 (0x3F0)
An attempt was made to reference a token that does not exist.

and a 121 error is:
ERROR_SEM_TIMEOUT121 (0x79)
The semaphore timeout period has expired.

What can I do to avoid these errors?
           private void WinIOError()
            {
                int e = Marshal.GetLastWin32Error();

                switch (e) {
                case 2:
                case 3:
                    throw new IOException("Port not found: " + m_Port, e);
                case 5:
                    throw new UnauthorizedAccessException("Access Denied: " + m_Port);
                case 32:
                    throw new IOException("Sharing violation: " + m_Port, e);
                case 206:
                    throw new PathTooLongException("Path too long: " + m_Port);
                }
                throw new IOException("Unknown error 0x" + e.ToString("X") + ": " + m_Port, e);
            }
Coordinator
Dec 10, 2013 at 6:23 PM
So I assume this is the code that is dying:
    public partial class SerialPortStream {
        private sealed partial class NativeSerialPort : IDisposable {
            public void Open() {
                ...
                m_ComPortHandle = UnsafeNativeMethods.CreateFile(@"\\.\" + m_Port,
                    NativeMethods.FileAccess.GENERIC_READ | NativeMethods.FileAccess.GENERIC_WRITE,
                    NativeMethods.FileShare.FILE_SHARE_NONE, 
                    IntPtr.Zero,
                    NativeMethods.CreationDisposition.OPEN_EXISTING,
                    NativeMethods.FileAttributes.FILE_FLAG_OVERLAPPED,
                    IntPtr.Zero);
                if (m_ComPortHandle.IsInvalid) WinIOError();
                ...
            }
        }
    }
Have you tried to connect using a terminal program, such as TeraTerm or ZOC for confirmation?

1008 = I don't use tokens in the code. (from stackoverflow) The code ERROR_NO_TOKEN generally means that someone has attempted to call OpenThreadToken on a thread that was not impersonating. Check the bluetooth connection with another terminal program first.

121 = I don;t use named pipes, nor am I using sockets which could result in this error. I suspect your bluetooth driver is reporting this error because it might not be able to connect to the remote device.

I've not tested the SerialPortStream on bluetooth devices, and I've not seen these errors on local USB2SER adapters (FTDI, PL2303), or virtual com ports (com0com).

I confirmed in code that I'm correctly defining CreateFile:
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern SafeFileHandle CreateFile(
Important is the "SetLastError=true" so this is being set by the Windows subsystem (and likely the driver for the bluetooth RFCOMM device).

Regards,
Jason.
Dec 10, 2013 at 7:31 PM
Again, thanks for the speedy reply.

I think you are correct wrt it being the Bluetooth drivers.... Mostly because I have also tried to open the same port around the same time using Putty.

So, I am suspecting that my test program may be causing the problem by not actually closing the serial port gracefully. Is there a known time after which the serial port resets if it is not connected. I ask because I try over and over again to start the test program and then suddenly I am able to connect again. It would be nice to know if there is some other timeout or something that I can tweak.

To keep testing I ended up adding a ConsoleCancelEventHandler to my code so that I could control the exit from the do..while loop and gracefully close the port. HEre is a snippet:
        public static void SerialPortStream_WriteReadLine_Multilines()
        {
            using (SerialPortStream src = new SerialPortStream(c_SourcePort, 9600, 8, Parity.None, StopBits.One))
            {
                src.ReadTimeout = c_Timeout;
                Console.WriteLine("About to open serial port: " + c_SourcePort);
                src.Open(); 

                bool err = false;

                string s;
                s = src.ReadLine();
                do
                {
                    try
                    {
                        s = src.ReadLine();
                        Console.WriteLine(": " + s);
                    }
                    catch (System.Exception e)
                    {
                        if (e is TimeoutException) err = true;
                    }

                    if (_cancelled) break;

                } while (s.Length > 0);

                Console.WriteLine("About to close serial port: " + c_SourcePort);
                src.Close();

            }
        }
My next goal is to feed this as a BufferedStream to my nmea parser.

Cheers
Coordinator
Dec 10, 2013 at 7:54 PM
Hi, I would suggest setting the read timeout to 3x that of the times between receiving NMEA sentences (e.g. to 3000ms). This is just a rule of thumb, if the GPS connection breaks, hopefully the parser will abort with an exception when no data arrives for three seconds (but that's depending on the parser).

You don't need to have "src.Close()" as you're using a "using" statement, which will automatically close the serial port when it goes out of scope (that's because Close() is called from within Dispose()). The Close() statement could be used, so that you can call Open() afterwards again (but that doesn't work after calling Dispose()).

When you call Close(), it stops the internal I/O thread (and waits that it is actually stopped) and actually closes the handle via the SafeFileHandle.Close() method. In the background, this calls CloseHandle() from Win32API. So any delays between closing and opening again might be specific to your Bluetooth RFCOMM drivers.

I can only suggest that when opening, you catch errors, sleep 1000ms, and try again. If it's unsuccessful after say 10s, then abort.

You set "err = true", but you don't use this, what about using "err" as the exit condition for your do.. while loop?

Regards,
Jason.
Marked as answer by jmcurl on 12/14/2014 at 3:51 AM
Dec 12, 2013 at 3:47 PM
Thanks for the feedback. I have the parser successfully reading the stream now and it seems stable.

Cheers