SerialPort and the BSOD - c#

I've written some C# code that checks whether a device is present on any SerialPort by issuing a command on the port and listening for a reply. When I just set the port speed, open the port, get the serial stream and start processing, it works 100% of the time. However, some of our devices work at different speeds and I am trying to probe for a device at various speeds to autonegotiate a connection as well as detect device presence.
When I do all this in a single thread there are no problems. However, 3s timeout at ten speeds is 30s per serial port, and there may be several. Hence the desire to probe all ports concurrently.
Sometimes this works. Sometimes Vista bluescreens. When I use threads to probe all the ports simultaneously it nearly always bluescreens. When I force everything to run in one thread it never happens.
A USB-serial Prolific PL-2303 adaptor is in use with x64 drivers.
#Vinko - thanks for the tip on reading minidumps.
As near as I can tell, the crux of the problem is that by starting a new asynchronous I/O operation from a different thread it is possible to give a whole new meaning to overlapped I/O, inducing a race condition inside the driver. Since the driver executes in kernel mode, BLAM!
Epilogue
Except for kicking off, don't use BeginXxx outside of the callback handler and don't call BeginXxx until you've called EndXxx, because you'll induce a race condition in driver code that runs in kernel mode.
Postscript
I have found that this also applies to socket streams.

Having written Windows drivers for one of these sort of device once, my advice would be not to waste your time with WinDbg trying to prove what you already know - i.e. that the driver you're using is buggy.
If you can find a more up-to-date driver from the PL2302, then try that, but my recommendation is that if you have to use USB->Serial adaptors, the FTDI-based ones are the best. (They're not the one I wrote the drivers for, either...)

You can also disable "Automatic Restart" under System Properties\Advanced\Start and Recovery\Settings. Once you disable that, you can see the BSOD and look for the error message, e.g. IRQL_LESS_OR_EQUAL, by searching for that error name, you can usually narrow down to the source of the problem.
Btw, not many notebook comes with serial ports nowadays, so you must be using USB-Serial converter? If that's the case, the driver might have been an issue to start with, since most manufacturer wrote the serial port driver as virtual driver.

BSOD usually means buggy drivers.
What kind of HW ports do you use? I've had BSODs with SiLabs CP21xx USB to Serial converters drivers.

There are FTDI drivers that are stable under x64 vista and win7. I second the person who said to use FTDI chipsets only.
Most of the cheap serial to usb dongles at the shops near me (Toronto, Canada) seem to be FTDI chips. It's never on the box, so I buy one, and if it's good, I go buy a box full of them.
W

Related

C# SerialPort System.ObjectDisposedException [duplicate]

I got a little problem with a USB Barcode Scanner.
I am using the Scanner with the "SerialPort" class:
this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 };
this._barcodeScanner.Open();
this._barcodeScanner.DataReceived += BarcodeScannerCallback;
If I unplug the USB Device while it´s opened via the "SerialPort" class, I can´t close the software properly and the virtual port stays open for all eternity or till I reboot the whole computer.
So my question is, is there any way to close the virtual port after I unplugged the device via C# code?
Greetings
[edit #1]
Alrighty, some more code:
This way I am checking every 10 seconds if the device is plugged in:
private bool CheckUsbDeviceAvailability()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'");
if (searcher.Get().Count > 0)
return true;
return false;
}
Thats the Callback-Event of the Serial Port:
void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim();
if (data.StartsWith("AX"))
{
string[] arrData = data.Split('\n');
this._barcodeScanner.StopAvailabilityThread();
Barcode code = new Barcode(arrData[0].Replace("\r", ""));
if (CheckIfBarcodeExists(code))
this.UpdateBarcodeNode(code);
else
this.CreateBarcodeNode(code);
BarcodeScannerCallbackEvent(sender, e, code);
this._barcodeScanner.StartAvailabilityThread();
}
this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available;
}
if it doesnt answer anymore it will fire the "DeviceNotAvailableEvent()":
void BarcodeScannerDeviceNotAvailableEvent()
{
this._barcodeScanner.Close();
this._barcodeScanner.Dispose();
}
I have overriden the Dispose Event of the "SerialPort" class so that it´s going to abort the Thread:
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
this._deviceAvailableThread.Abort();
}
base.Dispose(isDisposing);
}
Serial ports date from the stone age of computing. That's where you plugged in your ASR-33 teletype to start typing in your Fortran program. The electrical interface is very simple. So is the Windows API to use a serial port from your own code. Practically any runtime environment supports them.
USB has replaced serial port hardware completely. It has a much more advanced logical interface to the machine, supporting many different type of devices. And it supports Plug and Play, allowing the operating system to detect when a device is attached or removed as well as automatically installing the device driver, etcetera.
This flexibility comes at a price however, a USB device always needs a device driver to become usable. Device drivers are not created equal. Different drivers require different ways to talk to the device. Usually done through DeviceIoControl() or Read/WriteFile() but those are very opaque API functions. In the early days of USB, device manufacturers would supply a DLL that provided a rich API to hide the implementation details.
That did not work so well, manufacturers are not very good at writing good APIs and they sure don't like to support them. So a good solution would be to support a standard API, one that's available on any machine, supported by any runtime, documented and maintained by somebody else. Like the serial port API.
That did not work so well, manufacturers are not very good at writing device drivers that emulate serial ports. The biggest hang-up with the API is that it doesn't have any support for Plug and Play. The core support for it is missing, after all serial port hardware doesn't have the logical interface to support it. There is some support for detecting that a device is attached through the DTR hardware handshake line, but no support whatsoever for detecting that the port is no longer there.
Detaching the USB device is the problem. In an ideal world, the emulator built into the device driver would simply pretend that the serial port is still there until the last handle on the device is closed. That would be the logical implementation, given that there's no way to trigger a Plug and Play event. For some strange reason that seems to be difficult to implement. Most USB drivers take the crummy shortcut, they simply make the device disappear even while it is in use.
This plays havoc on any user mode code that uses the device. Which is typically written to assume it is a real serial port and real serial ports don't suddenly disappear. At least not without drawing a bright blue spark. What goes wrong is pretty unpredictable because it depends on how the driver responds to requests on a device that's no longer there. An uncatchable exception in a worker thread started by SerialPort was a common mishap. Sounds like your driver really gets it wrong, it generates an error return code on the MJ_CLOSE driver request. Which is kind of a logical thing to do for a driver, after all the device isn't there anymore, but quite unsolvable from your end. You have a handle and you can't close it. That's up a creek with no paddle.
Every major release of .NET had a small patch to the SerialPort classes to try to minimize the misery a bit. But there's a limited amount that Microsoft can do, catching all errors and pretending they didn't happen ultimately leads to class that provides no good diagnostic anymore, even with a good driver.
So practical approaches are:
always use the Remove Hardware Safely tray icon in Windows
use the latest version of .NET
contact the vendor and ask for a driver update
ditch vendors that supply lousy drivers
tell your users that, just because it is the only thing you can do with a USB device, that unplugging it doesn't solve any problems
make closing the port easy and accessible in your UI
glue the USB connector to the port so it can't be removed
The 5th bullet is also what gets programmers in trouble. Writing serial port code isn't easy, it is heavily asynchronous and the threadpool thread that runs the DataReceived event is difficult to deal with. When you can't diagnose the software problem you tend to blame the hardware. There's very little you can do with the hardware but unplug it. Bad Idea. Now you have two problems.
This Problem Exists in .Net 2 , 3 , 3.5 you can use framework 4 (problem does not exist in .net 4)

