Serial communication between a PokectPC and hyperterminal using VB.NET

Asked By Indu mathy
27-May-09 01:11 PM
Earn up to 0 extra points for answering this tough question.
Hello Sir...
   I want to do serial communication between a PocketPC(Windows Mobile 5.0) and hyperterminal.
Plz give me sample coding in VB.NET  (windows or console application)
also is it necessary to use emulator from VS 2008?

Plz help me Sir
Thanking U in advance...

iindumath@gmail.com

  re: Serial communication between a PokectPC and hyperterminal using VB.NET

Arun Kumar Ramesh replied to Indu mathy
30-Jun-10 01:47 PM
Back in the days of Visual Basic 6.0, you had to use the MSComm Control that was shipped with VB6, the only problem with this method was you needed to make sure you included that control in your installation package, not really that big of a deal. The control did exactly what was needed for the task.

We were then introduced to .Net 1.1, VB programmers loved the fact that Visual Basic had finally evolved to an OO language. It was soon discovered that, with all it's OO abilities, the ability to communicate via a serial port wasn't available, so once again VB developers were forced to rely on the MSComm Control from previous versionsof Visual Basic, still not that big of a deal, but some were upset that an intrinsic way of serial port communication wasn't offered with the .net Framework.

Then along comes .Net 2.0, and this time Microsoft added the System.IO.Ports Namespace, and within that was the SerialPort Class. DotNet developers finally had an intrinsic way of serial port communication, without having to deal with the complexities of interoping with an old legacy ActiveX OCX control. One of the most useful methods in the SerialPort class is the GetPortNames Method. This allows you to retrieve a list of available ports (COM1,COM2,etc.) available for the computer the application is running on.

Now that we have that out of the way, lets move on to programming our application. As with all application I create, I keep functionality separated from presentation, I do this by creating Manager classes that manage the functionality or a given process. What we will be looking at is the code in my CommManager class. As with anything you write in .Net you need to add the references to the Namespace's you'll be using:

view source
print?
1    Imports System
2    Imports System.Text
3    Imports System.Drawing
4    Imports System.IO.Ports
5    Imports System.Windows.Forms


In this application I wanted to give the user the option of what format they wanted to send the message in, either string or binary, so we have an enumeration for that, and an enumerations for the type of message i.e; Incoming, Outgoing, Error, etc. The main purpose of this enumeration is for changing the color of the text displayed to the user according to message type. Here are the enumerations:

view source
print?
01    #Region "Manager Enums"
02    ''' <summary>
03    ''' enumeration to hold our transmission types
04    ''' </summary>
05    Public Enum TransmissionType
06      Text
07      Hex
08    End Enum
09    
10    ''' <summary>
11    ''' enumeration to hold our message types
12    ''' </summary>
13    Public Enum MessageType
14      Incoming
15      Outgoing
16      Normal
17      Warning
18      [Error]
19    End Enum
20    #End Region


Next we have our variable list, 6 of them are for populating our class Properties, the others are being access throughout the manager class so they are made Global. Things are a bit different when sealing with delegates and how objects are access through VB.Net than they are in C#, so in the VB.Net version there are 2 more properties, and an extra Boolean variable used to determine if the buffer is to write the current data to the serial port. Here are the variables needed for the manager class:

view source
print?
01    #Region "Manager Variables"
02    'property variables
03    Private _baudRate As String = String.Empty
04    Private _parity As String = String.Empty
05    Private _stopBits As String = String.Empty
06    Private _dataBits As String = String.Empty
07    Private _portName As String = String.Empty
08    Private _transType As TransmissionType
09    Private _displayWindow As RichTextBox
10    Private _msg As String
11    Private _type As MessageType
12    'global manager variables
13    Private MessageColor As Color() = {Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red}
14    Private comPort As New SerialPort()
15    Private write As Boolean = True
16    #End Region


NOTE:I always separate my code into sections using the #region ... #end region to make it easier when scanning my code. It is a design choice so it's not necessary if you don't want to do it.

Now we need to create our class properties. All the properties in this class are public read/write properties. As stated above we needed to add 2 additional properties for the conversion from C# to VB.Net. We have properties for the following items:

    * Baud Rate: A measure of the speed of serial communication, roughly equivalent to bits per second.
    * Parity: The even or odd quality of the number of 1's or 0's in a binary code, often used to determine the integrity of data especially after transmission.
    * Stop Bits: A bit that signals the end of a transmission unit
    * Data Bits: The number of bits used to represent one character of data.
    * Port Name: The port with which we're communicating through, i.e; COM1, COM2, etc.
    * MessageType: Outgoing, Incoming, Error, Warning, etc.
    * Message: This is the actual message being sent through the serial port

