Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Make Bluetooth Work for You: Build a Sample Chat Application  : Page 2

Learn how to write applications that work over Bluetooth short-range networks, using the .NET Compact Framework. Extend the sample chat application in this story to build any kind of Bluetooth applications you'd like.

Building the User Interface>
To create the sample application, start Visual Studio .NET 2003 and create a new Smart Device Application Project.

Figure 2: Build Form1 for the Main UI. Form1 is populated with three controls—a TextBox, a Button, and a MainMenu.

Let's first populate the default Form1 with the following controls:
  • TextBox (for entering the text of a chat message)
  • Button (for sending the text)
  • MainMenu

The populated Form1 is shown in Figure 2.

Communicating using Bluetooth
Windows CE 3.0—the operating system for Pocket PC devices—does not come with any API for Bluetooth communication. As such, you have to use other methods, such as platform invoke, to communicate using Bluetooth. The lack of an API for Bluetooth means that you are not able to program Bluetooth communications in the same way you use sockets for TCP/IP communications. Instead, Bluetooth is just another serial port. And so, Bluetooth communication is actually done via serial connections. You can see for yourself by going to Bluetooth Manager—>Tools—>Settings for All Devices—>Serial Port in your Pocket PC's main menu (see Figure 3).

Figure 3: Serial Connections. The Bluetooth connection is just another pair of serial ports, in this case ports 7 and 8.

The Bluetooth connection is actually mapped to two COM ports—one for incoming and one for outgoing traffic. On my test device the incoming port is COM7 and the outgoing port is COM8 (see Figure 3). We will program the Bluetooth application using serial communication techniques.

Unfortunately, the .NET Compact Framework class library does not contain managed classes for serial communication. You have to rely on the operating system calls to provide that. In particular, we need to make use of functions provided by Windows CE 3.0's "coredll.dll" library.

In the .NET CF, use the <DllImport()> attribute to import the library that you want to use. In our case, I have imported four functions from the coredll.dll library. They are:

  • CreateFile()—Opens a connection to a COM port.
  • ReadFile()—Reads data from a COM port.
  • WriteFile()—Writes data to a COM port.
  • CloseHandle()—Closes a COM port.

Author's Note: Many of the details involved in serial communications are beyond the scope of this article. For more information on building serial-comm applications in Windows CE, refer to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceseril/htm/cmconProgrammingSerialConnections.asp. The example in this article does not contain all the error-handling mechanisms required for serial communications.

The VB.NET code for the import is shown in Listing 1.

Now that you have the functions that you'll need, you can begin building the applications. Start by declaring some global variables:

Dim infileHandler As Long Dim outfileHandler As Long Dim numReadWrite As Integer Dim t1 As System.Threading.Thread Dim stopThread As Boolean = False

We need to create a Connect menu item that, when tapped, will call the connect() method to open the serial connections. We need to open the connections to the inbound and outbound port so that data can be both received and sent. The code below handles the Connect menu selection:

Private Sub MenuItem2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MenuItem2.Click connect() MenuItem2.Enabled = False '---disable the Connect item MenuItem3.Enabled = True '---enable the Disconnect item End Sub

The method we are using for reading incoming messages, ReadFile() is a blocking one. Therefore, we need to invoke a thread to continuously poll for incoming data while allowing our application to be responsive to users' input at the same time.

Public Sub connect() '---port number for Bluetooth connection Dim inPort As Short = 7 Dim outPort As Short = 8 '---Opens the port for Bluetooth infileHandler = CreateFile("COM" & inPort & ":", _ &HC0000000, 0, 0, 3, 0, 0) Application.DoEvents() outfileHandler = CreateFile("COM" & outPort & ":", _ &HC0000000, 0, 0, 3, 0, 0) Application.DoEvents() '---invoke the thread to receive incoming messages stopThread = False t1 = New Threading.Thread(AddressOf receiveLoop) t1.Start() End Sub

The send() method writes a message to the COM port using the WriteFile() method. After a message is sent, a copy of the message is added to the TextBox control:

Public Function send(ByVal message As String) As Integer '---send the message through the serial port Dim value As String = message & vbCrLf Dim retCode As Integer = WriteFile(outfileHandler, _ stringToByteArray(value), _ value.Length(), _ numReadWrite, _ 0) txtMessageLog.Text += value Return retCode End Function

The receiveLoop() method continuously polls for incoming messages. As Windows controls are not thread-safe, accessing Windows controls within a thread will have unpredictable results. As such, you need to use a delegate method to call the updateMessage() method to update the TextBox control with the received message.

Public Sub receiveLoop() '---receive the message through the serial port Dim inbuff(300) As Byte Dim retCode As Integer = ReadFile(infileHandler, _ inbuff, _ inbuff.Length, _ numReadWrite, _ 0) Application.DoEvents() While True If retCode = 0 Or stopThread Then '---either error or stop is requested Exit While Else Dim updateDelegate As New _ myDelegate(AddressOf updateMessageLog) updateDelegate.Invoke(byteArrayToString(inbuff)) ReDim inbuff(300) retCode = ReadFile(infileHandler, _ inbuff, _ inbuff.Length, _ numReadWrite, _ 0) Application.DoEvents() End If End While End Sub

The myDelegate() method has the same signature as the updateMessageLog() method. myDelegate() is called when updating the TextBox control. You should not directly call the updateMessageLog() within the thread; only the main thread can directly call it.

Public Delegate Sub myDelegate(ByVal str As String) Public Sub updateMessageLog(ByVal str As String) If str.Length > 0 Then txtMessageLog.Text += "-->" & str End If End Sub

Clicking the Send button invokes the send() method:

Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click If send(txtMessage.Text) = 0 Then MsgBox("Error sending message.") End If End Sub

Finally, clicking on the Disconnect menu item invokes the disconnect() method:

Private Sub MenuItem3_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MenuItem3.Click disconnect() MenuItem2.Enabled = True '---enable the Connect button MenuItem3.Enabled = False '---disable the Connect button End Sub

The disconnect() method will set a global flag for the thread to stop receiving incoming messages. It will also close the two open ports:

Public Sub disconnect() stopThread = True CloseHandle(infileHandler) CloseHandle(outfileHandler) End Sub

Byte to String and Back Again
Throughout this application, we have used two supporting methods: stringToByteArray() and byteArrayToString(). These two methods are necessary as the ReadFile() and WriteFile() methods both take in a byte array containing the message to be read and sent, respectively.

The stringToByteArray() method converts a string into a byte array:

Public Function stringToByteArray(ByVal str As String) As Byte() '---e.g. "abcdefg" to {a,b,c,d,e,f,g} Dim s As Char() s = str.ToCharArray Dim b(s.Length - 1) As Byte Dim i As Integer For i = 0 To s.Length - 1 b(i) = Convert.ToByte(s(i)) Next Return b End Function

The byteArrayToString() method converts a byte array into a string:

Function byteArrayToString(ByVal b() As Byte) As String '---e.g. {a,b,c,d,e,f,g} to "abcdefg" Dim str As String Dim enc As System.Text.ASCIIEncoding enc = New System.Text.ASCIIEncoding str = enc.GetString(b, 0, b.Length()) Return str End Function

When sending a message, the message to be sent would need to be converted to a byte array, and vice versa, when a message is received as a byte array, it needs to be converted back to a string so that it can be displayed on the device.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.