Low priority threads get blocked. Win CE

I am working on a application which uses serial port communication via USB to Serial cable, which uses FTDI driver.
My application has multiple threads, with different priorities.
Now the issue I am seeing is, when I connect/disconnect the cable, I have seen that the application's threads, whose priority is less than Normal, will be stuck, and will not respond, where as the normal priority threads will keep on working.
Now the questions are:
Is it possible to keep the low priority threads running.
If not, then is it possible to recover from this situation, by restoring the serial port. I have seen, that even if I try to recover the serial port from the high priority thread, then also the low priority threaeds will not start functioning.
Are you running with the latest version of the FTDI driver? The 1.1.0.20 release has fixes for "surprise removal".
If that doesn't fix your problem, then try breaking in to the application with the debugger or by writing a kdmp. See what threads in the system are actively running. If the thread that's blocking you is in the USB driver you may need to contact the manufacturer of your device and ask for an update.

What can cause a GPIB to be unresponsive

I have a GPIB device that I'm communicating with using a National Instruments USB to GPIB. the USB to GPIB works great.
I am wondering what can cause a GPIB device to be unresponsive? If I Turn off the device and turn it back on it will respond, but when I run my program it will respond at first. It then cuts off I can't even communicate with the GPIB device it just times out.
Did I fill up the buffer?
Some specifics from another questioner
I'm controlling a National Instruments GPIB card (not USB) with PyVisa. The instrument on the GPIB bus is a Newport ESP300 motion controller. During a session of several hours (all the while sending commands to and reading from the ESP300) the ESP300 will sometimes stop listening and become unresponsive. All reads time out, and not even *idn? produces a response.
Is there something I can do that is likely to clear this state? e.g. drive the IFC line?
Since you are using National Instruments hardware you can run NI Trace in the background to check all the commands that is send out from the Program. In the Trace do check the last command and its parameters that is send out from the program that causes the hardware to hang.
You can download NI IO Trace here
There should be a clear command (something like "*CLS?", but dont quote me on that). I always run that when i first connect to a device. Then make sure you have a good timeout duration. I found for my device around 1 second works. Less then 1 second makes it so I miss the read after a write. Most of the time, a timeout is because you just missed it or you are reading after a command without a return. Make sure you are also checking for errors in the error queue in between write to make sure the write actually properly when through.
Even the command *CLS will not work if the device is not listening anymore (which might be the case here). The only way to force resetting the device's interface whatever its status (listening or not) is to send the low-level gpib bus message "Selected Device Clear" (it is implemented by the function "ibclr" of the standard gpib library, e.g. https://www.l-com.com/multimedia/manuals/M_USB-488.PDF page 3-7, but I don't know what is the equivalent in Python). This command is intended to be used whenever a GPIB error occurs, I'm always doing it and never had problems. For this to work well you should also monitor the return values of all gpib calls - usually people don't do it so they are unaware of errors until the program hangs.