We also have 4 properties that aren't related to the port itself, but with where the data will be displayed, what transmission type to use, the message type, and the message itself:

view source
print?
01    ''' <summary>
02    ''' property to hold the StopBits
03    ''' of our manager class
04    ''' </summary>
05    Public Property StopBits() As String
06      Get
07        Return _stopBits
08      End Get
09      Set(ByVal value As String)
10        _stopBits = value
11      End Set
12    End Property
13    
14    ''' <summary>
15    ''' property to hold the DataBits
16    ''' of our manager class
17    ''' </summary>
18    Public Property DataBits() As String
19      Get
20        Return _dataBits
21      End Get
22      Set(ByVal value As String)
23        _dataBits = value
24      End Set
25    End Property
26    
27    ''' <summary>
28    ''' property to hold the PortName
29    ''' of our manager class
30    ''' </summary>
31    Public Property PortName() As String
32      Get
33        Return _portName
34      End Get
35      Set(ByVal value As String)
36        _portName = value
37      End Set
38    End Property
39    
40    ''' <summary>
41    ''' property to hold our TransmissionType
42    ''' of our manager class
43    ''' </summary>
44    Public Property CurrentTransmissionType() As TransmissionType
45      Get
46        Return _transType
47      End Get
48      Set(ByVal value As TransmissionType)
49        _transType = value
50      End Set
51    End Property
52    
53    ''' <summary>
54    ''' property to hold our display window
55    ''' value
56    ''' </summary>
57    Public Property DisplayWindow() As RichTextBox
58      Get
59        Return _displayWindow
60      End Get
61      Set(ByVal value As RichTextBox)
62        _displayWindow = value
63      End Set
64    End Property
65    
66    ''' <summary>
67    ''' Property to hold the message being sent
68    ''' through the serial port
69    ''' </summary>
70    ''' <value></value>
71    ''' <returns></returns>
72    ''' <remarks></remarks>
73    Public Property Message() As String
74      Get
75        Return _msg
76      End Get
77      Set(ByVal value As String)
78        _msg = value
79      End Set
80    End Property
81    
82    ''' <summary>
83    ''' Message to hold the transmission type
84    ''' </summary>
85    ''' <value></value>
86    ''' <returns></returns>
87    ''' <remarks></remarks>
88    Public Property Type() As MessageType
89      Get
90        Return _type
91      End Get
92      Set(ByVal value As MessageType)
93        _type = value
94      End Set
95    End Property
96    #End Region


To be able to instantiate any class object we create we need Constructors. Constructors are the entry point to your class, and is the first code executed when instantiating a class object. We have 2 constructors for our manager class, one that sets our properties to a specified value, and one that sets our properties to an empty value, thus initializing the variables preventing a NullReferenceException from occurring. We also add an EventHandler in the constructor, the event will be executed whenever there's data waiting in the buffer:

view source
print?
01    #Region "Manager Properties"
02    ''' <summary>
03    ''' Property to hold the BaudRate
04    ''' of our manager class
05    ''' </summary>
06    Public Property BaudRate() As String
07      Get
08        Return _baudRate
09      End Get
10      Set(ByVal value As String)
11        _baudRate = value
12      End Set
13    End Property
14    
15    ''' <summary>
16    ''' property to hold the Parity
17    ''' of our manager class
18    ''' </summary>
19    Public Property Parity() As String
20      Get
21        Return _parity
22      End Get
23      Set(ByVal value As String)
24        _parity = value
25      End Set
26    End Property
27    
28    #Region "Manager Constructors"
29    ''' <summary>
30    ''' Constructor to set the properties of our Manager Class
31    ''' </summary>
32    ''' <param name="baud">Desired BaudRate</param>
33    ''' <param name="par">Desired Parity</param>
34    ''' <param name="sBits">Desired StopBits</param>
35    ''' <param name="dBits">Desired DataBits</param>
36    ''' <param name="name">Desired PortName</param>
37    Public Sub New(ByVal baud As String, ByVal par As String, ByVal sBits As String, ByVal dBits As String, ByVal name As
38    
39    String, ByVal rtb As RichTextBox)
40      _baudRate = baud
41      _parity = par
42      _stopBits = sBits
43      _dataBits = dBits
44      _portName = name
45      _displayWindow = rtb
46      'now add an event handler
47      AddHandler comPort.DataReceived, AddressOf comPort_DataReceived
48    End Sub
49    
50    ''' <summary>
51    ''' Comstructor to set the properties of our
52    ''' serial port communicator to nothing
53    ''' </summary>
54    Public Sub New()
55      _baudRate = String.Empty
56      _parity = String.Empty
57      _stopBits = String.Empty
58      _dataBits = String.Empty
59      _portName = "COM1"
60      _displayWindow = Nothing
61      'add event handler
62      AddHandler comPort.DataReceived, AddressOf comPort_DataReceived
63    End Sub
64    #End Region


The first think you need to know about serial port communication is writing data to the port. The first thing we do in our WriteData method is to check what transmission mode the user has selected, since binary data needs to be converted into binary, then back to string for displaying to the user. Next we need to make sure the port is open, for this we use the IsOpen Property of the SerialPort Class. If the port isnt open we open it by calling the Open Method of the SerialPort Class.

For writing to the port we use the Write Method. It is in this method we utilize the new boolean variable, write to determine if we want to write the data.This is used to handling byte transmission type when the data is in the incorrect format:

view source
print?
01    #Region "WriteData"
02    Public Sub WriteData(ByVal msg As String)
03    Select Case CurrentTransmissionType
04      Case TransmissionType.Text
05        'first make sure the port is open
06        'if its not open then open it
07        If Not (comPort.IsOpen = True) Then
08          comPort.Open()
09        End If
10        'send the message to the port
11        comPort.Write(msg)
12        'display the message
13        _type = MessageType.Outgoing
14        _msg = msg + "" + Environment.NewLine + ""
15        DisplayData(_type, _msg)
16        Exit Select
17      Case TransmissionType.Hex
18        Try
19          'convert the message to byte array
20          Dim newMsg As Byte() = HexToByte(msg)
21          'Determine if we are goint
22          'to write the byte data to the screen
23          If Not write Then
24            DisplayData(_type, _msg)
25            Exit Sub
26          End If
27          'send the message to the port
28          comPort.Write(newMsg, 0, newMsg.Length)
29          'convert back to hex and display
30          _type = MessageType.Outgoing
31          _msg = ByteToHex(newMsg) + "" + Environment.NewLine + ""
32          DisplayData(_type, _msg)
33        Catch ex As FormatException
34          'display error message
35          _type = MessageType.Error
36          _msg = ex.Message + "" + Environment.NewLine + ""
37          DisplayData(_type, _msg)
38        Finally
39          _displaywindow.SelectAll()
40        End Try
41        Exit Select
42      Case Else
43        'first make sure the port is open
44        'if its not open then open it
45        If Not (comPort.IsOpen = True) Then
46          comPort.Open()
47        End If
48        'send the message to the port
49        comPort.Write(msg)
50        'display the message
51        _type = MessageType.Outgoing
52        _msg = msg + "" + Environment.NewLine + ""
53        DisplayData(MessageType.Outgoing, msg + "" + Environment.NewLine + "")
54        Exit Select
55    End Select
56    End Sub
57    #End Region


You will notice in this method we call three methods:

    * HexToByte
    * ByteToHex
    * DisplayData

These methods are required for this manager. The HexToByte method converts the data provided to binary format, then the ByteToHex converts it back to hex format for displaying. The last one, DisplayData is where we marshal a call to the thread that created the control for displaying the data, since UI controls can only be accessed by the thread that created them. First we'll look at converting the string provided to binary format:

view source
print?
01    #Region "HexToByte"
02    ''' <summary>
03    ''' method to convert hex string into a byte array
04    ''' </summary>
05    ''' <param name="msg">string to convert</param>
06    ''' <returns>a byte array</returns>
07    Private Function HexToByte(ByVal msg As String) As Byte()
08      'Here we added an extra check to ensure the data
09      'was the proper length for converting to byte
10      If msg.Length Mod 2 = 0 Then
11        'remove any spaces from the string
12        _msg = msg
13        _msg = msg.Replace(" ", "")
14        'create a byte array the length of the
15        'divided by 2 (Hex is 2 characters in length)
16        Dim comBuffer As Byte() = New Byte(_msg.Length / 2 - 1) {}
17        For i As Integer = 0 To _msg.Length - 1 Step 2
18          comBuffer(i / 2) = CByte(Convert.ToByte(_msg.Substring(i, 2), 16))
19        Next
20        write = True
21        'loop through the length of the provided string
22        'convert each set of 2 characters to a byte
23        'and add to the array
24        'return the array
25        Return comBuffer
26      Else
27        'Message wasnt the proper length
28        'So we set the display message
29        _msg = "Invalid format"
30        _type = MessageType.Error
31        ' DisplayData(_Type, _msg)
32        'Set our boolean value to false
33        write = False
34        Return Nothing
35      End If
36    End Function
37    #End Region


