Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Enhanced Serial Port

3.13/5 (6 votes)
6 Apr 2012CPOL1 min read 42.3K  
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.  

C#
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
        
    }
}    

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)