C# COM port communication - errors with a USB to Serial Adapter

Here's the scenario - I have a C# application that reads from a COM port. Most of the time I use devices with a serial adapter and on a machine with a serial ports. However, machines with serial ports are increasingly difficult to come by so I have started using machines with a USB/Serial connection.
In some cases, the C# code that I have will work just fine with a "true" serial connection but fail with a USB/serial connection. The data comes in fragmented with the first part of the data coming in (like maybe the first 1 or 2 characters) and nothing else.
I'm using something basic like comport.ReadExisting() to pick up the data from the port. Is this part of the problem? Are there other methods that would guarantee that all the data would be read in a single string?
Finally, I want to add that I've already played around with some of the USB/serial settings in device manager AND the data comes in fine when using good, ole' hyperterminal . . . so it has to be something in the code.
With USB-serial converters, you MUST set your receive timeout, because the data can sit in the USB device for a long time where Windows doesn't know about it. Real serial ports hold data in the 16550 FIFO where the Windows driver can see it.
Most of the times you would want to use the SerialPort.DataReceived event ( http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx ).
This requires you to combine the chunks of data manually since you can receive parts of your string, but once you detect the boundary of a single 'record' you can fire of processing that record while letting the IO receive more events.
This allows some asynchronous IO which doesn't block your threads, and thus allows more efficient handling of the data in general. If it helps in your specific situation I don't know, but it has helped me in the past dealing with data reading issues, low speeds, thread pooling, and lock-ups.

How do I force a serial port write method to wait for the line to clear before sending its data?

