Reading from a Serial Port and Saving to a Database

Recently I was sent a question about how to read from a serial port and save the information to a database so instead of following up privately I thought I'd post my answer here. There's a good article in the MSDN Library that has some hints on how to do this with the System.IO.Ports.SerialPort class. In Visual Basic 2005 you can use the My Namespace to access the ports on your computer easily. For instance, you can open a port to COM4 like this:

Dim WithEvents mySerialport As SerialPort
mySerialport = My.Computer.Ports.OpenSerialPort("COM4", 56000, Parity.None, 8, StopBits.One)

Once we open the serial port we can listen to the DataReceived event. In my sample I just append the incomming messages to a StringBuilder and then save the string to a DataSet when we stop listening to the port. Its important to note that the DataReceived event will fire on a separate thread than your main thread. So if you need to update UI elements on a Form you need to use the Form's Invoke method in order to execute code onto the UI thread.

Dim myStringBuilder As New StringBuilder

Private

Sub mySerialport_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles mySerialport.DataReceived

'This happens on another thread

myStringBuilder.Append(mySerialport.ReadExisting())

Me.Invoke(New EventHandler(AddressOf UpdateControls))

End Sub

Private Sub UpdateControls(ByVal sender As Object, ByVal e As EventArgs)

'Do any UI code here on the main thread

Me.TextBox1.Text = myStringBuilder.ToString()

End Sub

I just created a simple SQL-Server Express database with one table called Message that has a field called Message. I then created a DataSet called MessageDataSet with the one MessageDataTable and then dropped that onto a grid onto my form to hook up some data binding automatically. When we stop reading from the serial port I just add a new MessageRow and then save it back using the MessageTableAdapter.Update() method.

Private Sub Stop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStopRead.Click

If mySerialport IsNot Nothing Then

mySerialport.Close()

End If

Try

Dim message As MessageDataSet.MessageRow = Me.MessageDataSet.Message.NewMessageRow()

message.Message = myStringBuilder.ToString()

Me.MessageDataSet.Message.Rows.Add(message)

Me.Save()

myStringBuilder.Remove(0, myStringBuilder.Length)

Me.TextBox1.Text = ""

Catch ex As Exception

End Try

End Sub

Private Sub Save()

Me.Validate()

Me.MessageBindingSource.EndEdit()

Me.MessageTableAdapter.Update(Me.MessageDataSet.Message)

End Sub

It's kind of hard to test hardware without hardware so if you don't have the hardware setup it's suggested that you get a null modem and hook that up between two USB to Serial converters to simulate two ports, one read one write. Unfortunately I don't have a null modem so I couldn't fully test my code. I've attached the entire solution to this post, you just need Visual Basic Express (or Visual Studio) and SQL-Server Express to run the example. If anyone has the hardware setup for this and finds a bug, please let me know and I'll post any corrections. You can also check out the forums for more info. Have fun!

ReadFromSerialPort.zip