Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do robust SerialPort programming with .NET / C#?

I'm writing a Windows Service for communication with a Serial Mag-stripe reader and a relay board (access control system).

I run into problems where the code stops working (i get IOExceptions) after another program has "interrupted" the process by opening the same serial port as my service.

Part of the code is as follows:

public partial class Service : ServiceBase {     Thread threadDoorOpener;     public Service()     {         threadDoorOpener = new Thread(DoorOpener);     }     public void DoorOpener()     {         while (true)         {             SerialPort serialPort = new SerialPort();             Thread.Sleep(1000);             string[] ports = SerialPort.GetPortNames();             serialPort.PortName = "COM1";             serialPort.BaudRate = 9600;             serialPort.DataBits = 8;             serialPort.StopBits = StopBits.One;             serialPort.Parity = Parity.None;             if (serialPort.IsOpen) serialPort.Close();             serialPort.Open();             serialPort.DtrEnable = true;             Thread.Sleep(1000);             serialPort.Close();         }     }     public void DoStart()     {         threadDoorOpener.Start();     }     public void DoStop()     {         threadDoorOpener.Abort();     }     protected override void OnStart(string[] args)     {         DoStart();     }     protected override void OnStop()     {         DoStop();     } } 

My sample program successfully starts the work-thread, and the opening/closing and raising of DTR causes my Mag-stripe reader to power up (wait 1sec), shut down (wait 1 sec) and so on.

If I launch HyperTerminal and connects to the same COM port, HyperTerminal tells me the port is currently in use. If i repeatedly press ENTER in HyperTerminal, to try to reopen the port it will succeed after a few retries.

This has the effect of causing IOExceptions in my work-thread, which is expected. However, even if I close down HyperTerminal, i still get the same IOException in my work-thread. The only cure is actually to restart the computer.

Other programs (which is not using .NET libraries for port-access) seem to work normally at this point.

Any ideas as to what is causing this?

like image 484
Thomas Kjørnes Avatar asked Jan 14 '09 01:01

Thomas Kjørnes


2 Answers

@thomask

Yes, Hyperterminal does in fact enable fAbortOnError in SetCommState's DCB, which explains for most of the IOExceptions thrown by the SerialPort object. Some PCs / handhelds also have UARTs that have the abort on error flag turned on by default - so it's imperative that a serial port's init routine clears it (which Microsoft neglected to do). I wrote a long article recently to explain this in greater detail (see this if you're interested).

like image 124
Zach Saw Avatar answered Sep 22 '22 15:09

Zach Saw


You can't close someone elses connection to a port, the following code will never work:

if (serialPort.IsOpen) serialPort.Close(); 

Because your object didn't open the port you can't close it.

Also you should close and dispose the serial port even after exceptions occur

try {    //do serial port stuff } finally {    if(serialPort != null)    {       if(serialPort.IsOpen)       {          serialPort.Close();       }       serialPort.Dispose();    } } 

If you want the process to be interruptible then you should Check if the port is open and then back off for a period and then try again, something like.

while(serialPort.IsOpen) {    Thread.Sleep(200); } 
like image 39
trampster Avatar answered Sep 24 '22 15:09

trampster