Here we convert the provided string to a byte array, then the WriteData method sends it out the port. For displaying we need to convert it back into string format, so we use the ByteToHex method we created:

view source
print?
01    #Region "ByteToHex"
02    ''' <summary>
03    ''' method to convert a byte array into a hex string
04    ''' </summary>
05    ''' <param name="comByte">byte array to convert</param>
06    ''' <returns>a hex string</returns>
07    Private Function ByteToHex(ByVal comByte As Byte()) As String
08      'create a new StringBuilder object
09      Dim builder As New StringBuilder(comByte.Length * 3)
10      'loop through each byte in the array
11      For Each data As Byte In comByte
12        builder.Append(Convert.ToString(data, 16).PadLeft(2, "0"c).PadRight(3, " "c))
13        'convert the byte to a string and add to the stringbuilder
14      Next
15      'return the converted value
16      Return builder.ToString().ToUpper()
17    End Function
18    #End Region


The last method that WriteData depends on is the DisplayData method. Here we use the Invoke Method of our RichTextBox, the control used to display the data, to create a new EventHandler which creates a new Delegate for setting the properties we wish for our message, then appending it to the value already displayed.

We had to change the format of the DisplayData method as VB.Net handles delegates completely different than C#. Instead of putting the functionality of the delegate in the method, we had to create a seperate method, then use the AddressOf Method to reference the procedure that will act as our delegate:

view source
print?
01    #Region "DisplayData"
02    ''' <summary>
03    ''' Method to display the data to and
04    ''' from the port on the screen
05    ''' </summary>
06    ''' <remarks></remarks>
07    <STAThread()> _
08    Private Sub DisplayData(ByVal type As MessageType, ByVal msg As String)
09      _displaywindow.Invoke(New EventHandler(AddressOf DoDisplay))
10    End Sub
11    #End Region


