Enhanced Serial Port






3.13/5 (6 votes)
Take away the burden of manually configuring the available serial ports on your code or on the side of the users of your app.
Introduction
The EnhancedSerialPort
class is inherited from WinForm component, "SerialPort". When you use this class you are taking away the burden
of manually selecting the available serial ports on your code or on the side of the users of your app, and assures that your device is connected to an available serial port in your PC, thereby making your serial port device plug and play. This is very useful when you are developing a system which utilizes multiple serial ports or a serial port hub to manage available ports programmatically. You can also inherit this class and override its OnDataReceived
and OnPinChanged
event handler methods.
Background
Although nowadays, USB is the common communication interface of PCs, unlike "parallel" port or LPT, the legacy RS232 serial port or COM is still around. You could still find the serial port on new motherboards that supports intel iX series processors. Many devices specially industrial equipments still use the RS232 serial port as their communication interface. That is why there are USB-To-Serial Port converters and PCI-To-Serial Port cards in the market. There are also virtual serial ports which rides over USB and Serial Port Hubs which lets you have over 16 serial ports to one USB interface. You may search using Google if you want to know more about the basics of serial port.
Using the Code
Below is the code. You may use it in a separate library (DLL) project folder or with your own Visual Studio project folder.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.ComponentModel;
using System.Threading;
namespace EnhancedSerialPort
{
/// <summary>
/// The EnhancedSerialPort is the class that is derived from MS SerialPort class.
/// It listes all available serial ports of the computer.
/// And it automatically assigns the first available port. to itself.
/// By: Lemuel Adane
/// Created: June 15, 2011
/// </summary>
public class EnhancedSerialPort : SerialPort
{
#region Variables
// data read parameters
protected string _dataRead = null;
// declare and instantiate a list for available ports
List<string> _availablePorts = new List<string>();
// connection flag
protected bool _connected;
// flag that data is in the received buffer
bool _isReceived = false;
#endregion
#region Properties
/// <summary>
/// Property that returns string read from serial ports.
/// </summary>
public string DataRead { get { return _dataRead; } }
/// <summary>
/// Property that returns all the available ports.
/// </summary>
public List<string> AvailablePorts
{
get
{
return _availablePorts;
}
}
/// <summary>
/// Property which sets and gets the command to retrieve the device Id from the device.
/// </summary>
public string DeviceIdCommand { get; set; }
/// <summary>
/// Will serve as the device's ID reference
/// </summary>
public string DeviceId { get; set; }
#endregion
#region Constructors
public EnhancedSerialPort() : base()
{
InitializeComponent();
}
public EnhancedSerialPort(IContainer container) : base(container)
{
InitializeComponent();
}
#endregion
#region Methods
public void InitializeComponent()
{
//sets the read and write timeout to 5 seconds
base.WriteTimeout = base.ReadTimeout = 5000;
// if a port is available assigns the first available port to your device.
if (GetAvailablePorts().Count > 0)
base.PortName = _availablePorts[0];
this.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(
this.OnDataReceived);
this.PinChanged +=
new System.IO.Ports.SerialPinChangedEventHandler(
this.OnPinChanged);
}
/// <summary>
/// The method that filters all the available ports which are not taken by some devices
/// </summary>
private List<string> GetAvailablePorts()
{
//SerialPort.GetNames() method gets all specified serial ports from your computer.
foreach (string port in SerialPort.GetPortNames())
{
base.PortName = port;
try
{
// check if port is open and close it.
if (base.IsOpen)
base.Close();
base.Open();
_availablePorts.Add(base.PortName);
base.Close();
continue;
}
catch (System.IO.IOException ioError)
{
if (ioError.Message.EndsWith("does not exist."))
continue;
}
catch (System.UnauthorizedAccessException uax)
{
if (uax.Message.EndsWith("is denied."))
continue;
}
}
if (_availablePorts.Count == 0)
throw new NoSerialPortAvailableError();
return _availablePorts;
}
/// <summary>
/// The method that initiate the handshake between your PC and your device.
/// </summary>
public bool CheckConnection()
{
if (!base.IsOpen)
{
foreach (string port in AvailablePorts)
{
if (base.IsOpen) base.Close();
base.PortName = port;
try
{
if (!base.IsOpen) base.Open();
}
catch (System.UnauthorizedAccessException uax)
{
if (uax.Message.EndsWith("is denied."))
continue;
}
// Retrieves the device ID
base.Write(DeviceIdCommand);
//wait for sometime
for (int i = 0; i < 10 && !_isReceived; i++)
{
Thread.Sleep(50);
}
_isReceived = false;
// Check if the device id is right, if it is declare it is connected to the
// right device
if (_dataRead != null)
if (_dataRead.Equals(DeviceId))
{
_connected = true;
return true;
}
_connected = false;
}
}
if (!_connected) throw new DeviceCommunicationError();
return _connected;
}
#endregion
#region Event Handler Methods
protected virtual void OnDataReceived(
object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
_dataRead = ReadLine();
}
protected virtual void OnPinChanged(
object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
if (e.EventType == SerialPinChange.CDChanged)
{
}
else if (e.EventType == SerialPinChange.CtsChanged)
{
}
else if (e.EventType == SerialPinChange.DsrChanged)
{
}
}
#endregion
#region Exceptions
/// <summary>
/// Exception thrown when there is no available ports detected.
/// </summary>
public class NoSerialPortAvailableError : Exception
{
public override string Message
{
get
{
return "No serial port available.";
}
}
}
/// <summary>
/// Exception thrown when the handshake fails.
/// </summary>
public class ConnectionError : Exception
{
public override string Message
{
get
{
return "Disconnected or cannot connect to the device.";
}
}
}
#endregion
}
}