Archive

Posts Tagged ‘SerialPort’

Serial Port Programming Part 2 – Developing a GUI to set the Port Settings and validating the data

December 22, 2011 1 comment

As promised the next instalment is on how to build the GUI elements needed to manage the settings for your serial port. The updated code for this entry is here.

Validating data for ComPort settings is a fairly easy process but slightly different depending on the setting you’re working with.  There are many different ways, the two most commonly used are to validate at the class level and the other is to validate at the user interaction level. There are many arguments for both, for validating at the GUI level it’s simple, it’s easier to prevent the user from entering anything they want rather then checking every setting many different ways. For validating at the class level there’s the argument that if you re-use your code you have to keep re-entering the validation for the settings every time you design a new program. Both arguments are equally valid.

What I decided to do in this example is to create highly restrictive controls and place them in the same library as my serial port class. That way I don’t have to re-do the validation every time I draw a new GUI and it’s easier to restrict the user then to validating any data they enter.

Before we continue a few comments about creating your own controls. In many cases it’s not as hard as most people assume it is to create your own controls and it saves you a tonne of time. I only have two criteria to create a new control class; a) am I going to re-use it more then once in this project or b) do I think I’ll need it in the future. In the case of the serial port class, I think I’ll use it in the future again and it’ll take about as long to create a re-usable control as it would to just add it to the form now and set up the restrictions.

The first settings (and easiest) is Port Name. On every computer there’s a different number of ports and with differed names. When possible you want to limit the user to what they could enter. The best way to display a series of values and have a user select one is the ComboBox Class. I want to create a combo box and load in the available port settings. I also want to make sure that I select one, if there’ isn’t one select the user may just type one themselves. The first step is to inherit from the ComboBox class.  You may note in the class below I didn’t implement a constructor and I decided to put the load statements in the OnCreateControl method (lines 3 – 13). The reason for that is that the Constructor of a control also gets called during design time. In order to avoid effecting my design environment I added the methods I needed when the Control is created. When inheriting from a control, instead of tying into a particular event it’s best to override the OnEvent methods. These methods are what triggers the events, for example when the Button Click event is fired it’s actually the OnClick method that’s firing the event. The other line to note is 6. I’m not sure what methods are called when creating the control in design time, so in order to avoid any problems I enclose the functional parts of the method in an if statement. Finally it’s just a matter of loading the resulting strings from SerialPort.GetPortNames() into the combo box items and selecting the first one.

 1: public class ComPortComboBox : ComboBox
 2:     {
 3:         protected override void OnCreateControl()
 4:         {
 5:             this.Items.Clear();
 6:             if (!this.DesignMode)
 7:             {
 8:                 this.Items.AddRange(SerialPort.GetPortNames());
 9:                 this.SelectedIndex = 0;
 10:             }
 11:  
 12:             base.OnCreateControl();
 13:         }
 14:     }

Then next step is to have a look at the BaudRate. BaudRate setting expects an integer, but it can’t be any integer. For example if the user enters 0 or 2 it will not be a valid baud rate. The other setting that fits that criteria is the DataBits. Since there are two settings that fit this criteria I will first create an abstract class that manages the user interaction then create one specific to BaudRate and DataBits.

For the abstract class I decided to inherit from the NumericUpDown Class. This control allows only numbers and has a convenient and familiar look to it. Since we’re looking for a discreet set of numbers I created an int[] variable called baudrates (line 3). This will contain all the permissible entries for our control. Following that I set the minimum and maximum values in the OnCreateControl() method (lines 8 – 9). Notice I don’t discreetly enter any values, I simply refer back to the array for that. Then I simply override the OnValueChanged  method (lines 12 – 21) and if the value increases (line 16) I use the next highest value in the array and if it decreases (line 18) I use the next lowest value. I use the private variable oldValue (line 4,21) to track the value before it was incremented or decremented.

 1:     public abstract class RestrictedUpDown : NumericUpDown
 2:     {
 3:         protected int[] baudRates = new int[2]{1,2};
 4:         private int oldValue = 0;
 5: 
 6:         protected override void OnCreateControl()
 7:         {
 8:             base.Minimum = baudRates[0];
 9:             base.Maximum = baudRates[baudRates.Length - 1];
 10:             base.OnCreateControl();
 11:         }
 12:         protected override void OnValueChanged(EventArgs e)
 13:         {
 14:             if (!baudRates.Contains((int)this.Value) )
 15:             {
 16:                 if ((int)this.Value > oldValue)
 17:                     this.Value = baudRates.First(p => p > this.Value);
 18:                 else this.Value = baudRates.Last(p => p < this.Value);
 19:             }
 20:             base.OnValueChanged(e);
 21:             oldValue = (int) this.Value;
 22:         }
 23: 
 24:     }

Once that’s done creating the controls for the BaudRate and Databits take a few seconds:

 1:  public class BaudRateUpDown : RestrictedUpDown
 2:     {
 3:         public BaudRateUpDown()
 4:         {
 5:             baudRates= new int[]{1200,1800,2400,4800,7200,9600,14400,19200,38400,57600,115200,128000};
 6:         }
 7:     }
 8:     public class DataBits : RestrictedUpDown
 9:     {
 10:         public DataBits() :base()
 11:         {
 12:             baudRates = new int[] { 4, 5, 6, 7, 8 };
 13:         }
 14:     }