NOTE: You will notice that we have added the STAThreadAttribute to our method. This is used when a single thread apartment is required by a control, like the RichTextBox.

Now we will look at our delegate method, which is responsible for setting all of the properties of our display window,
which is a RichTextBox, as it has text formatting options not available to the regular TextBox:

view source
print?
1    #Region "DoDisplay"
2    Private Sub DoDisplay(ByVal sender As Object, ByVal e As EventArgs)
3      _displaywindow.SelectedText = String.Empty
4      _displaywindow.SelectionFont = New Font(_displaywindow.SelectionFont, FontStyle.Bold)
5      _displaywindow.SelectionColor = MessageColor(CType(_type, Integer))
6      _displaywindow.AppendText(_msg)
7      _displaywindow.ScrollToCaret()
8    End Sub
9    #End Region


If you will read my tutorial on Serial Port Communication in C# you will see the same exact functionality that is in the DisplayData method, except in VB.Net, as pointed out earlier, requires the AddressOf Operator to reference a method to act as the delegate.The next method we will look at it used when we need to open the port initially. Here we set the BaudRate, Parity, StopBits, DataBits and PortName Properties of the SerialPort Class:

view source
print?
01    #Region "OpenPort"
02    Public Function OpenPort() As Boolean
03      Try
04        'first check if the port is already open
05        'if its open then close it
06        If comPort.IsOpen = True Then
07          comPort.Close()
08        End If
09    
10        'set the properties of our SerialPort Object
11        comPort.BaudRate = Integer.Parse(_baudRate)
12        'BaudRate
13        comPort.DataBits = Integer.Parse(_dataBits)
14        'DataBits
15        comPort.StopBits = DirectCast([Enum].Parse(GetType(StopBits), _stopBits), StopBits)
16        'StopBits
17        comPort.Parity = DirectCast([Enum].Parse(GetType(Parity), _parity), Parity)
18        'Parity
19        comPort.PortName = _portName
20        'PortName
21        'now open the port
22        comPort.Open()
23        'display message
24        _type = MessageType.Normal
25        _msg = "Port opened at " + DateTime.Now + "" + Environment.NewLine + ""
26        DisplayData(_type, _msg)
27        'return true
28        Return True
29      Catch ex As Exception
30        DisplayData(MessageType.[Error], ex.Message)
31        Return False
32      End Try
33    End Function
34    #End Region