Here's some background on what I'm trying to do:
Open a serial port from a mobile device to a Bluetooth printer.
Send an EPL/2 form to the Bluetooth printer, so that it understands how to treat the data it is about to receive.
Once the form has been received, send some data to the printer which will be printed on label stock.
Repeat step 3 as many times as necessary for each label to be printed.
Step 2 only happens the first time, since the form does not need to precede each label. My issue is that when I send the form, if I send the label data too quickly it will not print. Sometimes I get "Bluetooth Failure: Radio Non-Operational" printed on the label instead of the data I sent.
I have found a way around the issue by doing the following:
for (int attempt = 0; attempt < 3; attempt++)
{
try
{
serialPort.Write(labelData);
break;
}
catch (TimeoutException ex)
{
// Log info or display info based on ex.Message
Thread.Sleep(3000);
}
}
So basically, I can catch a TimeoutException and retry the write method after waiting a certain amount of time (three seconds seems to work all the time, but any less and it seems to throw the exception every attempt). After three attempts I just assume the serial port has something wrong and let the user know.
This way seems to work ok, but I'm sure there's a better way to handle this. There are a few properties in the SerialPort class that I think I need to use, but I can't really find any good documentation or examples of how to use them. I've tried playing around with some of the properties, but none of them seem to do what I'm trying to achieve.
Here's a list of the properties I have played with:
CDHolding
CtsHolding
DsrHolding
DtrEnable
Handshake
RtsEnable
I'm sure some combination of these will handle what I'm trying to do more gracefully.
I'm using C# (2.0 framework), a Zebra QL 220+ Bluetooth printer and a windows Mobile 6 handheld device, if that makes any difference for solutions.
Any suggestions would be appreciated.
[UPDATE]
I should also note that the mobile device is using Bluetooth 2.0, whereas the printer is only at version 1.1. I'm assuming the speed difference is what's causing the printer to lag behind in receiving the data.
Well I've found a way to do this based on the two suggestions already given. I need to set up my serial port object with the following:
serialPort.Handshake = Handshake.RequestToSendXOnXOff;
serialPort.WriteTimeout = 10000; // Could use a lower value here.
Then I just need to do the write call:
serialPort.Write(labelData);
Since the Zebra printer supports software flow control, it will send an XOff value to the mobile device when the buffer is nearly full. This causes the mobile device to wait for an XOn value to be sent from the printer, effectively notifying the mobile device that it can continue transmitting.
By setting the write time out property, I'm giving a total time allowed for the transmission before a write timeout exception is thrown. You would still want to catch the write timeout, as I had done in my sample code in the question. However, it wouldn't be necessary to loop 3 (or an arbitrary amount of) times, trying to write each time, since the software flow control would start and stop the serial port write transmission.
Flow control is the correct answer here, and it may not be present/implemented/applicable to your bluetooth connection.
Check out the Zebra specification and see if they implement, or if you can turn on, software flow control (xon, xoff) which will allow you to see when the various buffers are getting full.
Further, the bluetooth radio is unlikely to be capable of transmitting faster than 250k at the maximum. You might consider artificially limiting it to 9,600bps - this will allow the radio a lot of breathing room for retransmits, error correction, detection, and its own flow control.
If all else fails, the hack you're using right now isn't bad, but I'd call Zebra tech support and find out what they recommend before giving up.
-Adam
The issue is likely not with the serial port code, but with the underlying bluetooth stack. The port you're using is purely virtual, and it's unlikely that any of the handshaking is even implemented (as it would be largely meaningless). CTS/RTS DTR/DSR are simply non-applicable for what you're working on.
The underlying issue is that when you create the virtual port, underneath it has to bind to the bluetooth stack and connect to the paired serial device. The port itself has no idea how long that might take and it's probably set up to do this asynchronously (though it would be purely up to the device OEM how that's done) to prevent the caller from locking up for a long period if there is no paired device or the paired device is out of range.
While your code may feel like a hack, it's probably the best, most portable way to do what you're doing.
You could use a bluetooth stack API to try to see if the device is there and alive before connecting, but there is no standardization of stack APIs, so the Widcom and Microsoft APIs differ on how you'd do that, and Widcom is proprietary and expensive. What you'd end up with is a mess of trying to discover the stack type, dynamically loading an appropriate verifier class, having it call the stack and look for the device. In light of that, your simple poll seems much cleaner, and you don't have to shell out a few $k for the Widcom SDK.

Categories