The rest of the properties are all enumerators. Once again we start with an abstract class. This time notice the <T> that simply denotes that we can add a specific type when inheriting. Following that it’s similar to the PortNames combo box however we enumerate through the <T> and get all the possible values and enter them into the combo box (lines 10 – 14) and automatically select the first one.

 1: public abstract class EnumComboBox<T> : ComboBox
 2:     {
 3: 
 4:         protected override void OnCreateControl()
 5:         {
 6:             Type enumType = typeof(T);
 7:             if (!this.DesignMode)
 8:             {
 9:                 base.Items.Clear();
 10:                 foreach (var item in Enum.GetValues(enumType))
 11:                 {
 12:                     base.Items.Add(item);
 13:                 }
 14:                 this.SelectedIndex = 0;
 15:             }
 16:             base.OnCreateControl();
 17:         }
 18:  
 19:     }

Creating the actual combo boxes from there is only a few lines of code (3 to be exact) as follows:

 1:     public class ParityComboBox : EnumComboBox<Parity> { }
 2:     public class StopBitsComboBox : EnumComboBox<StopBits> { }
 3:     public class HandShakeComboBox : EnumComboBox<Handshake> { }

Now what we have is a few controls that we can drag and drop and without any coding be able to create a simple user control that looks like this:

Untitled

Following that we drag this user control into a form and set up the saving and loading of the settings and we’re done. Please see the complete source code here.

As you can see in this case creating validated controls to manager are settings is simply the quickest and most efficient route.

Serial Port Programming Part 1–A (very) brief introduction

December 21, 2011 Leave a comment

My first entry in this blog is going to be about serial port. Why? Mostly because I read a lot of posts in various programming forums in regards to interacting with the serial ports. Most programmers frequently forget that serial ports have been around a very long time so they act a little different then most current communication technologies.

When deploying an application that will be interacting with serial ports the first question should always be what device will be attached and how? The “how” is the most important question. If the device only uses the transmit, receive and signals ground pins then the deployment is a lot easier, if it use all 8 pins it could increase the complexity of the project.

First some resources, a complete understanding is not really necessary but if you get some of the more challenging devices you might need a detailed understanding of how serial communication works in order to troubleshoot properly. Here’s a short list below:

Wiki UART Description

Free BSD UART Description

On to the programming before proceeding you might want to have a quick look at the MSDN Pages for Serial Port class here.

Below is a very brief implementation of the serial port. There’s more to come however this will get you started. There’s a very important note on this implementation, there must always be a terminator or a set byte length of the data. By set byte length I meant that each block of data that you’ll need to process is x long. So instead of a terminator you use track how many bytes are read to know when you’re received all the data.

Next time – Serial Port Programming Part 2 – Developing a GUI to set the Port Settings and validating the data.

You can download the code below at : http://code.msdn.microsoft.com/SerialPort-brief-Example-ac0d5004

 1: using System;
 2: using System.IO.Ports;
 3: using System.Text;
 4: 
 5: namespace SerialPortExample
 6: {
 7:     /// <summary>
 8:     /// Interfaces with a serial port. There should only be one instance
 9:     /// of this class for each serial port to be used.
 10:     /// </summary>
 11:     public class SerialPortInterface
 12:     {
 13:         private SerialPort  _serialPort     = new SerialPort();
 14:         private int         _baudRate       = 9600;
 15:         private int         _dataBits       = 8;
 16:         private Handshake   _handshake      = Handshake.None;
 17:         private Parity      _parity         = Parity.None;
 18:         private string      _portName       = "COM1";
 19:         private StopBits    _stopBits       = StopBits.One;
 20: 
 21:         /// <summary>
 22:         /// Holds data received until we get a terminator.
 23:         /// </summary>
 24:         private string tString              = string.Empty;
 25:         /// <summary>
 26:         /// End of transmition byte in this case EOT (ASCII 4).
 27:         /// </summary>
 28:         private byte _terminator            = 0x4;
 29:  
 30:         public int BaudRate         { get { return _baudRate; }     set { _baudRate  = value; } }
 31:         public int DataBits         { get { return _dataBits; }     set { _dataBits  = value; } }
 32:         public Handshake Handshake  { get { return _handshake; }    set { _handshake = value; } }
 33:         public Parity Parity        { get { return _parity; }       set { _parity    = value; } }
 34:         public string PortName      { get { return _portName; }     set { _portName  = value; } }
 35:         public bool Open()
 36:         {
 37:             try
 38:             {
 39:                 _serialPort.BaudRate = _baudRate;
 40:                 _serialPort.DataBits = _dataBits;
 41:                 _serialPort.Handshake = _handshake;
 42:                 _serialPort.Parity = _parity;
 43:                 _serialPort.PortName = _portName;
 44:                 _serialPort.StopBits = _stopBits;
 45:                 _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
 46:             }
 47:             catch { return false; }
 48:             return true;
 49:         }
 50: 
 51:         void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
 52:         {
 53:             //Initialize a buffer to hold the received data
 54:             byte[] buffer = new byte[_serialPort.ReadBufferSize];
 55:  
 56:             //There is no accurate method for checking how many bytes are read
 57:             //unless you check the return from the Read method
 58:             int bytesRead = _serialPort.Read(buffer, 0, buffer.Length);
 59:  
 60:             //For the example assume the data we are received is ASCII data.
 61:             tString += Encoding.ASCII.GetString(buffer, 0, bytesRead);
 62:             //Check if string contains the terminator 
 63:             if (tString.IndexOf((char)_terminator) > -1)
 64:             {
 65:                 //If tString does contain terminator we cannot assume that it is the last character received
 66:                 string workingString = tString.Substring(0, tString.IndexOf((char)_terminator));
 67:                 //Remove the data up to the terminator from tString
 68:                 tString = tString.Substring(tString.IndexOf((char)_terminator));
 69:                 //Do something with workingString
 70:                 Console.WriteLine(workingString);
 71:             }
 72:         }
 73: 
 74:     }
 75: }