Now that we have opened our port for communication for sending data through, we need to be able to close the port when we are finished without our application. Here we simply call the Close Method of the SerialPort Object, which also disposes of the internal stream being used for the data transmission:

view source
print?
01    #Region " ClosePort "
02    Public Sub ClosePort()
03      If comPort.IsOpen Then
04        _msg = "Port closed at " + DateTime.Now + "" + Environment.NewLine + ""
05        _type = MessageType.Normal
06        DisplayData(_type, _msg)
07        comPort.Close()
08      End If
09    End Sub
10    #End Region


Next lets take a look at our event handler. This event will be executed whenever there's data waiting in the buffer. This method looks identical to our WriteData method, because it has to do the same exact work:

view source
print?
01    #Region "comPort_DataReceived"
02    ''' <summary>
03    ''' method that will be called when theres data waiting in the buffer
04    ''' </summary>
05    ''' <param name="sender"></param>
06    ''' <param name="e"></param>
07    Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
08      'determine the mode the user selected (binary/string)
09      Select Case CurrentTransmissionType
10        Case TransmissionType.Text
11          'user chose string
12          'read data waiting in the buffer
13          Dim msg As String = comPort.ReadExisting()
14          'display the data to the user
15          _type = MessageType.Incoming
16          _msg = msg
17          DisplayData(MessageType.Incoming, msg + "" + Environment.NewLine + "")
18          Exit Select
19        Case TransmissionType.Hex
20          'user chose binary
21          'retrieve number of bytes in the buffer
22          Dim bytes As Integer = comPort.BytesToRead
23          'create a byte array to hold the awaiting data
24          Dim comBuffer As Byte() = New Byte(bytes - 1) {}
25          'read the data and store it
26          comPort.Read(comBuffer, 0, bytes)
27          'display the data to the user
28          _type = MessageType.Incoming
29          _msg = ByteToHex(comBuffer) + "" + Environment.NewLine + ""
30          DisplayData(MessageType.Incoming, ByteToHex(comBuffer) + "" + Environment.NewLine + "")
31          Exit Select
32        Case Else
33          'read data waiting in the buffer
34          Dim str As String = comPort.ReadExisting()
35          'display the data to the user
36          _type = MessageType.Incoming
37          _msg = str + "" + Environment.NewLine + ""
38          DisplayData(MessageType.Incoming, str + "" + Environment.NewLine + "")
39          Exit Select
40      End Select
41    End Sub
42    #End Region


We have 3 small methods left, and these are actually optional, for the lack of a better word. These mthods are used to populate my ComboBoxe's on my UI with the port names available on the computer, Parity values and Stop Bit values. The Parity and Stop Bits are available in enumerations included with the .Net Framework 2.0:

    * Parity Enumeration
    * StopBits Enumeration

view source
print?
01    #Region "SetParityValues"
02    Public Sub SetParityValues(ByVal obj As Object)
03      For Each str As String In [Enum].GetNames(GetType(Parity))
04        DirectCast(obj, ComboBox).Items.Add(str)
05      Next
06    End Sub
07    #End Region
08    
09    #Region "SetStopBitValues"
10    Public Sub SetStopBitValues(ByVal obj As Object)
11      For Each str As String In [Enum].GetNames(GetType(StopBits))
12        DirectCast(obj, ComboBox).Items.Add(str)
13      Next
14    End Sub
15    #End Region
16    
17    #Region "SetPortNameValues"
18    Public Sub SetPortNameValues(ByVal obj As Object)
19    
20      For Each str As String In SerialPort.GetPortNames()
21        DirectCast(obj, ComboBox).Items.Add(str)
22      Next
23    End Sub
24    #End Region


That is how you do Serial Port Communication in VB.Net. Microsoft finally gave us intrinsic tools to perform this task, no more relying on legacy objects. I am providing this class and a sample application to show how to implement what we just learned. What I am providing is under the GNU General Public License meaning you can modify and distribute how you see fit, but the license header must stay in tact. I hope you found this tutorial useful and informative, thatnk you for reading.

Happy Coding :)

 

~ Arun

Create New Account