This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links. -------------------------------------------------------------------------------- Infrared Programming Using the .NET Compact Framework Wei-Meng Lee With all the buzz around Wi-Fi, Bluetooth, and other wireless technologies, it's easy to overlook one of the simplest and most common forms of wireless communications out there: infrared. Anyone who's ever used a remote control has used it! Infrared makes use of the invisible spectrum of light just beyond red in the visible spectrum. You can use it in applications for short-range, point-to-point data transfer. Because it uses light, line-of-sight is a prerequisite for infrared. Despite this limitation, infrared is increasingly popular in devices such as digital cameras, PDAs, and notebook computers. In this article, Wei-Meng Lee shows you how to build an infrared chat application using the IrDAClient class supported in the .NET Compact Framework class libraries. Founded in 1993 as a non-profit organization, the Infrared Data Association (IrDA) is an international organization that creates and promotes interoperable, low-cost infrared data interconnection standards that allow users to point one device at another and have it just work. The Infrared Data Association standards support a broad range of appliances, computing, and communications devices. The term IrDA is also used to refer to the protocols for infrared communications, not exclusively to the non-profit body. There are currently four versions of IrDA, their differences mainly being in the transfer speed. They are: Serial Infrared (SIR)—This is the original standard with a transfer speed of up to 115 Kbps. Medium Infrared (MIR)—Improved transfer speed of 1.152 Mbps. Not widely implemented. Fast Infrared (FIR)—Speed of up to 4 Mbps. Most new computers implement this standard. Very Fast Infrared (VFIR)—Speed of up to 16 Mbps. Not widely implemented yet. Future versions of the IrDA will boost speeds up to 50 Mbps. When two devices with two different IrDA implementations communicate with each other, they'll both step down to the lower transfer speed. In terms of operating range, infrared devices can communicate up to one or two meters. Depending on the implementation, if a device uses a lower power version, the range can be stepped down to a mere 20 to 30 cm. This is crucial for low-power devices. All data packets exchanged are protected using a Cyclic Redundancy Check (CRC), which uses a number derived from the transmitted data to verify its integrity. CRC-16 is used for speeds up to 1.152Mb/s and CRC-32 at 4 Mb/s. The IrDA also defines a bi-directional communication for infrared communications. Building the application To begin creating the sample application, launch Microsoft Visual Studio .NET 2003 and create a Smart Device Application project using Visual Basic, as shown in Figure 1. Name the project IrDA. Start by building the interface of the chat application. Drop the following controls onto the default Form1 (see Figure 2): TextBox Button MainMenu The MainMenu control has one MenuItem control named "Service Name". My application allows two Pocket PCs to communicate with each other using the built-in infrared port. It can come in handy at dull meetings. Coding the application For this application, I need to import the following namespaces: Imports System.Net Imports System.IO Imports System.Net.Sockets To use the IrDAClient class in .NET CF for infrared communications, you need to add a reference to the System.Net.IrDa reference to the project. To do so, right-click on the project name (IrDA) in Solution Explorer and select Add Reference (see Figure 3). Double-click on the System.Net.IrDa item and click OK. I also declare these constants and global variables: Const MAX_MESSAGE_SIZE = 128 Const MAX_TRIES = 3 Private ServiceName As String = "default" Dim irdaClient As New System.Net.Sockets.IrDAClient Dim irStream As Stream The MAX_MESSAGE_SIZE constant is the maximum size of a message exchanged, and MAX_TRIES is the maximum number of tries to send a message before giving up. The ServiceName variable is used as a unique identifier for an infrared communication session. I also created an IrDAClient object for infrared communication and a Stream object for sending and receiving data. Supporting functions Throughout this application, I use two supporting functions—stringToByteArray() and byteArrayToString(). The stringToByteArray() method, as you might expect, 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 does the opposite and works similarly. Another way to convert a string to byte array (and vice versa) would be to use the Encoding.ASCII.GetString() and Encoding.ASCII.GetBytes() methods available in the System.Text namespace. Receiving messages When the application is loaded, it needs to start listening for messages. And so, in the Form1_Load event, I have this: Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim t1 As System.Threading.Thread t1 = New Threading.Thread(AddressOf receiveLoop) t1.Start() End Sub Essentially, I've spun off a thread to invoke the receiveLoop() method. The aim here is to listen for messages in the background so that you can send messages at any time. Here's the code for the receiveLoop() method: Public Sub receiveLoop() Dim strReceived As String strReceived = receiveMessage(MAX_MESSAGE_SIZE) While True '---keep on listening for new message If strReceived <> "" Then Dim updateDelegate As New _ myDelegate(AddressOf UpdateTextBox) updateDelegate.Invoke(strReceived) strReceived = _ receiveMessage(MAX_MESSAGE_SIZE) End If End While End Sub The main use of the receiveLoop() method is to repeatedly invoke the receiveMessage() method. The receiveMessage() method returns the message received. Here's the code for the receiveMessage() method: Private Function receiveMessage( _ ByVal BufferLen As Integer) As String Dim bytesRead As Integer = 0 Dim listener As IrDAListener = _ New IrDAListener(ServiceName) Dim client As IrDAClient = Nothing Dim stream As System.IO.Stream = Nothing Dim Buffer(MAX_MESSAGE_SIZE) As Byte Dim str As String Try listener.Start() ' blocking call client = listener.AcceptIrDAClient() stream = client.GetStream() bytesRead = stream.Read(Buffer, 0, BufferLen) str = client.RemoteMachineName + "->" + _ byteArrayToString(Buffer, bytesRead) Catch e As Exception MsgBox("Error listening to incoming message") Finally If (Not stream Is Nothing) Then stream.Close() End If If (Not client Is Nothing) Then client.Close() End If listener.Stop() End Try Return str End Function Let's spend some time going through this method. First, I set up the relevant variables for this method. In particular, I created an IrDAListener object. The IrDAListener object is used to listen for incoming data through the IR port. It takes in the Service name argument. Two devices communicating through infrared must have the same Service name. I also created an IrDAClient object for sending and receiving data from the other device. The IrDAListener object starts listening for incoming data and returns an IrDAClient object when data is received. I then use a Stream object to read the data on the stream and format it for display. Finally, the receiveMessage() method returns the data formatted in a fashion ready to be displayed on the form. Displaying the received messages Since Windows controls aren't thread-safe, accessing Windows controls within a thread will have unpredictable results. As such, you need to use a delegate method to call the updateTextBox() method to update the TextBox control with the received message: Private Delegate Sub myDelegate(ByVal str As String) Private Sub UpdateTextBox(ByVal str As String) '---delegate to update the textbox control txtMessagesArchive.Text += str End Sub Sending messages Now that you've seen how to receive messages, I'll show you how to send. When the Send button is clicked, I invoke the sendMessage() method: Private Sub Button1_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cmdSend.Click sendMessage(MAX_TRIES, _ stringToByteArray(txtMessage.Text), _ txtMessage.Text.Length) End Sub The SendMessage() method first tries to establish a connection with the other device until the number of retries is exceeded. Once a connection is established, it writes to the other device using an IO Stream object. Finally, it closes the stream and the connection: Private Sub sendMessage(ByVal NumRetries As Integer, _ ByVal Buffer() As Byte, _ ByVal BufferLen As Integer) Dim client As IrDAClient = Nothing Dim CurrentTries As Integer = 0 Do Try client = New IrDAClient(ServiceName) Catch se As SocketException If (CurrentTries >= NumRetries) Then Throw se End If End Try CurrentTries = CurrentTries + 1 Loop While client Is Nothing And _ CurrentTries < NumRetries If (client Is Nothing) Then 'timeout occurred MsgBox("Error establishing contact") Return End If Dim stream As System.IO.Stream = Nothing Try stream = client.GetStream() stream.Write(Buffer, 0, BufferLen) Catch e As Exception MsgBox("Error sending") Finally If (Not stream Is Nothing) Then stream.Close() End If If (Not client Is Nothing) Then client.Close() End If End Try End Sub Changing the Service name By default, the Service name of the two communicating devices is set to be "default". However, the user can change the default Service name by using the menu item named Service Name. This is how you can implement the change in Service name: Private Sub MenuItem2_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MenuItem2.Click Dim response As String = _ InputBox("Please enter a Service Name.", _ "Service Name", ServiceName) If response <> "" Then 'change the service name ServiceName = response End If End Sub Compiling and deploying the application That's it! To test the application, you need to install the sample application on both Pocket PCs. The easiest way to do this is to connect one of the Pocket PCs to the development machine and use Visual Studio .NET 2003 to deploy the application on the device. When you press F5, the application will automatically be copied onto the device. The next step is to copy the application onto the other Pocket PC. There are two steps involved here. First, you need to generate a CAB file for the application so that it can be copied and installed on the target Pocket PC. Second, you install the assembly for the .NET Compact Framework on it (this only needs to be done once). Follow these steps: To generate a CAB file for the application, click on the Build Cab File button in Visual Studio .NET 2003 (see Figure 4). When the CAB file is generated, you can locate it in the Cab\Debug folder of the application. Visual Studio .NET 2003 will generate the CAB files for the various platforms that are supported by the .NET Compact Framework. Choose the right one for the platform. I selected IrDA_PPC.ARM.CAB for my Compaq iPaq 3630 (see Figure 5). To copy the CAB file to the Pocket PC, connect the Pocket PC to the machine and use Microsoft ActiveSync's Explore option. Drag and drop the selected CAB file onto the desired directory on the Pocket PC. Once the CAB file is copied to the device, you can use infrared to beam the CAB file to the other Pocket PC. Next, copy the .NET Compact Framework assembly to the Pocket PC. You can find the CAB file for the .NET Compact Framework in the following directory on the development machine (with Visual Studio .NET 2003 installed): C:\Program Files\ Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\wce300. Choose the platform for the Pocket PC. For example, my iPaq 3630 uses the "arm" platform since it runs using an ARM processor (see Figure 6). Copy the netcf.core.ppc3.arm file to the Pocket PC via ActiveSync. Again, use infrared to beam the file to the other Pocket PC. On the other Pocket PC, you can now install the .NET Compact Framework and the application by using File Explorer and tapping on the two CAB files (the order of installation is important—install the .NET CF assembly first). Once the application is installed, you should find an IrDA application icon in the Programs folder. Using two infrared-equipped Pocket PCs, you can now align their infrared ports and start communicating (see Figure 7)! Summary In this article, I've given you a bit of background on infrared technology and shown you how to use Microsoft Visual Studio .NET 2003 to develop infrared-enabled Pocket PC applications. Though the sample application is for chatting, you should be able to easily adapt it for your own applications. Download 402LEE.ZIP To find out more about Hardcore Visual Studio and Pinnacle Publishing, visit their Web site at http://www.pinpub.com/ Note: This is not a Microsoft Corporation Web site. Microsoft is not responsible for its content. This article is reproduced from the February 2004 issue of Hardcore Visual Studio. Copyright 2004, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. Hardcore Visual Studio is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-788-1900. Send feedback to Microsoft © Microsoft Corporation. All rights reserved.