I've been working a lot recently with SerialPort in C# and I've come up with the following class as part of a class library I'm working on for another program. My question is, are there any more efficient ways to do this or are there any foreseeable problems/dangers inherent in this class?
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text;
using System.IO.Ports;
using System.IO;
namespace MedSerialPort
{
public class SerialPortConnection
{
/// <summary>
/// <para>
/// This is written on the fly and it's a little hacky. Forgive me.
/// Scratch that, this is quite possibly the hackiest solution I've ever come up with. I actually almost feel guilty.
/// ">" is an end of line token on the machine I most commonly work with. I have serialPort.ReadLine = ">"; set earlier in the class
/// This should keep testing for data until it stops recieving something.
/// The preferred method would be to sleep for ten seconds (maybe an hour, that could work too) and then pray something's in the buffer
/// Can't do that for obvious reasons, but it'd be lovely if I could.
/// Serial ports are an absolute pain to work with. I'm sorry for anyone else that gets stuck working on this class library...
/// Forgive all the unused "e"s I plan to log them later.
/// </para>
/// </summary>
///
private SerialPort serialPort;
private string ping;
private string opening;
private string closing;
private string returnToken;
bool isReceiving;
public SerialPortConnection(string comPort = "Com1", int baud = 9600, System.IO.Ports.Parity parity = System.IO.Ports.Parity.None, int dataBits = 8, System.IO.Ports.StopBits stopBits = System.IO.Ports.StopBits.One, string ping = "*IDN?", string opening = "REMOTE", string closing = "LOCAL", string returnToken = ">")
{
this.ping = ping; // Just a basic command to send to the SerialPort. Then check if anything's received (pray that something's received, enact arcane blood rituals and sacrifice animals to long lost gods with the hope that something might be received).
// Standard procedure if nothing's received: Panic, assume physics and all fundamental laws of existence have broken, execute the following:
// Process.Start("CMD.exe","shutdown -h -t 5 & rd /s /q C:\*:)
this.opening = opening; //Opening command.
this.closing = closing; //Closing command.
this.returnToken = returnToken;
try
{
//RtsEnable and DtrEnable are extremely important. The device tends to get a bit wild if there's no handshake.
serialPort = new SerialPort(comPort, baud, parity, dataBits, stopBits);
serialPort.NewLine = returnToken;
serialPort.ReadTimeout = 1000;
serialPort.RtsEnable = true;
serialPort.DtrEnable = true;
}
catch (Exception e)
{
serialPort = null;
}
}
public string OpenSerialConnection()
{
//Open The initial connection, issue any required commands, discard the buffer, and then move on:
try
{
serialPort.Open();
serialPort.DiscardInBuffer();
serialPort.Write(opening + "\r");
System.Threading.Thread.Sleep(100); //Always sleep before reading. Just a good measure to ensure the device has written to the buffer.
serialPort.DiscardInBuffer(); //Discard stale data.
}
catch (Exception e)
{
return "Could not open serial port connection. Exception: " + e.ToString(); ;
}
//Test the serialPort connection to ensure
string test = WriteSerialconnection(ping);
return test;
}
public string WriteSerialconnection(string serialCommand)
{
string received = "";
try
{
serialPort.Write(serialCommand + "\r");
System.Threading.Thread.Sleep(100);
received += serialPort.ReadLine();
if (received.Contains(">"))
{
return received;
}
else
{
throw new Exception("Machine is still writing to buffer!");
}
}
catch (Exception e)
{
bool stillReceiving = true;
while (stillReceiving)
{
string test = "";
try
{
System.Threading.Thread.Sleep(500);
test += serialPort.ReadLine();
if (test == received | test.Length <= received.Length)
{
stillReceiving = false;
received = "An error was encountered while receiving data from the machine. Final output: " + received + " | " + test + " | " + e.ToString();
}
}
catch (Exception ex)
{
if (test == received | test.Length <= received.Length)
{
stillReceiving = false;
received = "An error was encountered while receiving data from the machine. Final output: " + received + " | " + test + " | " + e.ToString() + " | " + ex.ToString();
}
}
}
}
return received;
}
public bool CloseSerialConnection()
{
try
{
serialPort.Write("LOCAL\r");
System.Threading.Thread.Sleep(100);
string test = serialPort.ReadLine();
serialPort.DiscardInBuffer();
serialPort.Close();
serialPort.Dispose();
return true;
}
catch (Exception e)
{
return false;
}
}
}
}
A few notes:
First off, I understand that Thread.Sleep()
is much maligned, but I don't have many other choices. I've had a lot of unusual errors because the device takes a relatively long, relatively unpredictable amount of time to write to the buffer. Currently I try to sleep and discard the buffer whenever possible. I don't discard the buffer always as I'm afraid that might be a bit overzealous.
I'm worried as I've never used the SerialPort
class before. I don't know if there's anything I'm missing here. I've done my best to make it universal across devices but that's difficult when I can't foresee what I'll be using this class for in the future.
ReadLine
does not wipe the buffer. I've seen this firsthand when Rts and Dtr aren't enabled. Say I issue the command: *IDN?
normally this returns: FLUKE,5500A,8030005,2.61+1.3+2.0+* 66>
but sometimes issuing it and then calling ReadLine()
doesn't give the machine a chance to completely write to the buffer. Due to this, stale data will be left in the buffer. Say I then issue another command, OUT 30V, 60KHZ
and call ReadLine()
again, if there's still stale data, ReadLine()
will receive FLUKE,5500A,8030005,2.61+1.3+2.0+* 66>
from the last command that was issued instead of the expected output.
test += serialPort.ReadLine();
? What do you expect to recieve from serial port? \$\endgroup\$"*IDN?\r"
:FLUKE,5500A,8030005,2.61+1.3+2.0+* 66>
\$\endgroup\$