All pastes #635025 Raw Edit

Something

public text v1 · immutable
#635025 ·published 2007-07-26 19:53 UTC
rendered paste body
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.