<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9 - Entries tagged with hardwarehacks</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Tags/hardwarehacks/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9 - Entries tagged with hardwarehacks</title>
      <link>http://channel9.msdn.com/Tags/hardwarehacks</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Tags/hardwarehacks</link>
    <language>en</language>
    <pubDate>Fri, 24 May 2013 21:49:38 GMT</pubDate>
    <lastBuildDate>Fri, 24 May 2013 21:49:38 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>12</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Coding4Fun at PDC 2009 – Video Montage</title>
      <description><![CDATA[ <p>We'll be posting one project each month but here is the Coding4Fun booth at PDC 2009!&nbsp; You can even view the Iron Bartender challenge at GeekFest as well!</p><p><a href="http://channel9.msdn.com/posts/Clint/Coding4Fun-at-PDC-2009/">Overall Recap of each project</a></p><p><iFrame src="http://channel9.msdn.com/posts/Clint/Coding4Fun-at-PDC-2009//player?h=384&w=512" frameborder="0" scrolling="no" width="512px" height="384px"></iFrame></p><p>&nbsp;</p><p><a href="http://channel9.msdn.com/posts/LauraFoy/Coding4Fun-DrinkTendr/">Iron Bartender!</a></p><p><iFrame src="http://channel9.msdn.com/blogs/laurafoy/coding4fun-drinktendr/player?h=384&w=512" frameborder="0" scrolling="no" width="512px" height="384px"></iFrame></p><p>&nbsp;</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:4dfed1b5bae74cef95c59e7600ca951f">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/Coding4Fun-at-PDC-2009--Video-Montage</comments>
      <itunes:summary> We&#39;ll be posting one project each month but here is the Coding4Fun booth at PDC 2009!&amp;nbsp; You can even view the Iron Bartender challenge at GeekFest as well! Overall Recap of each project  &amp;nbsp; Iron Bartender!  &amp;nbsp; </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/Coding4Fun-at-PDC-2009--Video-Montage</link>
      <pubDate>Fri, 04 Dec 2009 15:25:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/Coding4Fun-at-PDC-2009--Video-Montage</guid>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/Coding4Fun-at-PDC-2009--Video-Montage/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>WPF</category>
      <category>XNA</category>
      <category>XNA framework</category>
      <category>C4FNews</category>
      <category>wiimote</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Wiimote Virtual Reality Desktop</title>
      <description><![CDATA[
<table border="0" cellspacing="0" cellpadding="1" width="100%">
<tbody>
<tr class="entry_overview">
<td></td>
<td>In this article I want to introduce a Virtual Reality system that can be build with two Nintendo Wii Remotes (Wiimotes) and just a little extra hardware that costs less than $10 USD.</td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">&nbsp;</div>
<div class="entry_author"><a href="http://www.vrhome.de/" target="_blank">Timo Fleisch</a></div>
<div class="entry_author">&nbsp;</div>
<div class="entry_details"><b></b></div>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Expert</span></div>
<div class="entry_details"><b>Time Required:</b> 3-4<span class="entry_details_input"> hours</span></div>
<div class="entry_details"><b>Cost: </b>: $80 for two Wiimotes, ~$20 for IR-LEDs, stripboards, battery holder</div>
<div class="entry_details"><b>Software: </b><a href="http://www.microsoft.com/express/vcsharp/" target="_blank">Visual C# Express Edition 2008</a>,
<a href="http://creators.xna.com/" target="_blank">XNA Games Studio 3.0</a>, <a href="http://www.codeplex.com/WiimoteLib" target="_blank">
Managed Library for Nintendo's Wiimote</a>, <a href="http://opencv.willowgarage.com/wiki/" target="_blank">
OpenCV Computer Vision Library</a> and <a href="http://www.emgu.com/wiki/index.php/Main_Page" target="_blank">
EmguCV C# Wrapper</a></div>
<div class="entry_details"><b>Hardware: </b>Two Nintendo Wii Remote (Wiimote), Anaglyph 3D Glasses (Red/Green Glasses) or Zalman 3D Monitor, compatible PC Bluetooth adapter and stack</div>
<div class="entry_details"><b>Download Binary: </b><a href="http://vrhome.de/vrdesktopsetup.exe" target="_blank">Download</a></div>
<div class="entry_details"><b>Download Source: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/VRDesktopSrc.zip" target="_blank">Download</a></div>
</td>
</tr>
</tbody>
</table>
<h4>Introduction</h4>
<p>The term Virtual Reality (VR) has been around many years by now but is still associated with very special and expensive hardware that is only available for research laboratories or big companies. Most people might think of a setup where the user wears a
 head-mounted-display and a data glove. Technically speaking Virtual Reality is defined by two things:</p>
<ul>
<li>Immersion and </li><li>Interactivity </li></ul>
<p>By immersion is meant, that the user gets the impression of being inside a computer generated world. Usually VR systems use stereoscopic output devices to give the user a real 3D impression of the virtual world. But besides visual immersion, haptic and acoustic
 can also play an important role.</p>
<p>3D images can for example be experienced in IMAX 3D cinemas – but this is still no Virtual Reality. What is missing is the interactivity. When the user is able to interact with the virtual world, by navigation and manipulation of the objects then the definition
 for VR is complete.</p>
<p>In this article I want to introduce a Virtual Reality system that can be build with two Nintendo Wii Remotes (Wiimotes) and just a little extra hardware that costs less than 10 USD. By that VR should be affordable for everyone. The demo software and source
 can be downloaded from my website: <br>
<a href="http://www.vrhome.de" target="_blank">http://www.vrhome.de</a>.</p>
<div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:313bfb23-8e16-4be6-94d5-db05144cffed" class="wlWriterEditableSmartContent">
<div id="dd7579ad-f36e-40b9-980a-d1b7bd53880e">
<div><a href="http://www.youtube.com/watch?v=eLy9AWi67XU&amp;hl=en&amp;fs=1" target="_new"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/video838d632e3098.jpg" alt=""></a></div>
</div>
</div>
<h4>Virtual Reality Desktop</h4>
<p>A VR Desktop setup uses a monitor as 3D output display and is sometimes referred to as fishtank Virtual Reality. I use a stereo monitor that needs a pair of polarization glasses to display stereo images. If you don't own a stereo monitor you can still construct
 the VR Desktop by using the anaglyph or red/green stereo method. For that you just need a pair of red/green glasses and you can use any monitor. Even though you loose color information the stereo effect is still very good.</p>
<p>For interactivity the two Wiimotes come into play. In this setup there are two kinds of interaction possible. First we have a kind of navigation support. Navigation inside a rendered 3D scenes means the movement of the camera, as the camera represents the
 eyes of the user. For the Desktop setup this means we have to track the users' eyes or head position to move the 3D scene camera correctly – therefore this is also called head tracking. For the head tracking I mount one Wiimote at the top of the monitor to
 point at the user's face.</p>
<p>The second Wiimote is mounted from the top in vertical down position facing the area in front of the monitor. This will be used to interact with the 3D scene by manipulating the transformation of a 3D object. As you use the hand for this interaction I call
 this hand tracking. The Virtual Reality Desktop setup is shown in Picture 1.</p>
<h4>Wiimote 6DOF Tracking</h4>
<p>The core of this VR setup is using the Nintendo Wiimote Controller as a tracking camera. As one might already know the Wiimote is equipped with an infra-red camera that is able to recognize up to four infra-red lights. The main idea now is to build a device
 with four infra-red LEDs that can be recognized by the Wiimote. This device I call IR-LED beacon. Using the values of the 4 LEDs as recognized by the Wiimote I use an algorithm to reconstruct the original position and orientation of the IR-LED beacon. Getting
 all 3 axis translations and all 3 axis rotation angles of the device is called 6 degree of freedom tracking – or short 6DOF tracking.</p>
<h4><a title="TOC-IR-LED-Beacon1" name="TOC-IR-LED-Beacon1"></a>IR-LED Beacon</h4>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/wiimotevrdesktop1.jpg"><img title="OLYMPUS DIGITAL CAMERA         " border="0" alt="OLYMPUS DIGITAL CAMERA         " src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/wiimotevrdesktop1_thumb.jpg" width="166" height="244"></a>
<br>
<strong>Picture 1: Wiimote Desktop Virtual Reality Setup</strong></p>
<p>Because this setup uses head tracking as well as a tracking for a hand manipulation two beacon have to be built. In pictures 2 and 3 the beacons that I built for my setup are shown.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/IRbeaconheadtracker.jpg"><img title="IR-beacon headtracker" border="0" alt="IR-beacon headtracker" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/IRbeaconheadtracker_thumb.jpg" width="244" height="145"></a>
<br>
<strong>Picture 2: Head Tracking IR-LED Beacon</strong></p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/IRbeaconhandtracker.jpg"><img title="OLYMPUS DIGITAL CAMERA         " border="0" alt="OLYMPUS DIGITAL CAMERA         " src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/IRbeaconhandtracker_thumb.jpg" width="244" height="195"></a>
<br>
<strong>Picture 3: Hand Tracking IR-LED Beacon</strong></p>
<p>As can bee seen the beacons just consist of 4 IR-LEDs, a battery holder and wiring. For easy construction and less wiring I use a stripboard. When choosing the IR-LEDs it is important to look out for a very wide angle of radiation. Typical LED just have
 a small angle, try to find LEDs with angles greater than 120°, a good source might be digikey.com. Three of the four LEDs are aligned in a line with only slightly different height. The fourth LED is mounted above the line with more height. This special order
 of the lights is needed by the algorithm to be able to assign the IR-points recognized by the Wiimote to the original LEDs of the beacon. It is also important that the fourth LED has not the same height, so that the LEDs are not so planar. Please see picture
 4 for a schematic layout of the beacon. For power supply I just us on AAA battery and connect all LEDs in parallel to the battery poles. For easy handling I use a battery holder which are also available at electronic components supply stores.
</p>
<p>After soldering everything together the exact positions of the LEDs have to be measured in the correct order. It is very important to measure the 3D position of the LED lights very accurately. If the data for these coordinates is not accurate the tracking
 results will be poor. The values have to be in millimeters. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/led.png"><img title="led" border="0" alt="led" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9412433/led_thumb.png" width="260" height="157"></a>
<br>
<strong>Picture 4: Schematic of IR-LED Beacon</strong></p>
<p>For example, my LEDs have the following measurements:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;1, 0, 8.5&quot;</span><span>/&gt;</span><br><span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;29, 0, 11&quot;</span><span>/&gt;</span><br><span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;56, 0, 6&quot;</span><span>/&gt;</span><br><span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;29, 45, 21&quot;</span><span>/&gt;</span></pre>
<br>
</div>
<p>&nbsp;</p>
<h4>Configuring the Software</h4>
<p>After position the Wiimotes as shown and constructing and measuring the beacons you have to configure the software using two configuration files. You will find the files in the application's directory.</p>
<h5>Settings.xml</h5>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>Settings</span><span>&gt;</span> <br>    <span>&lt;</span><span>Stereo</span><br>        <span>eyeDistance</span> = <span>&quot;0.02&quot;</span><br>        <span>switchLeftRight</span> = <span>&quot;False&quot;</span><br>        <span>fieldOfView</span> = <span>&quot;60&quot;</span><br>        <span>antiAlias</span> = <span>&quot;False&quot;</span><br>        <span>stereoMode</span> = <span>&quot;lineInterlaced&quot;</span><br>        <span>fullscreen</span> = <span>&quot;False&quot;</span><br>        <span>resolution</span> = <span>&quot;1280,1024&quot;</span><br>        <span>displayDevice</span> = <span>&quot;Screen&quot;</span><br>        <span>anaglyph</span> = <span>&quot;True&quot;</span><br>        <span>windowPosition</span> = <span>&quot;0,0&quot;</span> <span>/&gt;</span><br><span>&lt;/</span><span>Settings</span><span>&gt;</span></pre>
<br>
</div>
<div id="codeSnippetWrapper"><br>
</div>
<p>If you own a line-interlaced 3D Monitor from Zalman, you can change the anaglyph to False. If you have difficulties adjusting your eyes to the stereo image you can try changing the value for the eyeDistance. Reducing the value makes it easier to adjust but
 might reduce the 3D effect. The other parameters should work as you might expect from the name.</p>
<h5>Tracker.xml</h5>
<p>In this file the configuration for the tracking is stored. It defines the Wiimotes and its positions and the IR-LED beacons. Furthermore it defines filtering parameters. Here I will point to the places where you need to adjust the values for your setup.
</p>
<p>First you will need to specify the exact position of your Wiimotes relative to the center of the screen. You need to measure this distance for each Wiimote in millimeter. Probably the values will be similar to the default values:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>TrackerCam</span> <br>    <span>id</span><span>=&quot;2&quot;</span> <span>cameramodel</span><span>=&quot;Wiimote&quot;</span> <br>    <span>translation</span><span>=&quot;0,200,50&quot;</span> <br>    <span>rotation</span><span>=&quot;0,0,0&quot;</span> <span>scale</span><span>=&quot;0.001&quot;</span> <br>    <span>xAxis</span><span>=&quot;x&quot;</span> <span>yAxis</span><span>=&quot;y&quot;</span> <span>zAxis</span><span>=&quot;z&quot;</span><span>&gt;</span> <br><span>&lt;/</span><span>TrackerCam</span><span>&gt;</span><br><span>&lt;</span><span>TrackerCam</span><br>    <span>id</span><span>=&quot;1&quot;</span> <span>cameramodel</span><span>=&quot;Wiimote&quot;</span><br>    <span>translation</span><span>=&quot;0,350,350&quot;</span> <span>rotation</span><span>=&quot;0,0,0&quot;</span> <span>scale</span><span>=&quot;0.001&quot;</span><br>    <span>xAxis</span><span>=&quot;x&quot;</span> <span>yAxis</span><span>=&quot;z&quot;</span> <span>zAxis</span><span>=&quot;y&quot;</span><span>&gt;</span><br><span>&lt;/</span><span>TrackerCam</span><span>&gt;</span></pre>
<br>
</div>
<div id="codeSnippetWrapper"><br>
</div>
<p>&nbsp;</p>
<p>The Wiimote with id=2 is the one mounted at the top of the monitor to do the head tracking. In the translation field enter the distance of the front tip of the Wiimote to the center of the screen. In the default settings the Wiimote is 200mm above (y-value)
 and 50mm in front (z-value) of the center. Do the same for the second Wiimote in the following entry with id=1. You can see, that here the y-axis is assigned to the z-axis and the z-axis is assigned to the y-axis. This is necessary because the Wiimote is mounted
 in vertical position. If the software recognizes the Wiimotes in wrong order you can exchange the order of the definition blocks.</p>
<p>The second part where you need to make changes is the definition of the IR-LED-Beacons:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>MarkerBody</span><span>&gt;</span><br>    <span>&lt;</span><span>WiiMarkerBody</span> <span>id</span><span>=&quot;0&quot;</span> <span>name</span><span>=&quot;WiiMote Head Beacon&quot;</span> <span>nearClip</span><span>=&quot;20&quot;</span><br>        <span>farClip</span><span>=&quot;1500&quot;</span> <span>translation</span><span>=&quot;0,0,0&quot;</span> <span>rotation</span><span>=&quot;0,0,0&quot;</span><span>&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;0, 4, 7&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;40, 4.5, 10.5&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;83.5, 5, 7.5&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;38, 45, 18&quot;</span><span>/&gt;</span><br>    <span>&lt;/</span><span>WiiMarkerBody</span><span>&gt;</span><br>    <span>&lt;</span><span>WiiMarkerBody</span> <span>id</span><span>=&quot;4&quot;</span> <span>name</span><span>=&quot;WiiMote Hand Beacon&quot;</span> <span>nearClip</span><span>=&quot;20&quot;</span> <br>        <span>farClip</span><span>=&quot;1500&quot;</span> <span>translation</span><span>=&quot;0,0,0&quot;</span> <span>rotation</span><span>=&quot;0,0,0&quot;</span><span>&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;1, 0, 8.5&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;29, 0, 11&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;56, 0, 6&quot;</span><span>/&gt;</span><br>        <span>&lt;</span><span>point3d</span> <span>value</span><span>=&quot;29, 45, 21&quot;</span><span>/&gt;</span><br>    <span>&lt;/</span><span>WiiMarkerBody</span><span>&gt;</span><br><span>&lt;/</span><span>MarkerBody</span><span>&gt;</span></pre>
<br>
</div>
<p>&nbsp;</p>
<p>Here you need to change the values for the beacon points in millimeter according to your measurements. Please note that the correct order of the points is necessary. They have to be from LED1 to LED4 according to the schematic in Picture 4.</p>
<p>Furthermore you will find a description for the tracked device:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>TrackedDevice</span> <span>id</span><span>=&quot;4&quot;</span> <span>type</span><span>=&quot;WiiMote&quot;</span> <span>rotation</span><span>=&quot;True&quot;</span> <span>translation</span><span>=&quot;True&quot;</span><span>&gt;</span><br>    <span>&lt;</span><span>MarkerBodyId</span><span>&gt;</span>0<span>&lt;/</span><span>MarkerBodyId</span><span>&gt;</span><br>    <span>&lt;</span><span>TrackerCamId</span><span>&gt;</span>2<span>&lt;/</span><span>TrackerCamId</span><span>&gt;</span><br>    <span>&lt;</span><span>ReverseTranslation</span><span>&gt;</span>False,True,True<span>&lt;/</span><span>ReverseTranslation</span><span>&gt;</span><br>    <span>&lt;</span><span>ReverseRotation</span><span>&gt;</span>False,False,False<span>&lt;/</span><span>ReverseRotation</span><span>&gt;</span><br>    <span>&lt;</span><span>LocalTranslation</span><span>&gt;</span>-45,25,0<span>&lt;/</span><span>LocalTranslation</span><span>&gt;</span><br>    <span>&lt;</span><span>LocalRotation</span><span>&gt;</span>0,0,0<span>&lt;/</span><span>LocalRotation</span><span>&gt;</span><br>    <span>&lt;</span><span>WorldTranslation</span><span>&gt;</span>0,0,0<span>&lt;/</span><span>WorldTranslation</span><span>&gt;</span><br>    <span>&lt;</span><span>WorldRotation</span><span>&gt;</span>0,0,0 <span>&lt;/</span><span>WorldRotation</span><span>&gt;</span><br>    <span>&lt;</span><span>RotationFilterId</span><span>&gt;</span>4<span>&lt;/</span><span>RotationFilterId</span><span>&gt;</span><br>    <span>&lt;</span><span>TranslationFilterId</span><span>&gt;</span>4<span>&lt;/</span><span>TranslationFilterId</span><span>&gt;</span><br><span>&lt;/</span><span>TrackedDevice</span><span>&gt;</span></pre>
<br>
</div>
<p>Here you assign which Wiimote (TrackedCamId) to use with which IR-LED-Beacon (MarkerBodyId). The only value that you might want to adjust from these settings is the LocalTranslation. The translation and rotation values that are calculated need to have their
 reference point on the beacon. By default the first LED will be this reference. Usually you want to have a different reference point, like the center of the beacon. Therefore measure the distance from the first LED to your preferred reference point in the
 same metric as the beacon values and write it in the LocalTranslation.</p>
<p>There are lot of more parameters you can tweak inside this configuration file, but to make the VR-Desktop run this shouldn't be necessary.</p>
<h4>Run the Software</h4>
<p>Before running the software it is necessary to connect the Wiimotes with the computer. For that the computer needs to be equipped with a compatible Bluetooth adapter. For more detailed description on how to do that please refer to Brian Peek's Wiimote Library
 article: </p>
<p><a href="http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx">http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx</a></p>
<p>After putting in your values in the configuration files and placement and connection of the two Wiimotes you can run the binary installation by clicking on the VRDesktoDemo in the start menu. If you want to run from the source code you have to copy the OpenCV
 dlls from <i>(VRDesktopSrc)</i>\<i>ExtLibs\OpenCV\opencvlib</i> to the binary destination directory of the compiled project, e.g. (<i>VRDesktopSrc)\VRDesktopDemo\bin\x86\Release
</i>before you can start the application.</p>
<h4>Using the Library</h4>
<p>Using the VRDesktop in your own XNA application is very easy. Here I will point out the relevant steps from the VRDesktopDemo application.</p>
<p>To start from scratch you will have to create a new XNA Windows Game Project. First include the references to the two libraries Tgex and Tvrx. Then open the created Game class.</p>
<p>At the top the namespaces for libraries have to be added:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>using</span> Tgex.Graphics;<br><span>using</span> Tgex;<br><span>using</span> Tvrx;</pre>
<br>
</div>
<p>&nbsp;</p>
<p>Then the parent class has to be changed from Game to VRGame:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>class</span> VRDesktop : VRGame</pre>
<br>
</div>
<p>VRGame is part of the Tgex library and adds the support for the stereo display. It creates a stereo camera and the application window according to the settings file. You can use the class more or less similar to the original game class. The main difference
 is, that for the drawing you must not override the Draw(GameTime time) function but the new DrawScene(GameTime time) because the Draw function of the VRGame class takes care about the stereo rendering.</p>
<p>For storing the transformation matrix of the hand tracker we define a variable:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">Matrix modelTransform = Matrix.Identity;</pre>
<br>
</div>
<p>And in this simple example we define a variable for the model:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">Model model;</pre>
<br>
</div>
<p>In the Initialize function the initialization of the TrackerManager needs to be done:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>protected</span> <span>override</span> <span>void</span> Initialize()<br>{<br>    <span>// The tracker manager is a singleton but needs to be initialized once.</span><br>    TrackerManager.Instance.Initialize();<br><br>    <span>// initialize base clase.</span><br>    <span>base</span>.Initialize();<br>}</pre>
<br>
</div>
<p>In the LoadContent function the model is loaded and the tracking is started:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>protected</span> <span>override</span> <span>void</span> LoadContent()<br>{<br>    <span>// for this demo just load the coordinate cross</span><br>    model = Content.Load&lt;Model&gt;(<span>&quot;coordinate&quot;</span>);<br>    modelTransforms = <span>new</span> Matrix[model.Bones.Count];<br><br>    <span>// start tracking now</span><br>    TrackerManager.Instance.StartTracking();<br>}</pre>
<br>
</div>
<p>The Update function is for the main game logic. First we allow the user to exit the game and the tracker to stop regularly:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// Allows the default game to exit on Xbox 360 and Windows</span><br><span>if</span> ((GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)<br>    || (Keyboard.GetState().IsKeyDown(Keys.Escape)))<br>{<br>    TrackerManager.Instance.StopTracking();<br>    <span>this</span>.Exit();<br>}</pre>
<br>
</div>
<div id="codeSnippetWrapper"><br>
</div>
<p>Before getting the latest tracking data we have to call an update on the TrackerManager:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">TrackerManager.Instance.Update();</pre>
<br>
</div>
<p>To get the transformation data we have to call the GetProxyTransform(indexNumber) from the manager. The proxies are defined in the tracking.xml file. In the example we call:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// tracking proxy with id 1 is the hand tracker</span><br>modelTransform = TrackerManager.Instance.GetProxyTransform(1);<br><br><span>// tracking proxy with id 0 is the head tracker - change eye position.</span><br>m_camera.EyePosition = <br>    TrackerManager.Instance.GetProxyTransform(0).Translation;</pre>
<br>
</div>
<p>The m_camera is defined in the VRGame parent class. The camera class will also make the necessary camera transformation adjustments for screen projected head-tracking by creating a perspective of center projection matrix.</p>
<p>Finally in the DrawScene function the model mesh is drawn. Here we need to pass the model transformation matrix as well as the camera matrices to the effect:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>//Draw the model, a model can have multiple meshes, so loop</span><br><span>foreach</span> (ModelMesh mesh <span>in</span> model.Meshes)<br>{<br>    <span>//This is where the mesh orientation is set, as well </span><br>    <span>// as our camera and projection</span><br>    <span>foreach</span> (BasicEffect effect <span>in</span> mesh.Effects)<br>    {<br>        effect.EnableDefaultLighting();<br>        effect.World = modelTransforms[mesh.ParentBone.Index]<br>                       * Matrix.CreateScale(0.01f) <span>// coordinate scale</span><br>                       * modelTransform;<br>        effect.View = m_camera.ViewMatrix;<br>        effect.Projection = m_camera.ProjectionMatrix;<br>    }<br><br>    <span>//Draw the mesh, will use the effects set above.</span><br>    mesh.Draw();<br>}</pre>
<br>
</div>
<p>That's all what has to be done to make use of the Wiimote Virtual Reality Desktop in your own application.</p>
<h4>How does it work</h4>
<p>For the interested reader I will explain now in more detail how the Wiimote tracking actually works. Anyhow, I will not go into the mathematical details of the core algorithm but provide you with the necessary references. I will just focus on the Wiimote
 tracking part and will not go into details of neither the tracking library Tvrx nor the game library Tgex.</p>
<h5><a title="TOC-Pose-Estimation" name="TOC-Pose-Estimation"></a>Pose Estimation</h5>
<p>Technically speaking, the Wiimote tracking is an optical marker based tracking. It is optical because we use the Wiimote camera and it is marker based, because we don't use the whole camera image. Instead the Wiimote returns the position of up to four infrared
 LEDs which represent our markers. <br>
The four LED positions are given in 2D coordinates which represent the markers as seen by the camera. Technically this is a 2D projection of the real LEDs according to the focus of the camera lens, this projection plane is called image plane - the 2D coordinated
 are therefore called image points. <br>
The main task now is to calculate the position and rotation of the IR-LED Beacon in real space according to the image points of the LEDs measured by the Wiimote. This task is called Pose Estimation and has been investigated by scientists since many years. One
 main application of pose estimation is computer vision for robotics. The pose estimation algorithm used for the Wiimote tracking has already been published in 1995 and still performs nice for our purpose. If you are interested in the exact details about how
 the pose estimation algorithm works, you can study the original paper, please see the references.
<br>
To be able to perform the pose estimation calculation you need the exact information about the image plane. Actually, the plane is nothing else then the image sensor of the camera. The picture is focused on the image sensor by the camera lens. For the calculation
 of the projection we need a mathematical model for the camera, in computer vision usually a pinhole camera model is used. The pinhole is the projection point origin. The image plane is at a certain distance from the origin. This distance is called focus length.
<br>
Now, what we need for the calculation is the focal length and the size of image plane, the camera sensor. These values are also called the intrinsic camera values. Unfortunately Nintendo does not publish these values for the Wiimote, so the values I use are
 assumptions: <br>
focal length in pixel = 1380</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// assume 1/4&quot; cd sensor (even though it probably is not)</span><br>pixel size <span>in</span> mm = 0.0035<br>chip resolution = 1024x768<br><br><span>// Wiimote center (approx.)</span><br>principal point = 512x384</pre>
<br>
</div>
<p>The resolution of the values returned by the Wiimote are 1024x768. Obviously this is not the physical resolution because cameras with this resolution would cost more than 1000 USD. The Wiimote has a PixArt Imaging Inc. (<a href="http://www.pixart.com.tw/">http://www.pixart.com.tw</a>)
 sensor and probably has a resolution of 352x288 or 164x124. However, trying to guess the real values with the help of the PixArt Sensor data sheets did not work out satisfactory so I decided to fix the pixel size and resolution on the above values and estimate
 the focal length. Even thought the values are not correct, they only need to be correct relative to each other to make the pose estimation work. The principal point is the actual origin of the image plane. Ideally this value should be measured, here I just
 assume it is the middle of the sensor chip.</p>
<h5>Overview of the tracking algorithm</h5>
<p>The overall tracking algorithm can be divided in the following steps:</p>
<ul>
<li>Retrieve the image point values of the infrared LEDs from the Wiimote. </li><li>Assign the image points to the LED beacon lights. </li><li>Run the pose estimation to calculate the rotation and translation of the LED beacon.
</li><li>Filter the resulting rotation and translation values. </li><li>Build a transformation matrix and transform the result according to configuration file.
<br>
(Wiimote position and orientation and local LED beacon transformation) </li></ul>
<p>In the following I will describe the steps in more detail and with code examples.</p>
<h6>Retrieve image points</h6>
<p>The connection and data retrieval with the Wiimote is done in the WiiMoteTracker class. This class implements the interface IMarkerTracker, that defines the interface for an optical marker based tracker. The Wiimote is initialized in the Initialize() function
 and connected when StartTracking() is called :</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>void</span> Initialize()<br>{<br>    <span>// test static variable for first time call</span><br>    <span>if</span> (m_wiimoteCount == 0)<br>        m_wiimoteCollection.FindAllWiimotes();<br><br>    <span>if</span> (m_wiimoteCollection.Count &lt;= m_wiimoteCount)<br>    {<br>        ErrorHandler.Report(<span>&quot;Invalid WiimoteTracker count, only &quot;</span><br>        &#43; m_wiimoteCollection.Count.ToString() &#43; <span>&quot; Wiimotes found&quot;</span>);<br>        <span>return</span>;<br>    }<br><br>    wm = m_wiimoteCollection.ElementAt(m_wiimoteCount);<br>    m_wiimoteId = m_wiimoteCount;<br>    m_wiimoteCount&#43;&#43;;<br><br>    <span>// setup the event to handle state changes</span><br>    wm.WiimoteChanged &#43;= wm_WiimoteChanged;<br><br>    <span>// setup the event to handle insertion/removal of extensions</span><br>    wm.WiimoteExtensionChanged &#43;= wm_WiimoteExtensionChanged;<br><br>    <span>// create filter for accelerator values</span><br>    AverageFilterDesc filterDesc = <span>new</span> AverageFilterDesc();<br>    filterDesc.numOfValues = 1000;<br><br>    <span>for</span> (<span>int</span> i = 0; i &lt; 3; i&#43;&#43;)<br>    {<br>        m_acceleratorFilter[i] = <span>new</span> AverageFilter();<br>        m_acceleratorFilter[i].SetFilterDesc(filterDesc);<br>    }<br><br>    <span>// create filter for image points</span><br>    filterDesc = <span>new</span> AverageFilterDesc();<br>    filterDesc.numOfValues = 5;<br><br>    <span>for</span> (<span>int</span> i = 0; i &lt; 8; i&#43;&#43;)<br>    {<br>        m_imagePointsFilter[i] = <span>new</span> AverageFilter();<br>        m_imagePointsFilter[i].SetFilterDesc(filterDesc);<br>    }<br>}<br><br><span>public</span> <span>void</span> StartTracking()<br>{<br>    <span>if</span> (!m_isTracking)<br>    {<br>        m_isTracking = <span>true</span>;<br><br>        <span>// connect to the Wiimote</span><br>        <span>try</span><br>        {<br>            wm.Connect();<br><br>            <span>// set the report type to return the IR sensor and accelerometer data </span><br>            <span>// (buttons always come back)</span><br>            wm.SetReportType(InputReport.IRAccel, <span>true</span>);<br>            wm.SetLEDs(m_wiimoteId);<br>        }<br>        <span>catch</span><br>        {<br>            ErrorHandler.Report(<span>&quot;Cannot connect to Wiimote&quot;</span>);<br>            m_isTracking = <span>false</span>;<br>        }<br>    }<br>}</pre>
<br>
</div>
<p>To receive the Wiimote data the <i>wm_WiimoteChanged </i>Callback has been registered. This function is then called whenever the Wiimote has updated values. Inside this function the infrared LED values are read and the LED beacon light assignment is done.</p>
<p>For that, first a list with with Vector2 for the image points is created:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// put in list</span><br>irList.Clear();<br><br><span>for</span> (<span>int</span> i = 0; i &lt; 4; i&#43;&#43;)<br>    irList.Add(<span>new</span> Vector2((<span>float</span>)<br>           (ws.IRState.IRSensors[i].Position.X * m_resolution.X) - m_principalPoint.X,<br>           (<span>float</span>)(ws.IRState.IRSensors[i].Position.Y * m_resolution.Y) - m_principalPoint.Y));</pre>
<br>
</div>
<h6>Assign image points</h6>
<p>Then the values have to be assigned to the IR-LEDs by putting them into the right order. This is done by a simple geometric pattern recognition. The idea is to have a geometric pattern that is invariant to the projection from 3D to 2D. As can be seen in
 picture 4, the 3 LEDs of the LED beacon are arranged in more or less a line and the 4<sup>th</sup> LED is above of the line. In the 2D image data of the Wiimote the 3 LEDs also form more or less a line. Therefore, the first step in the assignment algorithm
 is to find the 3 image points which are most close to form a line.The line test is done in the following function:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>void</span> TestPoints(Vector2 lineStartPoint, Vector2 lineEndPoint,<br>                Vector2 onLinePoint, Vector2 freePoint)<br>{<br>    <span>float</span> lambda;<br>    <span>float</span> dist = onLinePoint.DistanceToLine(lineStartPoint, lineEndPoint, <span>out</span> lambda);<br><br>    <span>// check if projected point is between line end and start point</span><br>    <span>if</span> ((lambda &gt; 0) &amp;&amp; (lambda &lt; 1))<br>    {<br>        <span>// if distance is short, make this combination the result</span><br>        <span>if</span> (dist &lt; m_pointLineDist)<br>        {<br>            m_pointLineDist = dist;<br>            m_lineStartPoint = lineStartPoint;<br>            m_lineEndPoint = lineEndPoint;<br>            m_onLinePoint = onLinePoint;<br>            m_freePoint = freePoint;<br>        }<br>    }<br>}</pre>
<br>
</div>
<p>The function is called with the four image points as input. It assumes the first point to be the line start point and the second point to be the line end point. Then the distance of the third point to the line is calculated. This is done by using a C# 3.0
 extension function of Vector2:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>static</span> <span>float</span> DistanceToLine(<span>this</span> Vector2 point,<br>                                   Vector2 startLinePoint,<br>                                   Vector2 endLinePoint,<br>                                   <span>out</span> <span>float</span> lambda)<br>{<br>    Vector2 rv = endLinePoint - startLinePoint;<br>    Vector2 p_ap = point - startLinePoint;<br>    <span>float</span> dot_rv = Vector2.Dot(rv, rv);<br>    lambda = Vector2.Dot(p_ap, (rv / dot_rv));<br>    Vector2 distVec = point - (startLinePoint &#43; lambda * rv);<br>    <span>return</span> distVec.Length();<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<p>The line distance test is a typical algorithm as described on: <a href="http://mathenexus.zum.de/html/geometrie/abstaende/AbstandPG.htm">
http://mathenexus.zum.de/html/geometrie/abstaende/AbstandPG.htm</a></p>
<p>It returns the distance to the line and an lambda value, which defines the position of the line projected point. If the projection point is outside the line start and line end point the lambda will be below 0 or greater than 1.</p>
<p>If the line was valid the distance of the third point is compared to the formerly smallest distance, and if it is smaller, then this order of image points will be saved as best solution.</p>
<p>To find the right order of the image points this function has to be called with all possible combinations of the 4 LED image points. In my code I do all the calls explicitly after initializing the minimum distance with float max value:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">m_pointLineDist = <span>float</span>.MaxValue;<br><br><span>// write all test cases explicite</span><br><span>// in the end the three point line should be found</span><br>TestPoints(irList[0], irList[1], irList[2], irList[3]);<br>TestPoints(irList[0], irList[1], irList[3], irList[2]);<br>TestPoints(irList[0], irList[2], irList[1], irList[3]);<br>TestPoints(irList[0], irList[2], irList[3], irList[1]);<br>TestPoints(irList[0], irList[3], irList[1], irList[2]);<br>TestPoints(irList[0], irList[3], irList[2], irList[1]);<br>TestPoints(irList[1], irList[2], irList[0], irList[3]);<br>TestPoints(irList[1], irList[2], irList[3], irList[0]);<br>TestPoints(irList[1], irList[3], irList[0], irList[2]);<br>TestPoints(irList[1], irList[3], irList[2], irList[0]);<br>TestPoints(irList[2], irList[3], irList[0], irList[1]);<br>TestPoints(irList[2], irList[3], irList[1], irList[0]);</pre>
<br>
</div>
<p>Now that we have the right order of the three points that form the line and the 4<sup>th</sup> point, it is still necessary to determine the right direction of the line. In our LED beacon the 4<sup>th</sup> LED is above the line. If the start and end point
 of the line would be interchanged then the 4<sup>th</sup> LED would be below the line. Mathematically we check if the order of the points is clockwise or counterclockwise:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// only remaing test is check if line start and </span><br><span>// end point is in right order</span><br><span>// check start and end line point with free point</span><br><span>// if clockwise direction then ok, if counterclockwise then exchange start </span><br><span>// and end point</span><br><br>Vector2 E1 = m_lineStartPoint - m_freePoint; <span>// P1-P2 </span><br>Vector2 E2 = m_lineEndPoint - m_freePoint; <span>// P3-P2 </span><br><span>bool</span> clockwise;<br><span>if</span> ((E1.X * E2.Y - E1.Y * E2.X) &gt;= 0)<br>    clockwise = <span>true</span>;<br><span>else</span><br>    clockwise = <span>false</span>;<br><br><span>if</span> (!clockwise)<br>{<br>    Vector2 tmp = m_lineEndPoint;<br>    m_lineEndPoint = m_lineStartPoint;<br>    m_lineStartPoint = tmp;<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<p>The algorithm for the clockwise check is taken from</p>
<p><a href="http://www.geocities.com/siliconvalley/2151/math2d.html" target="_blank">http://www.geocities.com/siliconvalley/2151/math2d.html</a></p>
<p>Then the correctly ordered points are slightly filtered with a simple average filter over the last 5 values and multiplied with the pixel size the change from pixel metric to millimeter metric. Finally the points are passed to the pose estimation class.</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// now write resulting order to image points</span><br>m_imagePoints[0].X = m_imagePointsFilter[0].Filter(m_lineStartPoint.X);<br>m_imagePoints[0].Y = m_imagePointsFilter[1].Filter(m_lineStartPoint.Y);<br>m_imagePoints[1].X = m_imagePointsFilter[2].Filter(m_onLinePoint.X);<br>m_imagePoints[1].Y = m_imagePointsFilter[3].Filter(m_onLinePoint.Y);<br>m_imagePoints[2].X = m_imagePointsFilter[4].Filter(m_lineEndPoint.X);<br>m_imagePoints[2].Y = m_imagePointsFilter[5].Filter(m_lineEndPoint.Y);<br>m_imagePoints[3].X = m_imagePointsFilter[6].Filter(m_freePoint.X);<br>m_imagePoints[3].Y = m_imagePointsFilter[7].Filter(m_freePoint.Y);<br><br><span>for</span> (<span>int</span> i = 0; i &lt; 4; i&#43;&#43;)<br>{<br>    m_imagePoints[i] *= m_pixelSize;<br>}<br><br><span>// send points to estimation</span><br>m_poseEstimate.UpdateImagePoints(m_imagePoints);</pre>
<br>
</div>
<p>&nbsp;</p>
<h6>Run pose estimation</h6>
<p>The pose estimation is done by the class Posit. This class implements the IPoseEstimate interface:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>interface</span> IPoseEstimate<br>{<br>    <span>void</span> InitializeCameraParameter(<span>double</span> focalLengthMM, <span>bool</span> flipImage,<br>                        <span>float</span> scale, <span>int</span>[] assignAxis, <span>int</span>[] assignAxisSign);<br>    <span>void</span> InitializeMarkerBody(Vector3[] markerPoints);<br>    <span>void</span> UpdateImagePoints(Vector2[] imagePoints);<br>    <span>void</span> GetTransform(<span>out</span> Vector3 position, <span>out</span> Vector3 rotation);<br>    <span>void</span> StartEstimation();<br>    <span>void</span> StopEstimation();<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<p>The pose estimation has to be initialized with the focal length of the tracking camera. The 3D positions of the real device – in our case the LEDs of the LED beacon – are passed in the InitializateMarkerBody function. The measured image points are passed
 with the UpdateImagePoints call and the calculated result can be taken from the GetTransform function. Because the pose estimation itself runs in an own thread asynchronously it has to be started and stopped by StartEstimation and StopEstimation. By using
 the interface it is easy to plug in different pose estimation algorithms.</p>
<p>As mentioned before the pose estimation algorithm used here is the PosIt algorithm published by D. DeMenthon. I use the implementation from the OpenCV computer vision library. As this library is C code it has to wrapped to manage code. I use the freely available
 wrapper EmguCV. Before the pose estimation can be done a pose estimation object has to be created. This is done when the 3D positions of the markers are passed:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>void</span> InitializeMarkerBody(Vector3[] markerPoints)<br>{<br>    m_numOfMarker = markerPoints.Length;<br>    MCvPoint3D32f[] worldMarker = <span>new</span> MCvPoint3D32f[m_numOfMarker];<br>    <span>for</span> (<span>int</span> i = 0; i &lt; m_numOfMarker; i&#43;&#43;)<br>    {<br>        worldMarker[i].x = markerPoints[i].X;<br>        worldMarker[i].y = markerPoints[i].Y;<br>        worldMarker[i].z = markerPoints[i].Z;<br>    }<br>    m_positObject = CvInvoke.cvCreatePOSITObject(<br>    worldMarker, m_numOfMarker);<br>    m_imagePoints = <span>new</span> MCvPoint2D32f[m_numOfMarker];<br>    m_imagePointsBuffer = <span>new</span> Vector2[m_numOfMarker];<br>}</pre>
<br>
</div>
<p>MCvPoint32f is a managed structure for the OpenCV CvPoint32f and similar to a Vector3f. The CvInvoke class of the EmguCV wrapper is a collection of static functions to invoke the original OpenCV functions. Because the pose estimation algorithm was not included
 in the class I had to insert the following functions:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>/// &lt;summary&gt;</span><br><span>/// Create pose estimation object</span><br><span>/// &lt;/summary&gt;</span><br>[DllImport(CV_LIBRARY)]<br><span>public</span> <span>static</span> <span>extern</span> IntPtr cvCreatePOSITObject(MCvPoint3D32f[] points, <br>                                                <span>int</span> point_count);<br><span>/// &lt;summary&gt;</span><br><span>/// Do pose estimation</span><br><span>/// &lt;/summary&gt;</span><br>[DllImport(CV_LIBRARY)]<br><span>public</span> <span>static</span> <span>extern</span> <span>void</span> cvPOSIT(IntPtr posit_object, <br>                                  MCvPoint2D32f[] image_points,<br>                                  <span>double</span> focal_length,<br>                                  MCvTermCriteria criteria,<br>                                  <span>float</span>[] rotation_matrix,<br>                                  <span>float</span>[] translation_vector);<br><span>/// &lt;summary&gt;</span><br><span>/// Release pose esitmation object</span><br><span>/// &lt;/summary&gt;</span><br>[DllImport(CV_LIBRARY)]<br><span>public</span> <span>static</span> <span>extern</span> <span>void</span> cvReleasePOSITObject(IntPtr posit_object);</pre>
<br>
</div>
<p>&nbsp;</p>
<p>The returned object of the CvInvoke.cvCreatePOSITObject function call is a simple IntPtr and is used later for the pose estimation function.</p>
<p>The pose estimation itself is done in an own thread in the PoseEstimate() function. First the new image points are fetched. If no update is available we wait for new values. This is done with the Monitor.Wait and Monitor.Pulse mechanism:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// copy image points</span><br>Monitor.Enter(m_imagePointsLock);<br><span>if</span> (!m_imagePointsUpdate)<br>    Monitor.Wait(m_imagePointsLock);<br><br><span>for</span> (<span>int</span> i = 0; i &lt; m_numOfMarker; i&#43;&#43;)<br>{<br>    m_imagePoints[i].x = m_imagePointsBuffer[i].X;<br>    m_imagePoints[i].y = m_imagePointsBuffer[i].Y;<br>}<br>m_imagePointsUpdate = <span>false</span>;<br>Monitor.Exit(m_imagePointsLock);</pre>
<br>
</div>
<p>After getting the new image values the cvPOSIT function is invoked:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">MCvTermCriteria criteria;<br>criteria.type = TERMCRIT.CV_TERMCRIT_EPS | TERMCRIT.CV_TERMCRIT_ITER;<br>criteria.epsilon = 0.00001;<br>criteria.max_iter = 500;<br>CvInvoke.cvPOSIT(m_positObject,m_imagePoints, m_focalLengthMM,<br>                 criteria, POSITRot, POSITTrans);</pre>
<br>
</div>
<p>Because the algorithm is an iterative algorithm the MCvTermCriteria defines when the algorithm should terminate. Here I defined that it should either terminate when either 500 iteration steps have been reached or when the difference of the values from the
 former iteration are smaller than 0.00001. You can play around with these value to see how the tracking accuracy reacts. Besides the termination criteria you have to pass the cvPOSIT function the IntPtr to the posit object, the image points and the camera
 focal length in millimeter. As result you get a 9 float array for the rotation matrix and a 3 float array for the translation result.</p>
<p>Because the rotation values should later be filtered they are translated to euler angels in the EulerAngles function. Euler angles define the rotation by giving the rotation about each coordinate axis. Before storing the final values there is some axis swapping
 and scaling according to the settings in the tracker.xml.</p>
<h6>Filter the estimation results</h6>
<p>Because the resolution of the Wiimote camera is not very hight and optical tracking always to some degree noisy the transformation results have quite strong jitters. To reduce the jittering the result values have to be filtered. As a side effect of strong
 filtering in tracking the virtual object seems not to follow the tracked objects movements directly and feels like swimming behind. A good compromise between jitter reduction and direct response is using Kalman filters. Kalman filters use a mathematical model
 to predict the change of the values and then uses the measured data to correct its prediction. A good introduction to Kalman Filters is the Siggraph 2001 Course from Greg Welch – see References. Anyhow, determine the best parameters for the filter for non-mathematicians
 is difficult. A good reference how to apply the filter in the tracking domain is the dissertation of Ronald Azuma “Predictive Tracking for Augmented Reality”. Please refer to that document if you want to learn the meaning of the parameters. For the Wiimote
 VR-Desktop the Kalman parameters are defined in the tracking.xml file:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>Kalman</span> <span>class</span><span>=&quot;KalmanFilter&quot;</span> <span>id</span><span>=&quot;4&quot;</span> <span>A</span><span>=&quot;1, 0.005, 0, 1&quot;</span> <br>    <span>measurement_noise_cov</span><span>=&quot;1.0&quot;</span> <span>process_noise_cov_1</span><span>=&quot;0.0000001&quot;</span><br>    <span>process_noise_cov_2</span><span>=&quot;0.0000001&quot;</span><span>/&gt;</span></pre>
<br>
</div>
<p>The Kalman implementation used is again part of the OpenCV library. The EmguCV wrapper comes with a complete wrapper for this function. In my implementation there is an interface for data filers, the IDataFilter. The KalmanFilter class implements this interface.
 Beside the Kalman filter there is also a simple AvarageFilter in the library. The initialization of the Kalman filter is like this:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>void</span> SetFilterDesc(DataFilterDesc desc)<br>{<br>    m_kalman = <span>new</span> Kalman(2, 1, 0);<br>    filterDesc = (KalmanFilterDesc)desc;<br>    <span>// set A - second parameter is frames per second</span><br>    m_kalman.TransitionMatrix.Data.SetValue(filterDesc.A[0], 0, 0);<br>    m_kalman.TransitionMatrix.Data.SetValue(filterDesc.A[1], 0, 1);<br>    m_kalman.TransitionMatrix.Data.SetValue(filterDesc.A[2], 1, 0);<br>    m_kalman.TransitionMatrix.Data.SetValue(filterDesc.A[3], 1, 1);<br>    <span>// set H</span><br>    m_kalman.MeasurementMatrix.Data.SetValue(1.0f, 0, 0);<br>    m_kalman.MeasurementMatrix.Data.SetValue(0.0f, 0, 1);<br>    <span>// set Q</span><br>    CvInvoke.cvSetIdentity(m_kalman.ProcessNoiseCovariance.Ptr, <span>new</span> MCvScalar(1));<br>    m_kalman.ProcessNoiseCovariance.Data.SetValue(filterDesc.process_noise_cov_1, 0, 0);<br>    m_kalman.ProcessNoiseCovariance.Data.SetValue(filterDesc.process_noise_cov_2, 1, 0);<br>    <span>// set R</span><br>    CvInvoke.cvSetIdentity(m_kalman.MeasurementNoiseCovariance.Ptr, <span>new</span> MCvScalar(1e-5));<br>    m_kalman.MeasurementNoiseCovariance.Data.SetValue(filterDesc.measurement_noise_cov, 0, 0);<br>    CvInvoke.cvSetIdentity(m_kalman.ErrorCovariancePost.Ptr, <span>new</span> <br>    MCvScalar(500));<br>    m_kalman.ErrorCovariancePost.Data.SetValue(2, 0, 0);<br>}</pre>
<br>
</div>
<p>After initializing a float value can be simply filter in the Filter function:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>float</span> Filter(<span>float</span> inData)<br>{<br>    <span>// Z measurement</span><br>    data.Data[0,0] = inData;<br>    m_kalman.Predict(predict);<br>    m_kalman.Correct(data);<br>    <span>return</span> m_kalman.CorrectedState[0, 0];<br>}</pre>
<br>
</div>
<p>Because in the resulting transformation of the pose estimation there are 3 float values for the translation and 3 float values for the rotation altogether 6 separate instances of the filter are needed. In the Tvrx library the filtering is done inside the
 TrackedDevice class, which is a parent class for tracked devices and is derived to the TrackedWiimote:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>virtual</span> <span>void</span> Filter() <br>{<br>    m_rawTranslation.X = m_translationFilter[0].Filter(m_rawTranslation.X);<br>    m_rawTranslation.Y = m_translationFilter[1].Filter(m_rawTranslation.Y);<br>    m_rawTranslation.Z = m_translationFilter[2].Filter(m_rawTranslation.Z);<br>    m_rawRotation.X = m_rotationFilter[0].Filter(m_rawRotation.X);<br>    m_rawRotation.Y = m_rotationFilter[1].Filter(m_rawRotation.Y);<br>    m_rawRotation.Z = m_rotationFilter[2].Filter(m_rawRotation.Z);<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<h6>Final transformations</h6>
<p>Also in the TrackedDevice class the transformation of the tracking values from the camera world space coordinate system to the actual in game virtual space coordinate system takes place:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>virtual</span> <span>void</span> TransformToVirtualSpace() <br>{<br>    Matrix bodyTransformMatrix =<br>    Matrix.CreateFromYawPitchRoll(m_rawRotation.Y, m_rawRotation.X, m_rawRotation.Z)<br>                                  * Matrix.CreateTranslation(m_rawTranslation);<br>    Matrix result = m_TrackerWorldTransform * m_DeviceWorldTransform;<br>    result = bodyTransformMatrix * result;<br>    result = m_DeviceLocalTransform * result;<br>    Vector3 scale;<br>    result.Decompose(<span>out</span> scale, <span>out</span> m_Rotation, <span>out</span> m_Translation);<br>}</pre>
<br>
</div>
<p>First a transformation matrix of the Euler angels and the translation vector is composed to the Body-Transform. From the tracking.xml configuration file we also have matrices for Tracker-World-Transform, Device-World-Transform and Device-Local-Transform.
</p>
<p>In addition to the Tracker-World-Transform translation from the tracker.xml I calculate the rotation angles of the Wiimotes using the acceleration sensors. By that it is possible to rotate the Wiimotes around the x and z axis to better focus the area you
 want to track and still get correct tracking results automatically.</p>
<p>Finally, to get the correct final transformation the matrices have to be multiplied in the correct order:</p>
<p>Device-Local-Transform * Body-Transform * Tracker-World-Transform * Device-World-Transform</p>
<p>Now the pose estimation transformation result is ready to be read by the TrackerManager.</p>
<h5>Conclusion and Limitation</h5>
<p>As I have shown it is possible to create a low-cost Desktop Virtual Reality Setup using two Wiimotes and anaglyph stereo glasses. But because of the low resolution of the Wiimote camera the quality is not comparable to professional monocular tracking systems.
 However, the quality of the presented system could still be improved by correctly measuring the intrinsic parameters of the Wiimote camera. There are various known algorithms how to measure these parameters by a set of sample data of an object with regular
 known geometry. For standard cameras usually a checkerboard pattern is used. An algorithm for that purpose is also integrated in OpenCV, so applying it to the Wiimote shouldn't be to hard.</p>
<p>Another issue with intrinsic parameters that I completely ignored so far is the lens distortion. All camera lenses do distort the image to a certain degree. By assuming a circular distortion the algorithms that measure the intrinsic parameters also calculate
 distortion parameters. If those parameters would be measured the Wiimote image points could be easily undistorted and the pose estimation results would be improved.</p>
<h5><a title="TOC-References" name="TOC-References"></a>References</h5>
<ul>
<li>D. DeMenthon and L.S. Davis, &quot;Model-Based Object Pose in 25 Lines of Code&quot;, International Journal of Computer Vision, 15, pp. 123-141, June 1995.
<br>
Paper about the used pose estimation algorithm by Daniel DeMenthon. You can find this brilliant paper on his
<a href="http://www.cfar.umd.edu/~daniel/Site_2/Welcome.html">homepage</a>. </li><li><a href="http://opencv.willowgarage.com/wiki/">OpenCV</a>: Open Source computer vision library. Includes implementation of the pose estimation algorithm and Kalman filter.
</li><li><a href="http://www.emgu.com/wiki/index.php/Main_Page">EmguCV</a>: C# wrapper for OpenCV
</li><li><a href="http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx">WiimoteLib</a>: Managed Library for Nintendo's Wiimote by
<a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a> </li><li><a href="http://www.codeplex.com/xnanimation">XNAnimation</a>: Very nice library for animations in XNA. I didn't use it for the actual Wiimote tracking, but used his animation demo application in the demonstration video.
</li><li><a href="http://creators.xna.com/">XNA</a>: Game development library in C# that I use as base for my applications.
</li><li><a href="http://www.cs.unc.edu/~welch/kalman/kalmanIntro.html">An Introduction to the Kalman Filter</a>. Greg Welch and Gary Bishop. Siggraph 2001 Course 8.
</li><li>Predictive Tracking for Augmented Reality. <a href="http://www.cs.unc.edu/~azuma/">
Ronald Tadao Azuma</a>. Dissertation. University of North Carolina. February 1995.
</li></ul>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:6c856e13538e409ebeb79e7600cd2db4">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Wiimote-Virtual-Reality-Desktop</comments>
      <itunes:summary>




In this article I want to introduce a Virtual Reality system that can be build with two Nintendo Wii Remotes (Wiimotes) and just a little extra hardware that costs less than $10 USD.



&amp;nbsp;
Timo Fleisch
&amp;nbsp;

Difficulty: Expert
Time Required: 3-4 hours
Cost: : $80 for two Wiimotes, ~$20 for IR-LEDs, stripboards, battery holder
Software: Visual C# Express Edition 2008,
XNA Games Studio 3.0, 
Managed Library for Nintendo&#39;s Wiimote, 
OpenCV Computer Vision Library and 
EmguCV C# Wrapper
Hardware: Two Nintendo Wii Remote (Wiimote), Anaglyph 3D Glasses (Red/Green Glasses) or Zalman 3D Monitor, compatible PC Bluetooth adapter and stack
Download Binary: Download
Download Source: Download




Introduction
The term Virtual Reality (VR) has been around many years by now but is still associated with very special and expensive hardware that is only available for research laboratories or big companies. Most people might think of a setup where the user wears a
 head-mounted-display and a data glove. Technically speaking Virtual Reality is defined by two things: 

Immersion and Interactivity 
By immersion is meant, that the user gets the impression of being inside a computer generated world. Usually VR systems use stereoscopic output devices to give the user a real 3D impression of the virtual world. But besides visual immersion, haptic and acoustic
 can also play an important role. 
3D images can for example be experienced in IMAX 3D cinemas – but this is still no Virtual Reality. What is missing is the interactivity. When the user is able to interact with the virtual world, by navigation and manipulation of the objects then the definition
 for VR is complete. 
In this article I want to introduce a Virtual Reality system that can be build with two Nintendo Wii Remotes (Wiimotes) and just a little extra hardware that costs less than 10 USD. By that VR should be affordable for everyone. The demo software and source
 can be downloaded from my website: 
http://www.vrhome.de</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Wiimote-Virtual-Reality-Desktop</link>
      <pubDate>Wed, 11 Feb 2009 18:15:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Wiimote-Virtual-Reality-Desktop</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9412433_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9412433_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Timo Fleisch</dc:creator>
      <itunes:author>Timo Fleisch</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Wiimote-Virtual-Reality-Desktop/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Controlling Your Festive Lights with the .NET Micro Framework</title>
      <description><![CDATA[
<table class="" cellspacing="0" cellpadding="2" width="470" border="0">
<tbody>
<tr>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Author:</strong></td>
<td class="" valign="top" width="363">Rob Miles: <a href="http://www.robmiles.com">
www.robmiles.com</a> </td>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Download:</strong></td>
<td class="" valign="top" width="363"><a title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/festivelights1.0.zip" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/festivelights1.0.zip">Download</a></td>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Software:</strong></td>
<td class="" valign="top" width="363">Visual Studio 2008 Express Edition or better,
<br>
<a href="http://www.microsoft.com/netmf/about/gettingstarted.mspx">.NET Micro Framework 3.0</a></td>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Hardware:</strong></td>
<td class="" valign="top" width="363"><a href="http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp">Digi Connect-ME</a>
<br>
<a href="http://www.ghielectronics.com/embeddedmaster.php">GHI Electronics Embedded Master</a>
<br>
<a href="http://devicesolutions.net/Products/Tahoe.aspx">Devices Solutions Tahoe II
</a></td>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Time Required:</strong></td>
<td class="" valign="top" width="363">3 hours</td>
</tr>
<tr>
<td class="" valign="top" width="105"><strong>Cost:</strong></td>
<td class="" valign="top" width="363">30 dollars for lights plus the .NET Micro Framework device</td>
</tr>
</tbody>
</table>
<p>The Micro Framework is one of the newest kids on the .NET block, but it does something really rather wonderful. It brings embedded development within the reach of any C# programmer. If you know C# and love Visual Studio, you can now get started building
 hardware and controlling it with your software. Moreover, it lets developers achieve one of their most cherished dreams, to control their festive lights using programs that they have written. This project shows you how to do just that and adds an extra magical
 feature, in that you can make all your festive lights flash red whenever I, Rob Miles, make a new post on that most famous of blogs,
<a href="http://www.robmiles.com">www.robmiles.com</a>. </p>
<p>Actually, you can modify the code so that you can make your lights do most anything in response to an event that happens on the web. You could signal home that you are running late, send the weather forecast to your Christmas tree or explore any number of
 communication options. You might decide that this is so useful that you leave your decorations up all year round.</p>
<p>If you just want to play with the .NET Micro Framework and get a feel for how easy it is to create software for tiny devices you don't actually need to use any extra hardware at all. The project comes with a complete emulation of the lights display so that
 you can run the whole thing on your computer and learn how hardware and software can be made to work together without burning your fingers with a soldering iron.</p>
<p>However building the hardware will give you an understanding of how some simple electronic components can be controlled from C# and even how serial and parallel data transfer works. It is also great fun.</p>
<p>To get started you will need some hardware and some software. Let's take each in turn.</p>
<h1>Hardware</h1>
<h2>Processor Hardware</h2>
<p>The .NET Micro Framework lets you run C# programs on tiny embedded devices. There are a number of these available today, and they are getting progressively cheaper. You can base this project on any.NET Micro Framework device that has a network port and three
 or more output ports. The ones I'd recommend are:</p>
<ul>
<li>Digi Connect-ME: <a href="http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp">
http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp</a> </li><li>GHI Electronics Embedded Master: <a href="http://www.ghielectronics.com/embeddedmaster.php">
http://www.ghielectronics.com/embeddedmaster.php</a> </li><li>Devices Solutions Tahoe II: <a href="http://devicesolutions.net/Products/Tahoe.aspx">
http://devicesolutions.net/Products/Tahoe.aspx</a> </li></ul>
<p>I built the project for Digi Connect board but the code can be customised for any of the above platforms. The beauty of the .NET Micro Framework is that you hardly need to change your program even if the underlying hardware is completely replaced. The only
 thing you will have to do is adjust the code to target different output pins. I'll flag this part of the program up when we get to it.</p>
<p>The project as supplied runs on a special emulator that runs on the PC and behaves like a .NET Micro Framework device with lights connected, so you can get started exploring the code right away.</p>
<h2>Lights</h2>
<p>I'm keeping things deliberately low voltage for this project. This means that kids of all ages can have a go at building the hardware without messing around with mains. The lights that I used were supplied as lines of twenty leds wired up as four strands
 of five leds each. All the leds in each strand were the same colour. The lights were fitted with a little battery box which held three AA batteries and a tiny controller. To get my display I simply removed the battery box and connected the strands to my hardware.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image.png"><img title="image" height="226" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb.png" width="324" border="0"></a>&nbsp;
<br>
<strong>Figure 1: My Battery Powered Lights</strong></p>
<p>You can do the same with any low power lighting kit that you wish to use. The drivers that I'm using can handle around 500 milliamps of continuous current and so you can connect a fair number of lights to each strand.
</p>
<h2>Buying the Lights</h2>
<p>The lights I used can be bought in the UK from Lights4Fun: www.lights4fun.co.uk and are called &quot;C-LED-4.5-M 20 Multi Coloured Battery Operated LED Fairy Lights&quot;. They are supplied with a battery box and controller that you can remove to connect to the Darlington
 drivers. I used an old 5 volt mobile phone charger to power the lights. If you search eBay for &quot;led christmas lights battery&quot; you should find plenty of suppliers.</p>
<h2>Driver Hardware</h2>
<p>We can't connect a .NET Micro Framework device directly to our lights. There are two reasons for this:</p>
<ol>
<li>The Micro Framework device will not be able to switch the amount of current that we need to drive the lights themselves.
</li><li>The Micro Framework device will not have enough outputs to control all the lights that we want to use.
</li></ol>
<p>This means that we need to make some hardware that goes between the processor and our lights. I actually don't see this as a problem. Making hardware is great fun, seeing something that you've built spring into life is very nice. The hardware we are going
 to use will provide a means by which we can control many hundreds of lights from a single Micro Framework board if we wish. It also has the ability to switch reasonable amounts of current, so you can use quite large numbers of lights if you wish. We are going
 to use two semiconductor components, a CD4094 Shift Register/Latch and a ULN2803 Octal Darlington Driver. A pair of these chips will allow us to control 8 outputs. If you want to control more outputs you simply get more chips and chain them together. For my
 version of the project I just used one of each chip, you can use as many as you like.The shift registers and Darlington amplifiers can be obtained in the UK from Maplin:
<a href="http://www.maplin.co.uk">www.maplin.co.uk</a>. The chip numbers and part numbers as are as follows: QW54J 4094 Shift Register, QY79L ULN2803A Darlington Driver. In the US you can obtain the components and breadboard from Digi-Key:
<a href="http://www.digikey.com">www.digikey.com</a>. </p>
<h2>Serial and Parallel Data</h2>
<p>You might be wondering how we can use just three output lines to control lots of lights. We are going to do this by using the three output lines to provide a
<i>serial</i> data stream which is converted by our hardware into <i>parallel</i> data that can be used to control our lights. This is a fundamental principle of digital electronics and is how, amongst many other things, computer networks transfer data.</p>
<p>We are going to use three signals which are called <b>clock</b>, <b>data</b> and
<b>latch</b>. Each of these can be set high (a voltage is present) or low (no voltage is present) by the .NET Micro Framework device under the control of our software. The signals are connected to the clock, data and latch inputs of our CD4094 shift register
 so that the program can talk to it.</p>
<p>The clock line triggers the shift register to do two things:</p>
<ol>
<li>Shift all the bits along to make room. </li><li>Sample the value of the data input and store this value in the space that was created.
</li></ol>
<p>To get a feel for how this works, take a look at Figure 2 below. It shows a shift register with a pattern of bits in it. The pattern is
<b>01100001</b>. Note that although this represents a number; it can also be regarded as a pattern of 0s and 1s in the shift register itself. The value 0 means 0 volts and the value 1 means some volts. These are the signals that will be used to control our
 lights. I'm going to call them 0 and 1 from now on. The Shift Register has Clock, Data and Latch signals connected and they are all set to 1. We can ignore the latch part of the chip for now.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_3.png"><img title="image" height="251" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_3.png" width="500" border="0"></a>
</p>
<p><strong>Figure 2: A shift register and latch with some data in it</strong></p>
<p>When the clock signal changes from 1 to 0 this causes the shift register to perform the two steps described above. First the data is shifted along to the right. Note that this means that there is an &quot;empty&quot; location at the start of the register, and that
 the right most bit in the register &quot;falls off&quot; the register and disappears. Figure 3 shows how this works.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_4.png"><img title="image" height="236" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_4.png" width="500" border="0"></a>
</p>
<p><strong>Figure 3: Shifting along the values in the shift register</strong></p>
<p>Once the shift has finished the shift register can copy the data signal into the empty bit at the left as shown in Figure 4 below.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_5.png"><img title="image" height="251" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_5.png" width="500" border="0"></a>
<strong><br>
Figure 4: Storing the new data bit</strong></p>
<p>By repeating this process 8 times a program can load a new pattern of 8 bits into the shift register. Then it is time to latch the new value to control the lights. This is the point at which the lights will appear to change. When the latch value is changed
 from 0 to 1 this causes the chip to copy the value in the Shift Register into the latch, as shown in Figure 5 below.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_6.png"><img title="image" height="251" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_6.png" width="500" border="0"></a>
</p>
<p><strong>Figure 5: Copying the shift register pattern into the latch.</strong></p>
<p>The latch is required so that the lights will not flicker as the new patterns are shifted into position. Each of the bits in the latch is connected to an output pin on the CD4094 which is used to switch a particular light colour on or off.</p>
<p>We need to create some C# that will provide the appropriate sequence of signals. It turns out that using the .NET Micro Framework to achieve this is actually very easy. The
<b>displayByte</b> method below sends an 8 bit value into a shift register and then latches it into the output. If you read through the code you can see how the clock, data and latch values are all set to true (high) or false (low) to first clock the data out
 and then trigger the latch to display the pattern on the lights. The input is an 8 bit byte value and the program uses a mask to pick out the value of each bit in turn and set the data output accordingly.</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> displayByte(<span class="kwrd">byte</span> <span class="kwrd">value</span>)
{
    latchPort.Write(<span class="kwrd">false</span>);
    clockPort.Write(<span class="kwrd">false</span>);

    <span class="kwrd">byte</span> mask = 1;

    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; 8; i&#43;&#43;)
    {
        <span class="kwrd">if</span> ((<span class="kwrd">value</span> &amp; mask) &gt; 0)
        {
            dataPort.Write(<span class="kwrd">true</span>);
        }
        <span class="kwrd">else</span>
        {
            dataPort.Write(<span class="kwrd">false</span>);
        }
        clockPort.Write(<span class="kwrd">true</span>);
        clockPort.Write(<span class="kwrd">false</span>);
        mask &lt;&lt;= 1;
    }
    latchPort.Write(<span class="kwrd">true</span>);
    latchPort.Write(<span class="kwrd">false</span>);
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>dataPort</b>, <b>clockPort</b> and <b>latchPort</b> variables are instances of the .NET Micro Framework class
<b>OutputPort</b>, which provides a method called <b>Write</b> which can be used to control the state of the output signal. We will consider how these are created a little later in the article.</p>
<p>The sample code for this project comes with a software emulator of the CD4094 which shows how it works. Figure 6 below shows that a new pattern is in the process of being shifted into the shift register, while the lights retain the previous one in the latch.
 The Clock and Data signals are high and the next statement will drop the Clock signal to add the next bit into the new pattern.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_7.png"><img title="image" height="303" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_7.png" width="264" border="0"></a>
</p>
<p><strong>Figure 6: The light emulator</strong></p>
<p>This figure also shows that I have two bits in the pattern controlling a strand of each colour. You can single step through the displayByte method above and watch it perform this output.</p>
<p>You can use this technique every time you want to control a large number of outputs using a small number of output pins. The CD4094 has &quot;daisy chain&quot; inputs and outputs so that the devices can be connected in sequence. If I used two devices I could control
 16 bits, with three I could control 24 and so on. This would require only minimal changes to the software.</p>
<h2>Output Driver</h2>
<p>The CD4094 device will produce a signal output, but it is not really powerful enough to drive things like lights. To do this we need an amplifier and the ULN2803 Octal Darlington Driver is perfect for this. It is packaged as a single chip which contains
 8 pairs of transistors. Each transistor pair is wired in a &quot;Darlington&quot; configuration and can be used as a switch which is controlled by on output from the CD4094. When the transistors are turned on they allow current to pass through them and this will cause
 the lamps to light. The lights that I bought used a &quot;pull down&quot; arrangement to make them light up. All of the light emitting diode (LED) lamps had one end wired to a common line that was connected to the positive supply. To make the a chain of LEDs light the
 other end that controls that chain needed to be pulled down to the ground level. This is a common arrangement with lights like these. The ULN2803 driver has the transistors wired in an arrangement that allows it to pull signals low in this way. Figure 7 shows
 how this arrangement works. The resistor shown is actually wired into each LED in the set of lights that I used.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_8.png"><img title="image" height="201" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_8.png" width="226" border="0"></a>
<br>
<strong>Figure 7: Lighting the LEDs</strong></p>
<h5>Complete Circuit</h5>
<p>The complete circuit shown in Figure 8 simply links each output of the CD4094 shift register to an input on the ULN2803 Darlington Driver. Note that there is no reason to link any particular bit with any other, the diagram shown is one which will translate
 most easily to a prototype &quot;breadboard&quot;.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_9.png"><img title="image" height="260" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_9.png" width="500" border="0"></a>
<br>
<strong>Figure 8: The Complete Circuit</strong></p>
<p>The diagram just shows four lights connected to OUT1 from pin 18 of the ULN2803, the other 7 channels are connected in exactly the same way. Some of the pins can be left unconnected. Pins 9 and 10 of the CD4094 are only required if you are connecting multiple
 shift registers together and the common connection on pin 10 of the ULN2803 is not required. The Latch, Data and Clock signals on the CD4094 are connected to the output signals from the Micro Framework device.
</p>
<p>Figure 9 shows the completed circuit built up on a prototype breadboard. The chip on the left is the CD4094 and the one on the right is the ULN2803.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_10.png"><img title="image" height="331" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9149635/image_thumb_10.png" width="484" border="0"></a>
<strong><br>
Figure 9: The Completed Circuit</strong></p>
<p>The red wires carry the positive voltage from the power supply, which is connected to the top left of the circuit. The green wires are ground. Other coloured wires are used for signals. The Clock, Latch and Data signals are brought out to a connector which
 will fit a Digi-ME prototyping board.</p>
<h2>Selecting Lights</h2>
<p>Each bit in the value sent to the <b>displayByte</b> method and then into the shift register will be mapped to a particular chain of lights. The mapping of these is not particularly important, since you can use program constants to represent particular values.
 I wired the red signals to output pins 4 and 8. To light up just the red lights I used the value 0x88 which is the appropriate bit pattern. I then set up constants for all the other colors:</p>
<pre class="csharpcode"><span class="kwrd">const</span> <span class="kwrd">byte</span> GREEN = 0x11;
<span class="kwrd">const</span> <span class="kwrd">byte</span> BLUE = 0x22;
<span class="kwrd">const</span> <span class="kwrd">byte</span> YELLOW = 0x44;
<span class="kwrd">const</span> <span class="kwrd">byte</span> RED = 0x88;</pre>
<h2>Setting Up the Hardware</h2>
<p>The .NET Micro Framework provides a set of classes that can be used to represent the hardware in a system. The program uses instances of the
<b>OutputPort</b> class to represent the output pins. These are created in the method that sets up the hardware:</p>
<pre class="csharpcode"><span class="kwrd">const</span> Cpu.Pin clockPin = Cpu.Pin.GPIO_Pin0;
<span class="kwrd">const</span> Cpu.Pin dataPin = Cpu.Pin.GPIO_Pin1;
<span class="kwrd">const</span> Cpu.Pin latchPin = Cpu.Pin.GPIO_Pin2;

<span class="kwrd">static</span> OutputPort clockPort;
<span class="kwrd">static</span> OutputPort dataPort;
<span class="kwrd">static</span> OutputPort latchPort;

<span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> setupOutputs()
{
    clockPort = <span class="kwrd">new</span> OutputPort(clockPin, <span class="kwrd">false</span>);
    dataPort = <span class="kwrd">new</span> OutputPort(dataPin, <span class="kwrd">false</span>);
    latchPort = <span class="kwrd">new</span> OutputPort(latchPin, <span class="kwrd">false</span>);
}</pre>
<p>In this version of the hardware I have connected pin 0 of the processor to the clock, pin 1 to the data and pin 2 to the latch. If you use different pins you can change the settings above.</p>
<h1>Software</h1>
<p>Now that we have working hardware we can consider how the software is to work. Note that this version of the program works correctly but lacks exception handlers that would make it truly robust. I've left these out to simplify the explanation. To make sense
 of this description you will need to have a copy of the program itself available for reference.</p>
<p>You can develop the code using Visual Studio 2008 Express edition, which you can download from
<a href="http://www.microsoft.com/express/">http://www.microsoft.com/express/</a>
</p>
<p>The software is written for the .NET Micro Framework 3.0 which you can download from
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9356ed6f-f1f0-43ef-b21a-4644dd089b4a&amp;displaylang=en">
http://www.microsoft.com/downloads/details.aspx?FamilyID=9356ed6f-f1f0-43ef-b21a-4644dd089b4a&amp;displaylang=en</a>
</p>
<h2>Reading the Blog</h2>
<p>The program reads the RSS feed from a blog and looks for the <b>&lt;pubDate&gt;</b> value. This contains the date when the feed was last updated. Whenever this date changes the lights must flash red for a few seconds before resuming a random display. Users of
 the full .NET Framework can use the <b>HTTPRequest</b> class to build a <b>GET</b> command to be sent to a server. Unfortunately the .NET Micro Framework does not support this, so we have to access the web feed using socket based communication. This part of
 the program is heavily based on the <b>SocketClient</b> example supplied with the .NET Micro Framework.</p>
<pre class="csharpcode"><span class="rem">// This method requests a page from the specified server.</span>
<span class="kwrd">private</span> <span class="kwrd">static</span> String GetWebPage(String server, <span class="kwrd">string</span> webPage)
{
    <span class="kwrd">const</span> Int32 c_httpPort = 80;
    <span class="kwrd">const</span> Int32 c_microsecondsPerSecond = 1000000;

    <span class="rem">// Create a socket connection to the specified server and port.</span>
    <span class="kwrd">using</span> (Socket serverSocket = ConnectSocket(server, c_httpPort))
    {
        <span class="rem">// Send request to the server.</span>
        String request = <span class="str">&quot;GET &quot;</span>&#43; webPage &#43; 
             <span class="str">&quot; HTTP/1.1\r\nHost: &quot;</span> &#43; server &#43; 
             <span class="str">&quot;\r\nConnection: Close\r\n\r\n&quot;</span>;
        Byte[] bytesToSend = Encoding.UTF8.GetBytes(request);
        serverSocket.Send(bytesToSend, bytesToSend.Length, 0);

        <span class="rem">// Allocate a buffer to receive HTML chunks</span>
        Byte[] buffer = <span class="kwrd">new</span> Byte[1024];

        <span class="rem">// 'page' refers to the HTML data as it is built up.</span>
        String page = String.Empty; 

        <span class="rem">// Wait up to 30 seconds for initial data </span>
        <span class="rem">// Will throw exception if connection closed</span>
        DateTime timeoutAt = DateTime.Now.AddSeconds(30);
        <span class="kwrd">while</span> (serverSocket.Available == 0 &amp;&amp; 
               DateTime.Now &lt; timeoutAt)
        {
            System.Threading.Thread.Sleep(100);
        }

        <span class="rem">// Poll for data until 30 second time out</span>
        <span class="rem">// Returns true for data and connection closed</span>
        <span class="kwrd">while</span> (serverSocket.Poll(30 * c_microsecondsPerSecond,
                                 SelectMode.SelectRead))
        {
            <span class="rem">// Zero all bytes in the re-usable buffer</span>
            Array.Clear(buffer, 0, buffer.Length);

            <span class="rem">// Read a buffer-sized HTML chunk</span>
            Int32 bytesRead = serverSocket.Receive(buffer);

            <span class="rem">// If 0 bytes in buffer, then connection is closed, </span>
            <span class="rem">// or we have timed out</span>
            <span class="kwrd">if</span> (bytesRead == 0)
                <span class="kwrd">break</span>;

            <span class="rem">// Append the chunk to the string</span>
            page &#43;= <span class="kwrd">new</span> String(Encoding.UTF8.GetChars(buffer));
        }

        <span class="kwrd">return</span> page;   <span class="rem">// Return the complete string</span>
    }
}</pre>
<p>This method is called to fetch the journal RSS feed from my blog:</p>
<pre class="csharpcode"><span class="kwrd">string</span> address = <span class="str">&quot;www.robmiles.com&quot;</span>;
<span class="kwrd">string</span> name = <span class="str">&quot;/journal/rss.xml&quot;</span>;

<span class="kwrd">string</span> html = GetWebPage(address, name);</pre>
<p>You can use it to download from any RSS feed or page on the web. It will throw an exception if the page cannot be read. This version of my program does not perform exception handling however.</p>
<h2>Getting the Published Date</h2>
<p>The date is held in the form:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">pubDate</span><span class="kwrd">&gt;</span>Wed, 05 Nov 2008 22:38:52 &#43;0000<span class="kwrd">&lt;/</span><span class="html">pubDate</span><span class="kwrd">&gt;</span></pre>
<p>It would be enough just to record this content and check for changes in the text, but I decided that I might want to use the date information in a later version of the program and so I created some small helper methods to read numbers from the input string
 and a larger method to read the publish date itself:</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> DateTime getRecentPubDate(<span class="kwrd">string</span> html, <span class="kwrd">string</span> startTag)
{
    <span class="kwrd">int</span> index = html.IndexOf(startTag) ;

    <span class="kwrd">if</span> (index &lt; 0) 
        <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="str">&quot;Missing tag &quot;</span> &#43; startTag);

    index &#43;= startTag.Length;

    <span class="rem">// spin past the name of the day</span>
    <span class="kwrd">while</span> (index &lt; html.Length &amp;&amp; html[index] != <span class="str">','</span>) index&#43;&#43;;
    <span class="kwrd">if</span> (index == html.Length) 
        <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="str">&quot;Short publish date&quot;</span>);

    <span class="kwrd">int</span> dayValue = getInt(html, <span class="kwrd">ref</span> index, <span class="str">' '</span>);

    <span class="kwrd">string</span> monthName = getString(html, <span class="kwrd">ref</span> index, <span class="str">' '</span>);
    <span class="kwrd">int</span> monthValue = getMonth(monthName);

    <span class="kwrd">int</span> yearValue = getInt(html, <span class="kwrd">ref</span> index, <span class="str">' '</span>);
    <span class="kwrd">int</span> hourValue = getInt(html, <span class="kwrd">ref</span> index, <span class="str">':'</span>);
    <span class="kwrd">int</span> minuteValue = getInt(html, <span class="kwrd">ref</span> index, <span class="str">':'</span>);
    <span class="kwrd">int</span> secondValue = getInt(html, <span class="kwrd">ref</span> index, <span class="str">' '</span>);

    <span class="kwrd">return</span> <span class="kwrd">new</span> DateTime(yearValue, monthValue, dayValue, 
                        hourValue, minuteValue, secondValue);
}</pre>
<p>The main body of the program uses this method to extract the date out of the RSS feed. When a new date is found it is time to update the lights.</p>
<h2>Lights and Threads</h2>
<p>My first version of the program flashed the lights for a while and then checked to see if a new blog post had been made. This worked OK, but the process of loading the RSS feed from the server and checking the dates can take a few seconds, which meant that
 the flashing lights would freeze every now and then. This did not look very good, and so I decided to use two threads instead. One is in charge of flashing the lights in a random pattern and the other loads the RSS feed from my blog and checks the date of
 the most recent publication. </p>
<p>Note that the threading I am using is exactly the same as threading in the full .NET Framework.
</p>
<h2>Thread Communication</h2>
<p>The two threads communicate by means of a single boolean variable which is set to true when the blog alert is to take place. The display thread reads this flag and flashes the lights red if it is time to alert.
</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> alert = <span class="kwrd">false</span>;

<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> flasher()
{
    setupOutputs();

    <span class="kwrd">while</span> (<span class="kwrd">true</span>)
    {
        randomDisplay(400, 10);
        <span class="kwrd">if</span> (alert)
        {
            alert = <span class="kwrd">false</span>;
            flashRed(600, 20);
        }
    }
}</pre>
<p>The methods <b>randomDisplay</b> and <b>flashRed</b> do exactly what you would expect. Each of them gets two numbers to control the lights. The first number gives the delay in milliseconds between flashes (a few hundred milliseconds giving best results).
 The second gives the number of times that the lights should be flashed before the method finishes.
<b>RandomDisplay</b> displays random colors, whereas <b>flashRed</b> is simply flashes the red lights. The
<b>alert</b> flag is cleared before the red lights are flashed so that the system will resume normal display after the alert.</p>
<p>The second thread in the system performs the blog download and date test behaviour. This all happens inside the
<b>Main</b> method:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Main()
{
    flashThread = <span class="kwrd">new</span> System.Threading.Thread(flasher);

    flashThread.Start();

    <span class="kwrd">string</span> address = <span class="str">&quot;www.robmiles.com&quot;</span>;
    <span class="kwrd">string</span> name = <span class="str">&quot;/journal/rss.xml&quot;</span>;

    String html = GetWebPage(address, name);

    DateTime lastUpdate = getRecentPubDate(html, <span class="str">&quot;&lt;pubDate&gt;&quot;</span>);

    Debug.Print(<span class="str">&quot;Initial Update Value : &quot;</span> &#43; lastUpdate.ToString());

    <span class="kwrd">while</span> (<span class="kwrd">true</span>)
    {
        System.Threading.Thread.Sleep(10000);

        html = GetWebPage(address, name);

        DateTime blogUpdate = getRecentPubDate(html, <span class="str">&quot;&lt;pubDate&gt;&quot;</span>);

        <span class="kwrd">if</span> (!blogUpdate.Equals(lastUpdate))
        {
            Debug.Print(<span class="str">&quot;Updated at : &quot;</span> &#43; blogUpdate.ToString());
            lastUpdate = blogUpdate;
            alert = <span class="kwrd">true</span>;
        }
    }
}</pre>
<p>To reduce the load on the network the system only checks the blog feed every 10 seconds.</p>
<h1>Future Work</h1>
<p>The program itself works fine, but the error handling is not wonderful. Although some of the methods used throw exceptions these are not caught anywhere, causing the blog reading thread to terminate. This does not stop the lights flashing, but it does mean
 that there will be no more alerts. However, it is not too hard to create a version which contains proper error handling and even flashes the lights different colors to indicate the alarm conditions. I have created a version that flashes the lights yellow every
 now and then if the network connection fails. There is also considerable scope for reading other web based sources and changing the output accordingly. Feel free to do all these things and make sure that you have fun.</p>
<h2>Thanks</h2>
<p>Thanks go to Ian Mitchell of Ormston Technology (<a href="http://www.ormtec.co.uk/">http://www.ormtec.co.uk/</a>) for doing such a great job of hardware design and build.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:90ff2e0eefa3449089ad9e7600cda780">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Controlling-Your-Festive-Lights-with-the-NET-Micro-Framework</comments>
      <itunes:summary>





Author:
Rob Miles: 
www.robmiles.com 


Download:
Download


Software:
Visual Studio 2008 Express Edition or better,

.NET Micro Framework 3.0


Hardware:
Digi Connect-ME

GHI Electronics Embedded Master

Devices Solutions Tahoe II



Time Required:
3 hours


Cost:
30 dollars for lights plus the .NET Micro Framework device



The Micro Framework is one of the newest kids on the .NET block, but it does something really rather wonderful. It brings embedded development within the reach of any C# programmer. If you know C# and love Visual Studio, you can now get started building
 hardware and controlling it with your software. Moreover, it lets developers achieve one of their most cherished dreams, to control their festive lights using programs that they have written. This project shows you how to do just that and adds an extra magical
 feature, in that you can make all your festive lights flash red whenever I, Rob Miles, make a new post on that most famous of blogs,
www.robmiles.com.  
Actually, you can modify the code so that you can make your lights do most anything in response to an event that happens on the web. You could signal home that you are running late, send the weather forecast to your Christmas tree or explore any number of
 communication options. You might decide that this is so useful that you leave your decorations up all year round. 
If you just want to play with the .NET Micro Framework and get a feel for how easy it is to create software for tiny devices you don&#39;t actually need to use any extra hardware at all. The project comes with a complete emulation of the lights display so that
 you can run the whole thing on your computer and learn how hardware and software can be made to work together without burning your fingers with a soldering iron. 
However building the hardware will give you an understanding of how some simple electronic components can be controlled from C# and even how serial and parallel data transfer works. It is also great fun.</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Controlling-Your-Festive-Lights-with-the-NET-Micro-Framework</link>
      <pubDate>Fri, 28 Nov 2008 01:58:46 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Controlling-Your-Festive-Lights-with-the-NET-Micro-Framework</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9149635_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9149635_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Rob Miles</dc:creator>
      <itunes:author>Rob Miles</itunes:author>
      <slash:comments>6</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Controlling-Your-Festive-Lights-with-the-NET-Micro-Framework/RSS</wfw:commentRss>
      <category>.NET Micro Framework</category>
      <category>Hardware</category>
      <category>Robotics</category>
      <category>Home Automation</category>
      <category>Holiday</category>
      <category>.NET Microframework</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>WiiEarthVR – A Fully Immersive 3D Experience with Virtual Earth 3D</title>
      <description><![CDATA[
<table border="0" cellspacing="0" cellpadding="1" width="100%">
<tbody>
<tr class="entry_overview">
<td width="50"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/globe4.png"><img title="globe4" border="0" alt="globe4" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/globe4_thumb.png" width="54" height="53"></a>
</td>
<td><span class="entry_description">In this article, Brian Peek will demonstrate how to use a Nintendo Wii Remote (Wiimote), a Wii Fit Balance Board, and Vuzix VR920 glasses as input devices for Microsoft Virtual Earth 3D, providing a fully immersive, 3D experience.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author"><a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a></div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> 2<span class="entry_details_input">-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">$60 for Wiimote and Nunchuk, $90 for Wii Fit (which includes Balance Board), $400 for
<a href="http://www.vr920.com/" target="_blank">Vuzix VR920 glasses</a></span></div>
<div class="entry_details"><b>Software: </b><a href="http://www.codeplex.com/WiimoteLib" target="_blank">Managed Library for Nintendo's Wiimote</a>,
<span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><a href="http://www.nintendo.com/wii/what/accessories">Nintendo Wii Remote (Wiimote) with Nunchuk</a>,
<a href="http://www.nintendo.com/games/detail/hoiNtus4JvIcPtP8LQPyud4Kyy393oep" target="_blank">
Wii Fit Balance Board</a>, <a href="http://www.vr920.com/iwear/products_vr920.html" target="_blank">
Vuzix VR920 glasses</a>, a compatible PC Bluetooth adapter and stack</div>
<div class="entry_details"><b>Download: </b><a href="http://www.brianpeek.com/files/folders/source_code/entry3066.aspx" target="_blank">Download</a></div>
<div class="entry_details"><strong>Discussion Forum: </strong><a href="http://www.brianpeek.com/forums/43.aspx" target="_blank">Forum</a></div>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h3>Introduction</h3>
<p>Virtual Earth is the 3D interface to <a href="http://maps.live.com" target="_blank">
Microsoft's Live Maps</a> service.&nbsp; Normally this control is loaded via the web browser and allows interaction with a keyboard, mouse, and Xbox 360 controller.&nbsp; In this article, we will take the Virtual Earth 3D control out of the web browser, use it in a WinForms
 application, and control it with a Nintendo Wii Remote (Wiimote) and a pair of Vuzix VR920 glasses, while also providing a stereoscopic 3D image to the glasses, creating the illusion of a fully three dimensional environment.&nbsp; Note that use of the Virtual Earth
 3D control in this way is undocumented and unsupported at the moment.&nbsp; Because of this, some of the descriptions in this article are educated guesses and may not be 100% accurate…</p>
<p>Originally, this project started as a simple Wiimote interface to Virtual Earth 3D as shown in the video below.&nbsp; Since I wrote that application, I learned of the VR920 glasses and the Wii Fit Balance Board was released, so I've decided to create a more immersive
 experience using all of these controls which was demonstrated at <a href="http://www.microsoftpdc.com/" target="_blank">
PDC2008</a>, shown here:</p>
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="320" height="240"> <param name="source" value="http://channel9.msdn.com/App_Themes/default/VideoPlayer.xap" /> <param name="initParams" value="m=mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/3/1/2/1/4/4/WiiEarthVR_s_ch9.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http://mschnlnine.vo.llnwd.net/d1/ch9/3/1/2/1/4/4/WiiEarthVR_large_ch9.jpg" /> <param name="background" value="#00FFFFFF" /> <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </object><h3>Setup</h3>
<p>Before we get started, you will need to install the Virtual Earth 3D control.&nbsp; If you haven't done this already, browse to
<a href="http://maps.live.com/">http://maps.live.com/</a> and click on the <b>3D</b> link to install the control and supporting software.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/captured_Image.png.png"><img title="captured_Image.png" border="0" alt="captured_Image.png" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/captured_Image.png_thumb.png" width="459" height="107"></a>
</p>
<p>Additionally, if you haven't already, please review my <a href="http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx" target="_blank">
Managed Library for Nintendo's Wiimote</a> article on this site.&nbsp; We will be using the library in this article, but I will not repeat the basic information that is located in the original article.&nbsp; You will also need to have the
<a href="http://www.vr920.com/" target="_blank">Vuzix VR920</a> glasses installed and setup according to its own user manual.&nbsp; That will also not be covered here.</p>
<h3>Implementation</h3>
<h4>The Virtual Earth 3D Control</h4>
<p>The Virtual Earth 3D (VE3D) control is intended to be used through a well documented JavaScript interface from a web page, however we would not be able to access the Wiimote or VR920 glasses from JavaScript.&nbsp; Therefore, we will be using the VE3D control
 through its native, but wholly undocumented interface.</p>
<p>Start by creating a new Windows Forms application named <strong>WiiEarthVR</strong> in C# or VB.&nbsp; As with all controls and 3rd party libraries, a reference needs to be set to the Virtual Earth 3D libraries.&nbsp; Add references to the following items:&nbsp;
</p>
<ul>
<li>Microsoft.MapPoint.Data </li><li>Microsoft.MapPoint.Data.VirtualEarthTileDataSource </li><li>Microsoft.MapPoint.Geometry </li><li>Microsoft.MapPoint.Rendering3D </li><li>Microsoft.MapPoint.Rendering3D.Utility </li></ul>
<p>If they do not show up in the .NET references, they can be found by selecting the Browse tab and navigating to C:\Program Files\Virtual Earth 3D\ or C:\Program Files (x86)\Virtual Earth 3D\ .&nbsp; With the references in place, the project file can now be opened
 and the references will be seen in the References folder in the Solution Explorer as usual.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/captured_Image.png11.png"><img title="captured_Image.png[11]" border="0" alt="captured_Image.png[11]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9068804/captured_Image.png11_thumb.png" width="376" height="229"></a>
</p>
<p>Creating an instance of the control can be done in code just like any other control.&nbsp; Used in the constructor or load event of the form, the following code will create a VE3D control and add it to the form as fully docked:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> GlobeControl _globeControl;</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> MainForm()</pre>
<pre>{</pre>
<pre>    InitializeComponent();</pre>
<pre>&nbsp;</pre>
<pre>    _globeControl = <span>new</span> GlobeControl();</pre>
<pre>    SuspendLayout();</pre>
<pre>    _globeControl.Location = <span>new</span> System.Drawing.Point(0, 0);</pre>
<pre>    _globeControl.Name = <span>&quot;_globeControl&quot;</span>;</pre>
<pre>    _globeControl.Size = ClientSize;</pre>
<pre>    _globeControl.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;</pre>
<pre>    _globeControl.TabIndex = 0;</pre>
<pre>    _globeControl.SendToBack(); <span>// we want the button to be on top</span></pre>
<pre>&nbsp;</pre>
<pre>    pnlGlobe.Controls.Add(_globeControl);</pre>
<pre>    ResumeLayout(<span>false</span>);</pre>
<pre>}</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> _globeControl <span>As</span> GlobeControl</pre>
<pre>&nbsp;</pre>
<pre><span>Public</span> <span>Sub</span> <span>New</span>()</pre>
<pre>    InitializeComponent()</pre>
<pre>&nbsp;</pre>
<pre>    _globeControl = <span>New</span> GlobeControl()</pre>
<pre>    SuspendLayout()</pre>
<pre>    _globeControl.Location = <span>New</span> System.Drawing.Point(0, 0)</pre>
<pre>    _globeControl.Name = <span>&quot;_globeControl&quot;</span></pre>
<pre>    _globeControl.Size = ClientSize</pre>
<pre>    _globeControl.Anchor = AnchorStyles.Left <span>Or</span> AnchorStyles.Right <span>Or</span> AnchorStyles.Top <span>Or</span> AnchorStyles.Bottom</pre>
<pre>    _globeControl.TabIndex = 0</pre>
<pre>    _globeControl.SendToBack() <span>' we want the button to be on top</span></pre>
<pre>&nbsp;</pre>
<pre>    pnlGlobe.Controls.Add(_globeControl)</pre>
<pre>    ResumeLayout(<span>False</span>)</pre>
<pre><span>End</span> Sub</pre>
</div>
</div>
<p>This sets up the VE3D control in its default state.&nbsp; If you were to run an application with only this code, you would see nothing but the earth.&nbsp; The navigation controls and other extras would be missing.</p>
<p>We can start adding items to the VE3D control by listening for the <strong>FirstFrameRendered</strong> event of the
<strong>GlobeControl</strong> and then setting the appropriate properties.&nbsp; Setting these properties prior to this point can lead to some unexpected results.</p>
<p>In the <strong>FirstFrameRendered</strong> event handler, if you wish to add the default navigation controls to the screen, the
<b>PlugInLoader</b> object is used.&nbsp; The <b>PlugInLoader</b> is created by using the
<b>CreateLoader</b> static method, passing in an instance of the <b>GlobeControl</b>'s
<b>Host</b> object.&nbsp; Then, the <b>NavigationPlugIn</b> can be loaded and activated as shown:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// load all the spiffy UI navigation goodies</span></pre>
<pre>PlugInLoader loader = PlugInLoader.CreateLoader(<span>this</span>.globeControl.Host);</pre>
<pre>loader.LoadPlugIn(<span>typeof</span>(NavigationPlugIn));</pre>
<pre>loader.ActivatePlugIn(<span>typeof</span>(NavigationPlugIn).GUID, <span>null</span>);</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' load all the spiffy UI navigation goodies</span></pre>
<pre><span>Dim</span> loader <span>As</span> PlugInLoader = PlugInLoader.CreateLoader(<span>Me</span>.globeControl.Host)</pre>
<pre>loader.LoadPlugIn(<span>GetType</span>(NavigationPlugIn))</pre>
<pre>loader.ActivatePlugIn(<span>GetType</span>(NavigationPlugIn).GUID, <span>Nothing</span>)</pre>
</div>
</div>
<p>The last thing to be added for basic functionality is the data.&nbsp; As it stands, the only data that will appear on the globe is the image of the continents.&nbsp; Zooming in only produces a blurry representation of that base image.</p>
<p>Data layers are created from specially formatted data sources provided by maps.live.com known as content manifests.&nbsp; These are XML files which tell the VE3D control how to load the data required for any view.&nbsp; Content layers can be added by adding them to
 the <strong>DataSources</strong> object of the <strong>GlobeControl</strong>.&nbsp; We can add any of the following layers (note that there may be other content manifests provided by maps.live.com, but these are the only 5 that I am aware of):</p>
<table border="1" cellspacing="0" cellpadding="2" width="516">
<tbody>
<tr>
<td valign="top" width="244">
<p align="center"><b>URL</b></p>
</td>
<td valign="top" width="163">
<p align="center"><b>DataSourceUsage Type</b></p>
</td>
<td valign="top" width="107">
<p align="center"><b>Description</b></p>
</td>
</tr>
<tr>
<td valign="top" width="244"><a title="http://local.live.com/Manifests/HighDemContentManifest.xml" href="http://local.live.com/Manifests/HD.xml">http://local.live.com/Manifests/HD.xml</a></td>
<td valign="top" width="163">ElevationMap</td>
<td valign="top" width="107">Terrain data</td>
</tr>
<tr>
<td valign="top" width="244"><a title="http://local.live.com/Manifests/ModelContentManifest.xml" href="http://local.live.com/Manifests/MO.xml">http://local.live.com/Manifests/MO.xml</a></td>
<td valign="top" width="163">Model</td>
<td valign="top" width="107">3D buildings</td>
</tr>
<tr>
<td valign="top" width="244"><a title="http://local.live.com/Manifests/AerialContentManifest.xml" href="http://local.live.com/Manifests/AT.xml">http://local.live.com/Manifests/AT.xml</a></td>
<td valign="top" width="163">TextureMap</td>
<td valign="top" width="107">Unlabeled aerial</td>
</tr>
<tr>
<td valign="top" width="244"><a title="http://local.live.com/Manifests/HybridContentManifest.xml" href="http://local.live.com/Manifests/HT.xml">http://local.live.com/Manifests/HT.xml</a></td>
<td valign="top" width="163">TextureMap</td>
<td valign="top" width="107">Labeled aerial</td>
</tr>
<tr>
<td valign="top" width="244"><a title="http://local.live.com/Manifests/RoadContentManifest.xml" href="http://local.live.com/Manifests/RT.xml">http://local.live.com/Manifests/RT.xml</a></td>
<td valign="top" width="163">TextureMap</td>
<td valign="top" width="107">Roads only</td>
</tr>
</tbody>
</table>
<p>For the best display, add the <b>ElevationMap</b>, <b>Model</b> and <b>Aerial</b>
<b>TextureMap</b> layers as shown:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// set various data sources, here for elevation data, terrain data, and model data.</span></pre>
<pre>_globeControl.Host.DataSources.Add(<span>new</span> DataSourceLayerData(<span>&quot;Elevation&quot;</span>, <span>&quot;Elevation&quot;</span>, <span>@&quot;http://maps.live.com//Manifests/HD.xml&quot;</span>, DataSourceUsage.ElevationMap));</pre>
<pre>_globeControl.Host.DataSources.Add(<span>new</span> DataSourceLayerData(<span>&quot;Texture&quot;</span>, <span>&quot;Texture&quot;</span>, <span>@&quot;http://maps.live.com//Manifests/AT.xml&quot;</span>, DataSourceUsage.TextureMap));</pre>
<pre>_globeControl.Host.DataSources.Add(<span>new</span> DataSourceLayerData(<span>&quot;Models&quot;</span>, <span>&quot;Models&quot;</span>, <span>@&quot;http://maps.live.com//Manifests/MO.xml&quot;</span>, DataSourceUsage.Model));</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' set various data sources, here for elevation data, terrain data, and model data.</span></pre>
<pre>_globeControl.Host.DataSources.Add(<span>New</span> DataSourceLayerData(<span>&quot;Elevation&quot;</span>, <span>&quot;Elevation&quot;</span>, <span>&quot;http://maps.live.com//Manifests/HD.xml&quot;</span>, DataSourceUsage.ElevationMap))</pre>
<pre>_globeControl.Host.DataSources.Add(<span>New</span> DataSourceLayerData(<span>&quot;Texture&quot;</span>, <span>&quot;Texture&quot;</span>, <span>&quot;http://maps.live.com//Manifests/AT.xml&quot;</span>, DataSourceUsage.TextureMap))</pre>
<pre>_globeControl.Host.DataSources.Add(<span>New</span> DataSourceLayerData(<span>&quot;Models&quot;</span>, <span>&quot;Models&quot;</span>, <span>&quot;http://maps.live.com//Manifests/MO.xml&quot;</span>, DataSourceUsage.Model))</pre>
</div>
</div>
<p>By passing the URL of the content manifest, a name for the layer, and what the manifest represents, a new
<b>DataSource</b> is created, which is in turn used to create a <b>DataSourceLayerData</b> object which is then given to the VE3D control to consume.&nbsp; This should be done in the
<strong>FirstFrameRendered</strong> event handler as well.</p>
<p>We also need to setup VE3D to turn off any UI elements, turn on the atmosphere effects, and ensure we have a full unobstructed view. Again, in the
<strong>FirstFrameRendered</strong> event handler, we can use the following code to achieve this:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// turn on the nice atmosphere</span></pre>
<pre>_globeControl.Host.WorldEngine.Environment.AtmosphereDisplay = Microsoft.MapPoint.Rendering3D.Atmospherics.EnvironmentManager.AtmosphereStyle.Scattering;</pre>
<pre>&nbsp;</pre>
<pre><span>// default to all off</span></pre>
<pre>_globeControl.Host.WorldEngine.Display3DCursor = <span>false</span>;</pre>
<pre>_globeControl.Host.WorldEngine.SetWindowsCursor(<span>null</span>);</pre>
<pre>_globeControl.Host.WorldEngine.ShowNavigationControl = <span>false</span>;</pre>
<pre>_globeControl.Host.WorldEngine.ShowCursorLocationInformation = <span>false</span>;</pre>
<pre>_globeControl.Host.WorldEngine.ShowScale = <span>false</span>;</pre>
<pre>_globeControl.Host.WorldEngine.ShowUI = <span>false</span>;</pre>
<pre>_globeControl.Host.WorldEngine.Environment.SunPosition = <span>null</span>;</pre>
<pre>_globeControl.Host.WorldEngine.Environment.LocalWeatherEnabled = <span>true</span>;</pre>
<pre>_globeControl.Host.WorldEngine.BaseCopyrightText = <span>&quot; &quot;</span>; // workaround <span>for</span> a display issue</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' turn on the nice atmosphere</span></pre>
<pre>_globeControl.Host.WorldEngine.Environment.AtmosphereDisplay = Microsoft.MapPoint.Rendering3D.Atmospherics.EnvironmentManager.AtmosphereStyle.Scattering</pre>
<pre>&nbsp;</pre>
<pre><span>' default to all off</span></pre>
<pre>_globeControl.Host.WorldEngine.Display3DCursor = <span>False</span></pre>
<pre>_globeControl.Host.WorldEngine.SetWindowsCursor(<span>Nothing</span>)</pre>
<pre>_globeControl.Host.WorldEngine.ShowNavigationControl = <span>False</span></pre>
<pre>_globeControl.Host.WorldEngine.ShowCursorLocationInformation = <span>False</span></pre>
<pre>_globeControl.Host.WorldEngine.ShowScale = <span>False</span></pre>
<pre>_globeControl.Host.WorldEngine.ShowUI = <span>False</span></pre>
<pre>_globeControl.Host.WorldEngine.Environment.SunPosition = <span>Nothing</span></pre>
<pre>_globeControl.Host.WorldEngine.Environment.LocalWeatherEnabled = <span>True</span></pre>
<pre>_globeControl.Host.WorldEngine.BaseCopyrightText = <span>&quot; &quot;</span> ' workaround <span>for</span> a display issue</pre>
</div>
</div>
<p>If you were to run the application at this point, you would see a fully functioning Virtual Earth 3D control with proper data and navigation.</p>
<h4>Control Scheme and Bindings</h4>
<p>The user will control VE3D with the Wiimote by holding the nunchuk in the left hand, which will move the user forward/back/left/right using the joystick.&nbsp; The C and Z buttons on the front of the nunchuk will be used to raise and lower the altitude of the
 camera.&nbsp; The Wiimote, held in the right hand, will be used to toggle various things on or off and interact with menus.&nbsp; The user will also stand on the Balance Board which will use their center of gravity to turn them in the environment.</p>
<p>VE3D bindings allow you to change or create new control schemes for VE3D by placing an XML file in a specific directory as follows:</p>
<ul>
<li><strong>Vista:</strong> C:\Users\&lt;username&gt;\AppData\LocalLow\Microsoft\Virtual Earth 3D
</li><li><strong>XP:</strong> C:\Documents and Settings\&lt;username&gt;\Local Settings\Microsoft\Virtual Earth 3D
</li></ul>
<p>In this directory you will find a <b>Bindings.xml </b>file.&nbsp; This XML schema defines the default keyboard, mouse, Gamepad and other input device properties.&nbsp; Open the file to see the schema used to define events and parameters.</p>
<p>By default, VE3D will load any file named Bindings*.xml from this directory.&nbsp; For the Wiimote control scheme, create a new file named
<b>BindingsWiiEarthVR.xml</b> in this directory.&nbsp; Set the contents of the file to the following:</p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>&lt;?</span><span>xml</span> <span>version</span><span>=&quot;1.0&quot;</span> <span>encoding</span><span>=&quot;utf-8&quot;</span> ?<span>&gt;</span></pre>
<pre><span>&lt;</span><span>Bindings</span><span>&gt;</span></pre>
<pre>    <span>&lt;</span><span>BindingSet</span> <span>Name</span><span>=&quot;WiiEarthVRBindings&quot;</span> <span>AutoUse</span><span>=&quot;True&quot;</span> <span>Cursor</span><span>=&quot;Drag&quot;</span><span>&gt;</span></pre>
<pre>        <span>&lt;!-- Nunchuk joystick --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.NunchukX&quot;</span> <span>Factor</span><span>=&quot;0.5&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Strafe&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.NunchukY&quot;</span> <span>Factor</span><span>=&quot;1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Move&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;!-- Nunchuk buttons --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.NunchukC&quot;</span> <span>Factor</span><span>=&quot;0.20&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Ascend&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.NunchukZ&quot;</span> <span>Factor</span><span>=&quot;-0.20&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Ascend&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;!-- Balance Board --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.BalanceBoardX&quot;</span> <span>Factor</span><span>=&quot;-0.0009&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Turn&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.BalanceBoardY&quot;</span> <span>Factor</span><span>=&quot;0.0009&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Ascend&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;!-- Wiimote buttons --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Home&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ResetOnCenter&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.A&quot;</span> <span>Factor</span><span>=&quot;1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Locations, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Left&quot;</span> <span>Factor</span><span>=&quot;-1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Locations, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Up&quot;</span> <span>Factor</span><span>=&quot;-1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;LocationsMove, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Down&quot;</span> <span>Factor</span><span>=&quot;1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;LocationsMove, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;!-- FPS-style keyboard controls in case we don't have a nunchuk --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.W&quot;</span> <span>Factor</span><span>=&quot;22&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Move&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.S&quot;</span> <span>Factor</span><span>=&quot;-22&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Move&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.D&quot;</span> <span>Factor</span><span>=&quot;22&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Strafe&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.A&quot;</span> <span>Factor</span><span>=&quot;-22&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Strafe&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.Space&quot;</span> <span>Factor</span><span>=&quot;20&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Ascend&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.C&quot;</span> <span>Factor</span><span>=&quot;-20&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;Ascend&quot;</span> <span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;!-- Other keys --&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.F1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;VR920SetZero, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.F2&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;BalanceBoardSetZero, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.F3&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleVR920Stereo, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Minus&quot;</span> <span>Factor</span><span>=&quot;-0.1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;VR920SetEyeDistance, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Plus&quot;</span> <span>Factor</span><span>=&quot;0.1&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;VR920SetEyeDistance, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.One&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleBalanceBoard, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.Two&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleVR920, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.B&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleBalanceBoard, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.V&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleVR920, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>        <span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Key.F&quot;</span><span>&gt;&lt;</span><span>Action</span> <span>Name</span><span>=&quot;FullScreen, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<pre>    <span>&lt;/</span><span>BindingSet</span><span>&gt;</span></pre>
<pre><span>&lt;/</span><span>Bindings</span><span>&gt;</span></pre>
</div>
</div>
<p>The <b>&lt;BindingSet&gt;</b> tags wrap groups of control bindings.&nbsp; It requires a <b>
Name</b> and optionally a <b>Cursor</b>.&nbsp; If the binding set is to be used automatically, as it would be in most cases, set the
<b>AutoUse</b> parameter to <b>True</b>.&nbsp; Inside of that are <b>&lt;Bind&gt;</b> tags.&nbsp; The tag requires the
<strong>Event </strong>parameter and optionally the <b>Factor</b> parameter.&nbsp; The
<b>Event </b>parameter will be used to match the binding to its handler which will be written later.&nbsp; The syntax is &lt;Handler Name&gt;.&lt;Event Name&gt;.&nbsp; The
<b>Factor</b> parameter is optional and can be used to scale the data value up or down to increase or decrease sensitivity of the input method.&nbsp; The
<b>Action</b> tag inside the <strong>Bind</strong> tag is used to map the specific binding to a particular method.&nbsp; Once the handler is written, these will make more sense.</p>
<p>The bindings above create the control scheme described above:&nbsp; NunchukX/Y describe what happens when the analog joystick is moved, NunchukC/Z describe what happens with the C/Z buttons are pressed, and so on.</p>
<p>The bindings also allow for several variations.&nbsp; Bindings are defined for both the IR position (<b>IRX</b>,
<b>IRY</b>) and accelerometer values (<b>AX</b>, <b>AY</b>).&nbsp; If an IR sensor bar is not available, the accelerometer values of the Wiimote can be used instead.&nbsp; Additionally, keyboard bindings are created in the style of a first person shooter using WASD.&nbsp;
 These can be used if a Nunchuk is not available.</p>
<p>Note that some bindings append two <b>Event</b>s together with a &#43; sign.&nbsp; This allows for button combinations.&nbsp; In this case, for the accelerometer and/or IR sensor, we only want to register the action if a button is pressed down.&nbsp; So, those events which
 require the button to be held down contain <b>Wiimote.B&#43;</b> and the event it is combined with.</p>
<p>For those events which require a custom action that will be written separately and not part of the VE3D control, the
<b>Action</b> parameter must contain the action name, followed by a comma, and then the full assembly name:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>Bind</span> <span>Event</span><span>=&quot;Wiimote.One&quot;</span><span>&gt;</span><br>    <span>&lt;</span><span>Action</span> <span>Name</span><span>=&quot;ToggleBalanceBoard, WiiEarthVR, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot;</span><span>/&gt;</span><br><span>&lt;/</span><span>Bind</span><span>&gt;</span></pre>
<br>
</div>
<div id="codeSnippetWrapper"><br>
You can change any of these button bindings simply by changing this XML file and deploying to the directory above.</div>
<h4>Event Source</h4>
<p>An <b>EventSource</b> is needed which will grab data from the Wiimote and pass it along to VE3D as defined by the bindings file above.&nbsp; Create a new class named
<b>WiimoteEventSource</b> which derives from <b>Microsoft.MapPoint.Binding.EventSource</b>&nbsp; as follows:</p>
<p>Next, add an enumeration named <b>WiimoteEvent</b> (the name isn't important) which contains all of the
<b>Name</b> items from the bindings XML file above.&nbsp; It should look like this:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// all events handled by this event source from XML file</span><br><span>public</span> <span>enum</span> WiimoteEvent<br>{<br>    IRX,        <span>// IR X position</span><br>    IRY,        <span>// IR Y position</span><br>    NunchukX,    <span>// Nunchuk joystick X position</span><br>    NunchukY,    <span>// Nunchuk joystick Y position</span><br>    NunchukC,    <span>// Nunchuk C button</span><br>    NunchukZ,    <span>// Nunchuk Z button</span><br>    AX,            <span>// Wiimote accelerometer X</span><br>    AY,            <span>// Wiimote accelerometer Y</span><br>    Up,            <span>// Dpad up</span><br>    Down,        <span>// Dpad down</span><br>    Left,        <span>// Dpad left</span><br>    Right,        <span>// Dpad right</span><br>    A,            <span>// A button</span><br>    B,            <span>// B button</span><br>    Minus,        <span>// Minus button</span><br>    Home,        <span>// Wiimote Home button</span><br>    Plus,        <span>// Plus button</span><br>    One,        <span>// Wiimote One button</span><br>    Two,        <span>// Wiimote Two button</span><br>    BalanceBoardX,    <span>// Balance Board COG X</span><br>    BalanceBoardY    <span>// Balance Board COG Y</span><br>}</pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>' all events handled by this event source from XML file</span><br><span>Public</span> <span>Enum</span> WiimoteEvent<br>    IRX <span>' IR X position</span><br>    IRY <span>' IR Y position</span><br>    NunchukX <span>' Nunchuk joystick X position</span><br>    NunchukY <span>' Nunchuk joystick Y position</span><br>    NunchukC <span>' Nunchuk C button</span><br>    NunchukZ <span>' Nunchuk Z button</span><br>    AX <span>' Wiimote accelerometer X</span><br>    AY <span>' Wiimote accelerometer Y</span><br>    Up <span>' Dpad up</span><br>    Down <span>' Dpad down</span><br>    Left <span>' Dpad left</span><br>    Right <span>' Dpad right</span><br>    A <span>' A button</span><br>    B <span>' B button</span><br>    Minus <span>' Minus button</span><br>    Home <span>' Wiimote Home button</span><br>    Plus <span>' Plus button</span><br>    One <span>' Wiimote One button</span><br>    Two <span>' Wiimote Two button</span><br>    BalanceBoardX <span>' Balance Board COG X</span><br>    BalanceBoardY <span>' Balance Board COG Y</span><br><span>End</span> Enum</pre>
<br>
</div>
<p>Next, several methods from the <b>EventSource</b> object need to be overridden:&nbsp;
<b>GetEventData</b>, <b>IsModifier</b>, <b>CanModify</b>, <b>TryGetEventId</b>, <b>
TryGetEventName</b>, <b>Name</b>.&nbsp; The methods do the following:</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="200">
<p align="center"><b>Method/Property</b></p>
</td>
<td valign="top" width="200">
<p align="center"><b>Description</b></p>
</td>
</tr>
<tr>
<td valign="top" width="200">GetEventData</td>
<td valign="top" width="200">Unsure at the moment...does not need to be implemented?</td>
</tr>
<tr>
<td valign="top" width="200">IsModifier</td>
<td valign="top" width="200">Returns a boolean stating whether the passed in event ID is a modifier (such as the Wiimote.B event above)</td>
</tr>
<tr>
<td valign="top" width="200">CanModify</td>
<td valign="top" width="200">Returns a boolean stating whether the current event is allowed as a modifier</td>
</tr>
<tr>
<td valign="top" width="200">TryGetEventID</td>
<td valign="top" width="200">Maps a string event name from the bindings file to the integer value in the enumeration above</td>
</tr>
<tr>
<td valign="top" width="200">TryGetEventName</td>
<td valign="top" width="200">Maps an integer event ID to the string name in the enumeration above</td>
</tr>
<tr>
<td valign="top" width="200">Name (property)</td>
<td valign="top" width="200">Returns the name of the handler which must match the name in the XML file above (Wiimote in this case)</td>
</tr>
</tbody>
</table>
<p>The code for these methods is presented below:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// return out value of the passed enum</span></pre>
<pre><span>public</span> <span>override</span> <span>bool</span> TryGetEventId(<span>string</span> eventName, <span>out</span> <span>int</span> eventId)</pre>
<pre>{</pre>
<pre>    eventId = (<span>int</span>)Enum.Parse(<span>typeof</span>(WiimoteEvent), eventName);</pre>
<pre>    <span>return</span> <span>true</span>;</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// return out the string name of the passed in enum value</span></pre>
<pre><span>public</span> <span>override</span> <span>bool</span> TryGetEventName(<span>int</span> eventId, <span>out</span> <span>string</span> eventName)</pre>
<pre>{</pre>
<pre>    eventName = ((WiimoteEvent)eventId).ToString();</pre>
<pre>    <span>return</span> <span>true</span>;</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// unknown</span></pre>
<pre><span>public</span> <span>override</span> EventData GetEventData(<span>int</span> eventId, EventActivateState state)</pre>
<pre>{</pre>
<pre>    <span>throw</span> <span>new</span> NotImplementedException();</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// can the event be used as a modifier?</span></pre>
<pre><span>public</span> <span>override</span> <span>bool</span> IsModifier(<span>int</span> eventId)</pre>
<pre>{</pre>
<pre>    <span>// yes to all for now</span></pre>
<pre>    <span>return</span> <span>true</span>;</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// can the supplied event be used as a modifier?</span></pre>
<pre><span>public</span> <span>override</span> <span>bool</span> CanModify(<span>int</span> eventId, EventKey other)</pre>
<pre>{</pre>
<pre>    <span>// only if it's from us</span></pre>
<pre>    <span>return</span> (other.Source == <span>this</span>);</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// this must match the Source name in the bindings XML file</span></pre>
<pre><span>public</span> <span>override</span> <span>string</span> Name</pre>
<pre>{</pre>
<pre>    get { <span>return</span> <span>&quot;Wiimote&quot;</span>; }</pre>
<pre>}</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' return out value of the passed enum</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>Function</span> TryGetEventId(<span>ByVal</span> eventName <span>As</span> <span>String</span>, &lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> eventId <span>As</span> <span>Integer</span>) <span>As</span> <span>Boolean</span></pre>
<pre>    eventId = <span>CInt</span>(Fix(System.<span>Enum</span>.Parse(<span>GetType</span>(WiimoteEvent), eventName)))</pre>
<pre>    <span>Return</span> <span>True</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>' return out the string name of the passed in enum value</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>Function</span> TryGetEventName(<span>ByVal</span> eventId <span>As</span> <span>Integer</span>, &lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> eventName <span>As</span> <span>String</span>) <span>As</span> <span>Boolean</span></pre>
<pre>    eventName = (<span>CType</span>(eventId, WiimoteEvent)).ToString()</pre>
<pre>    <span>Return</span> <span>True</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>' unknown</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>Function</span> GetEventData(<span>ByVal</span> eventId <span>As</span> <span>Integer</span>, <span>ByVal</span> state <span>As</span> EventActivateState) <span>As</span> EventData</pre>
<pre>    <span>Throw</span> <span>New</span> NotImplementedException()</pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>' can the event be used as a modifier?</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>Function</span> IsModifier(<span>ByVal</span> eventId <span>As</span> <span>Integer</span>) <span>As</span> <span>Boolean</span></pre>
<pre>    <span>' yes to all for now</span></pre>
<pre>    <span>Return</span> <span>True</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>' can the supplied event be used as a modifier?</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>Function</span> CanModify(<span>ByVal</span> eventId <span>As</span> <span>Integer</span>, <span>ByVal</span> other <span>As</span> EventKey) <span>As</span> <span>Boolean</span></pre>
<pre>    <span>' only if it's from us</span></pre>
<pre>    <span>Return</span> (other.Source <span>Is</span> <span>Me</span>)</pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>' this must match the Source name in the bindings XML file</span></pre>
<pre><span>Public</span> <span>Overrides</span> <span>ReadOnly</span> <span>Property</span> Name() <span>As</span> <span>String</span></pre>
<pre>    <span>Get</span></pre>
<pre>        <span>Return</span> <span>&quot;Wiimote&quot;</span></pre>
<pre>    <span>End</span> <span>Get</span></pre>
<pre><span>End</span> <span>Property</span></pre>
</div>
</div>
<p>With that in place, the constructor can be implemented which will call the base constructor and connect to the Wiimote.&nbsp; It is assumed you read the Wiimote article above and know how the library works.</p>
<p>The constructor must take one argument passed from the main from:&nbsp; an instance of the
<b>GlobeControl</b>'s <b>ActionSystem</b>.&nbsp; This just gets passed directly to the parent object's constructor untouched.&nbsp; The constructor code looks like the following:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> WiimoteEventSource(ActionSystem actionSystem) : <span>base</span>(actionSystem)<br>{<br>    <span>// get all connected Wiimotes</span><br>    WiimoteCollection wc = <span>new</span> WiimoteCollection();<br>    wc.FindAllWiimotes();<br><br>    <span>// setup wiimotes and event handlers</span><br>    <span>foreach</span>(Wiimote wm <span>in</span> wc)<br>    {<br>        wm.WiimoteChanged &#43;= <span>new</span> EventHandler&lt;WiimoteChangedEventArgs&gt;(OnWiimoteChanged);<br>        wm.WiimoteExtensionChanged &#43;= <span>new</span> EventHandler&lt;WiimoteExtensionChangedEventArgs&gt;(OnWiimoteExtensionChanged);<br>        wm.Connect();<br><br>        <span>// if we don't have an extension, set the report type to IR and accel's only</span><br>        <span>if</span>(!wm.WiimoteState.Extension &amp;&amp; wm.WiimoteState.ExtensionType != ExtensionType.BalanceBoard)<br>            wm.SetReportType(InputReport.IRAccel, <span>true</span>);<br><br>        <span>if</span>(wm.WiimoteState.ExtensionType == ExtensionType.BalanceBoard)<br>            _bb = wm;<br>        <span>else</span><br>            _wm = wm;<br><br>        <span>// turn off all LEDs</span><br>        wm.SetLEDs(0x00);<br>    }<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> actionSystem <span>As</span> ActionSystem)<br>    <span>MyBase</span>.<span>New</span>(actionSystem)<br><br>    <span>' get all connected Wiimotes</span><br>    <span>Dim</span> wc <span>As</span> <span>New</span> WiimoteCollection()<br>    wc.FindAllWiimotes()<br><br>    <span>' setup wiimotes and event handlers</span><br>    <span>For</span> <span>Each</span> wm <span>As</span> Wiimote <span>In</span> wc<br>        <span>AddHandler</span> wm.WiimoteChanged, <span>AddressOf</span> OnWiimoteChanged<br>        <span>AddHandler</span> wm.WiimoteExtensionChanged, <span>AddressOf</span> OnWiimoteExtensionChanged<br>        wm.Connect()<br><br>        <span>' if we don't have an extension, set the report type to IR and accel's only</span><br>        <span>If</span> (<span>Not</span> wm.WiimoteState.Extension) <span>AndAlso</span> wm.WiimoteState.ExtensionType &lt;&gt; ExtensionType.BalanceBoard <span>Then</span><br>            wm.SetReportType(InputReport.IRAccel, <span>True</span>)<br>        <span>End</span> <span>If</span><br><br>        <span>If</span> wm.WiimoteState.ExtensionType = ExtensionType.BalanceBoard <span>Then</span><br>            _bb = wm<br>        <span>Else</span><br>            _wm = wm<br>        <span>End</span> <span>If</span><br><br>        <span>' turn off all LEDs</span><br>        wm.SetLEDs(&amp;H00)<br>    <span>Next</span> wm<br><span>End</span> Sub</pre>
<br>
</div>
<p>The <b>OnWiimoteExtensionChanged</b> method simply sets the report mode for the Wiimote based on whether or not a Nunchuk is inserted as shown:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> OnWiimoteExtensionChanged(<span>object</span> sender, WiimoteExtensionChangedEventArgs args)<br>{<br>    <span>if</span>(_wm == <span>null</span>)<br>        <span>return</span>;<br><br>    <span>// if nunchuk inserted, set the report type to return extension data</span><br>    <span>if</span>(args.ExtensionType == ExtensionType.Nunchuk &amp;&amp; args.Inserted)<br>        _wm.SetReportType(InputReport.IRExtensionAccel, <span>true</span>);<br>    <span>else</span> <span>// in all other cases, set it to the default IR and accel's</span><br>        _wm.SetReportType(InputReport.IRAccel, <span>true</span>);<br>}</pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> OnWiimoteExtensionChanged(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> args <span>As</span> WiimoteExtensionChangedEventArgs)<br>    <span>If</span> _wm <span>Is</span> <span>Nothing</span> <span>Then</span><br>        <span>Return</span><br>    <span>End</span> <span>If</span><br><br>    <span>' if nunchuk inserted, set the report type to return extension data</span><br>    <span>If</span> args.ExtensionType = ExtensionType.Nunchuk <span>AndAlso</span> args.Inserted <span>Then</span><br>        _wm.SetReportType(InputReport.IRExtensionAccel, <span>True</span>)<br>    <span>Else</span> <span>' in all other cases, set it to the default IR and accel's</span><br>        _wm.SetReportType(InputReport.IRAccel, <span>True</span>)<br>    <span>End</span> <span>If</span><br><span>End</span> Sub</pre>
<br>
</div>
<p>The <b>OnWiimoteChanged</b> event handler is where the Wiimote data is handled and sent off to the VE3D control to reflect the changes.&nbsp; First, we handle the Balance Board.&nbsp; If the Balance Board is the controller reporting data, we take the center of gravity
 values and pass them to VE3D.&nbsp; This code looks at the appropriate values, determines if they are beyond the specified thresholds for the dead zones, and, if they are, activates the event for that value using the
<b>Execute </b>method.&nbsp; <b>Execute </b>is a method in the base <b>EventSource</b> class.&nbsp; This method will activate the event specified from the enumeration (which, remember, is contained in the bindings XML file) with the value associated with that event.&nbsp;
 An <b>EventData</b> object of some type must be created and passed to the <b>Execute</b> method.&nbsp; There are two
<b>EventData</b> types to know about:&nbsp; <b>AxisEventData</b> and <b>ButtonEventData</b>.&nbsp;
<b>AxisEventData</b> should be used when an event is activated that will modify the map position in some way.&nbsp; That is, if the map is being turned, elevation is changing, etc.&nbsp;
<b>ButtonEventData</b> should be used if the event is a simple toggle like pressing a button down and releasing it.</p>
<p>The Balance Board code can be seen below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>if</span>(ws.ExtensionType == ExtensionType.BalanceBoard &amp;&amp; <span>this</span>.BalanceBoardEnabled)</pre>
<pre>{</pre>
<pre>    <span>float</span> x1 = ws.BalanceBoardState.CenterOfGravity.X;</pre>
<pre>    <span>if</span>(x1 &gt; Properties.Settings.Default.BBDeadX || x1 &lt; -Properties.Settings.Default.BBDeadX)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.BalanceBoardX), x1 - _zero.X));</pre>
<pre>    <span>float</span> y1 = ws.BalanceBoardState.CenterOfGravity.Y;</pre>
<pre>    <span>if</span>(y1 &gt; Properties.Settings.Default.BBDeadY || y1 &lt; -Properties.Settings.Default.BBDeadY)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.BalanceBoardY), y1 - _zero.Y));</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>If</span> ws.ExtensionType = ExtensionType.BalanceBoard <span>AndAlso</span> <span>Me</span>.BalanceBoardEnabled <span>Then</span></pre>
<pre>    <span>Dim</span> x1 <span>As</span> <span>Single</span> = ws.BalanceBoardState.CenterOfGravity.X</pre>
<pre>    <span>If</span> x1 &gt; My.Settings.<span>Default</span>.BBDeadX <span>OrElse</span> x1 &lt; -My.Settings.<span>Default</span>.BBDeadX <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.BalanceBoardX))), x1 - _zero.X))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>    <span>Dim</span> y1 <span>As</span> <span>Single</span> = ws.BalanceBoardState.CenterOfGravity.Y</pre>
<pre>    <span>If</span> y1 &gt; My.Settings.<span>Default</span>.BBDeadY <span>OrElse</span> y1 &lt; -My.Settings.<span>Default</span>.BBDeadY <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.BalanceBoardY))), y1 - _zero.Y))</pre>
<pre>    <span>End</span> If</pre>
</div>
</div>
<p>Next, let's handle the IR and accelerometer data.&nbsp; The IR midpoint of the X and Y axes will be used from the
<b>WiimoteState</b> object to activate the <b>IRX</b> and <b>IRY</b> events we defined above in the bindings XML file.&nbsp; The accelerometer X and Y values will be used to activate the
<b>AX </b>and <b>AY</b> events.</p>
<p>This snippet assumes that there is a boolean property named <b>UseIR</b> created in the project to determine whether IR or motion values are used.&nbsp; Additionally, it assumes there are property settings created which contain values for the X/Y &quot;dead zones&quot;
 for the IR and accelerometers.&nbsp; These dead zones are used as a way to only activate the event when the values are pushed beyond the thresholds.&nbsp; This allows there to be a margin where the user's hand will not be read as movement, allowing the user to not have
 to worry about keeping a steady hand.</p>
<p>The application linked above uses the following default values for dead zones:</p>
<ul>
<li>NunchukDeadX/Y -&gt; 0.025 </li><li>WiimoteDeadX/Y -&gt; 0.15 </li><li>IRDeadX/Y -&gt; 0.1 </li><li>BBDeadX/Y –&gt; 3 </li></ul>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// if we're using the IR</span></pre>
<pre><span>if</span>(Properties.Settings.Default.UseIR)</pre>
<pre>{</pre>
<pre>    <span>// and both LEDs are found</span></pre>
<pre>    <span>if</span>(ws.IRState.Found1 &amp;&amp; ws.IRState.Found2)</pre>
<pre>    {</pre>
<pre>        <span>// normalize the midpoints to -0.5 to 0.5 (from 0 to 1.0)</span></pre>
<pre>        <span>float</span> x = ws.IRState.MidX - 0.5f;</pre>
<pre>        <span>float</span> y = ws.IRState.MidY - 0.5f;</pre>
<pre>&nbsp;</pre>
<pre>        <span>// if we're beyond the thresholds, activate the events</span></pre>
<pre>        <span>if</span>(x &gt; Properties.Settings.Default.IRDeadX || x &lt; -Properties.Settings.Default.IRDeadX)</pre>
<pre>            <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.IRX), x));</pre>
<pre>        <span>if</span>(y &gt; Properties.Settings.Default.IRDeadY || y &lt; -Properties.Settings.Default.IRDeadY)</pre>
<pre>            <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.IRY), y));</pre>
<pre>&nbsp;</pre>
<pre>        <span>// save the last IR settings...these get used if we go beyond the range of the IRs.</span></pre>
<pre>        <span>// in that case, the last used positions will be used until the Wiimote comes back in range</span></pre>
<pre>        <span>this</span>._lastIRX = x;</pre>
<pre>        <span>this</span>._lastIRY = y;</pre>
<pre>    }</pre>
<pre>    <span>else</span> <span>// one or both LEDs aren't seen</span></pre>
<pre>    {</pre>
<pre>        <span>// activate events based on the last known positions</span></pre>
<pre>        <span>if</span>(<span>this</span>._lastIRX &gt; Properties.Settings.Default.IRDeadX || <span>this</span>._lastIRX &lt; -Properties.Settings.Default.IRDeadX)</pre>
<pre>            <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.IRX), <span>this</span>._lastIRX));</pre>
<pre>        <span>if</span>(<span>this</span>._lastIRY &gt; Properties.Settings.Default.IRDeadY || <span>this</span>._lastIRY &lt; -Properties.Settings.Default.IRDeadY)</pre>
<pre>            <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.IRY), <span>this</span>._lastIRY));</pre>
<pre>    }</pre>
<pre>}</pre>
<pre><span>else</span> <span>// we're using motion controls</span></pre>
<pre>{</pre>
<pre>    <span>// activate the events based on the accelerometer values</span></pre>
<pre>    <span>if</span>(ws.AccelState.X &gt; Properties.Settings.Default.WiimoteDeadX || ws.AccelState.X &lt; -Properties.Settings.Default.WiimoteDeadX)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.AX), ws.AccelState.X));</pre>
<pre>    <span>if</span>(ws.AccelState.Y &gt; Properties.Settings.Default.WiimoteDeadY || ws.AccelState.Y &lt; -Properties.Settings.Default.WiimoteDeadY)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.AY), ws.AccelState.Y));</pre>
<pre>}</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' if we're using the IR</span></pre>
<pre><span>If</span> My.Settings.<span>Default</span>.UseIR <span>Then</span></pre>
<pre>    <span>' and both LEDs are found</span></pre>
<pre>    <span>If</span> ws.IRState.Found1 <span>AndAlso</span> ws.IRState.Found2 <span>Then</span></pre>
<pre>        <span>' normalize the midpoints to -0.5 to 0.5 (from 0 to 1.0)</span></pre>
<pre>        <span>Dim</span> x <span>As</span> <span>Single</span> = ws.IRState.MidX - 0.5f</pre>
<pre>        <span>Dim</span> y <span>As</span> <span>Single</span> = ws.IRState.MidY - 0.5f</pre>
<pre>&nbsp;</pre>
<pre>        <span>' if we're beyond the thresholds, activate the events</span></pre>
<pre>        <span>If</span> x &gt; My.Settings.<span>Default</span>.IRDeadX <span>OrElse</span> x &lt; -My.Settings.<span>Default</span>.IRDeadX <span>Then</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.IRX))), x))</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>        <span>If</span> y &gt; My.Settings.<span>Default</span>.IRDeadY <span>OrElse</span> y &lt; -My.Settings.<span>Default</span>.IRDeadY <span>Then</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.IRY))), y))</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>' save the last IR settings...these get used if we go beyond the range of the IRs.</span></pre>
<pre>        <span>' in that case, the last used positions will be used until the Wiimote comes back in range</span></pre>
<pre>        <span>Me</span>._lastIRX = x</pre>
<pre>        <span>Me</span>._lastIRY = y</pre>
<pre>    <span>Else</span> <span>' one or both LEDs aren't seen</span></pre>
<pre>        <span>' activate events based on the last known positions</span></pre>
<pre>        <span>If</span> <span>Me</span>._lastIRX &gt; My.Settings.<span>Default</span>.IRDeadX <span>OrElse</span> <span>Me</span>._lastIRX &lt; -My.Settings.<span>Default</span>.IRDeadX <span>Then</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.IRX))), <span>Me</span>._lastIRX))</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>        <span>If</span> <span>Me</span>._lastIRY &gt; My.Settings.<span>Default</span>.IRDeadY <span>OrElse</span> <span>Me</span>._lastIRY &lt; -My.Settings.<span>Default</span>.IRDeadY <span>Then</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.IRY))), <span>Me</span>._lastIRY))</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>Else</span> <span>' we're using motion controls</span></pre>
<pre>    <span>' activate the events based on the accelerometer values</span></pre>
<pre>    <span>If</span> ws.AccelState.X &gt; My.Settings.<span>Default</span>.WiimoteDeadX <span>OrElse</span> ws.AccelState.X &lt; -My.Settings.<span>Default</span>.WiimoteDeadX <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.AX))), ws.AccelState.X))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>    <span>If</span> ws.AccelState.Y &gt; My.Settings.<span>Default</span>.WiimoteDeadY <span>OrElse</span> ws.AccelState.Y &lt; -My.Settings.<span>Default</span>.WiimoteDeadY <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.AY))), ws.AccelState.Y))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>End</span> If</pre>
</div>
</div>
<p>Next, the nunchuk values need to be read and the associated events activated.&nbsp; This is done as follows:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// if the nunchuk is connected</span></pre>
<pre><span>if</span>(ws.Extension &amp;&amp; ws.ExtensionType == ExtensionType.Nunchuk)</pre>
<pre>{</pre>
<pre>    <span>// activate the nunchuk-based events</span></pre>
<pre>    <span>if</span>(ws.NunchukState.X &gt; Properties.Settings.Default.NunchukDeadX || ws.NunchukState.X &lt; -Properties.Settings.Default.NunchukDeadX)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.NunchukX), ws.NunchukState.X));</pre>
<pre>    <span>if</span>(ws.NunchukState.Y &gt; Properties.Settings.Default.NunchukDeadY || ws.NunchukState.Y &lt; -Properties.Settings.Default.NunchukDeadY)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.NunchukY), ws.NunchukState.Y));</pre>
<pre>    <span>if</span>(ws.NunchukState.C)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.NunchukC), 1.0f));</pre>
<pre>    <span>if</span>(ws.NunchukState.Z)</pre>
<pre>        <span>this</span>.Execute(<span>new</span> AxisEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)WiimoteEvent.NunchukZ), 1.0f));</pre>
<pre>}</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' if the nunchuk is connected</span></pre>
<pre><span>If</span> ws.Extension <span>AndAlso</span> ws.ExtensionType = ExtensionType.Nunchuk <span>Then</span></pre>
<pre>    <span>' activate the nunchuk-based events</span></pre>
<pre>    <span>If</span> ws.NunchukState.X &gt; My.Settings.<span>Default</span>.NunchukDeadX <span>OrElse</span> ws.NunchukState.X &lt; -My.Settings.<span>Default</span>.NunchukDeadX <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.NunchukX))), ws.NunchukState.X))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>    <span>If</span> ws.NunchukState.Y &gt; My.Settings.<span>Default</span>.NunchukDeadY <span>OrElse</span> ws.NunchukState.Y &lt; -My.Settings.<span>Default</span>.NunchukDeadY <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.NunchukY))), ws.NunchukState.Y))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>    <span>If</span> ws.NunchukState.C <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.NunchukC))), 1.0f))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>    <span>If</span> ws.NunchukState.Z <span>Then</span></pre>
<pre>        <span>Me</span>.Execute(<span>New</span> AxisEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(WiimoteEvent.NunchukZ))), 1.0f))</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>End</span> If</pre>
</div>
</div>
<p>Finally, the button events need to be activated.&nbsp; A helper method which will check the current button state will be used for determining which button of all the Wiimote buttons is pressed.&nbsp; For those that are, the appropriate event is activated with a call
 to <b>Execute</b>.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> <span>void</span> HandleButton(WiimoteEvent we, <span>bool</span> buttonState, <span>bool</span> lastButtonState)</pre>
<pre>{</pre>
<pre>    <span>if</span>(buttonState == lastButtonState)</pre>
<pre>        <span>return</span>;</pre>
<pre>    <span>else</span></pre>
<pre>    {</pre>
<pre>        <span>if</span>(buttonState)</pre>
<pre>            <span>this</span>.Execute(<span>new</span> ButtonEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)we), EventActivateState.Activate));</pre>
<pre>        <span>else</span></pre>
<pre>            <span>this</span>.Execute(<span>new</span> ButtonEventData(<span>new</span> EventKey(<span>this</span>, (<span>int</span>)we), EventActivateState.Deactivate));</pre>
<pre>    }</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// handle all the Wiimote buttons</span></pre>
<pre>HandleButton(WiimoteEvent.Up, ws.ButtonState.Up, _lastBS.Up);</pre>
<pre>HandleButton(WiimoteEvent.Down, ws.ButtonState.Down, _lastBS.Down);</pre>
<pre>HandleButton(WiimoteEvent.Left, ws.ButtonState.Left, _lastBS.Left);</pre>
<pre>HandleButton(WiimoteEvent.Right, ws.ButtonState.Right, _lastBS.Right);</pre>
<pre>HandleButton(WiimoteEvent.A, ws.ButtonState.A, _lastBS.A);</pre>
<pre>HandleButton(WiimoteEvent.B, ws.ButtonState.B, _lastBS.B);</pre>
<pre>HandleButton(WiimoteEvent.Minus, ws.ButtonState.Minus, _lastBS.Minus);</pre>
<pre>HandleButton(WiimoteEvent.Home, ws.ButtonState.Home, _lastBS.Home);</pre>
<pre>HandleButton(WiimoteEvent.Plus, ws.ButtonState.Plus, _lastBS.Plus);</pre>
<pre>HandleButton(WiimoteEvent.One, ws.ButtonState.One, _lastBS.One);</pre>
<pre>HandleButton(WiimoteEvent.Two, ws.ButtonState.Two, _lastBS.Two);</pre>
<pre>&nbsp;</pre>
<pre>...</pre>
<pre>&nbsp;</pre>
<pre><span>// save off the current button state for next time</span></pre>
<pre>_lastBS = ws.ButtonState;</pre>
<pre>_lastNunchuk = ws.NunchukState;</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> <span>Sub</span> HandleButton(<span>ByVal</span> we <span>As</span> WiimoteEvent, <span>ByVal</span> buttonState <span>As</span> <span>Boolean</span>, <span>ByVal</span> lastButtonState <span>As</span> <span>Boolean</span>)</pre>
<pre>    <span>If</span> buttonState = lastButtonState <span>Then</span></pre>
<pre>        <span>Return</span></pre>
<pre>    <span>Else</span></pre>
<pre>        <span>If</span> buttonState <span>Then</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> ButtonEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(we))), EventActivateState.Activate))</pre>
<pre>        <span>Else</span></pre>
<pre>            <span>Me</span>.Execute(<span>New</span> ButtonEventData(<span>New</span> EventKey(<span>Me</span>, <span>CInt</span>(Fix(we))), EventActivateState.Deactivate))</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>End</span> <span>Sub</span></pre>
<pre>&nbsp;</pre>
<pre>...</pre>
<pre>&nbsp;</pre>
<pre><span>' handle all the Wiimote buttons</span></pre>
<pre>HandleButton(WiimoteEvent.Up, ws.ButtonState.Up, _lastBS.Up)</pre>
<pre>HandleButton(WiimoteEvent.Down, ws.ButtonState.Down, _lastBS.Down)</pre>
<pre>HandleButton(WiimoteEvent.Left, ws.ButtonState.Left, _lastBS.Left)</pre>
<pre>HandleButton(WiimoteEvent.Right, ws.ButtonState.Right, _lastBS.Right)</pre>
<pre>HandleButton(WiimoteEvent.A, ws.ButtonState.A, _lastBS.A)</pre>
<pre>HandleButton(WiimoteEvent.B, ws.ButtonState.B, _lastBS.B)</pre>
<pre>HandleButton(WiimoteEvent.Minus, ws.ButtonState.Minus, _lastBS.Minus)</pre>
<pre>HandleButton(WiimoteEvent.Home, ws.ButtonState.Home, _lastBS.Home)</pre>
<pre>HandleButton(WiimoteEvent.Plus, ws.ButtonState.Plus, _lastBS.Plus)</pre>
<pre>HandleButton(WiimoteEvent.One, ws.ButtonState.One, _lastBS.One)</pre>
<pre>HandleButton(WiimoteEvent.Two, ws.ButtonState.Two, _lastBS.Two)</pre>
<pre>&nbsp;</pre>
<pre><span>' save off the current button state for next time</span></pre>
<pre>_lastBS = ws.ButtonState</pre>
<pre>_lastNunchuk = ws.NunchukState</pre>
</div>
</div>
<p>And, the current button values are stored away to check on the next event so button events are only fired once.</p>
<p>Now that the event source object is written, it needs to be hooked up to the <b>
GlobeControl</b> so it can be used.&nbsp; This can be done by creating an instance of the
<b>WiimoteEventSource</b> object, passing in the VE3D's <b>ActionSystem </b>from the
<b>BindingsManager</b> object.&nbsp; Then, the event source instance is passed to the <b>
ActionSystem</b>'s <b>EventSourceManager</b> and registered using the <b>RegisterEventSource</b> method.&nbsp; Event sources should re registered before the control is added to the form.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>// wiimote events</span></pre>
<pre><span>private</span> WiimoteEventSource _wiimoteEventSource;</pre>
<pre>&nbsp;</pre>
<pre>...</pre>
<pre>&nbsp;</pre>
<pre><span>// create a new instance of the Wiimote event handler</span></pre>
<pre>_wiimoteEventSource = <span>new</span> WiimoteEventSource(<span>this</span>.globeControl.Host.BindingsManager.ActionSystem, <span>this</span>);</pre>
<pre>&nbsp;</pre>
<pre><span>// register it in the event source list</span></pre>
<pre>_globeControl.Host.BindingsManager.ActionSystem.EventSourceManager.RegisterEventSource(<span>this</span>._wiimoteEventSource);</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' wiimote events</span></pre>
<pre><span>Private</span> _wiimoteEventSource <span>As</span> WiimoteEventSource</pre>
<pre>&nbsp;</pre>
<pre>...</pre>
<pre>&nbsp;</pre>
<pre><span>' create a new instance of the Wiimote event handler</span></pre>
<pre>_wiimoteEventSource = <span>New</span> WiimoteEventSource(<span>Me</span>.globeControl.Host.BindingsManager.ActionSystem, <span>Me</span>)</pre>
<pre>&nbsp;</pre>
<pre><span>' register it in the event source list</span></pre>
<pre>_globeControl.Host.BindingsManager.ActionSystem.EventSourceManager.RegisterEventSource(<span>Me</span>._wiimoteEventSource)</pre>
</div>
</div>
<h4>Actions and the BindingManager</h4>
<p>Our binding list contains several action types that are not defined by the default VE3D actions.&nbsp; These actions and their handlers must be registered with the VE3D control.&nbsp; The actions can be registered as follows in the
<strong>FirstFrameRendered</strong> event handler:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>BindingsSource bs = <span>new</span> BindingsSource(<span>base</span>.GetType());</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;Locations&quot;</span>, LocationsHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;LocationsMove&quot;</span>, LocationsMoveHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleVR920&quot;</span>, ToggleVR920Handler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;VR920SetZero&quot;</span>, VR920SetZero);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;BalanceBoardSetZero&quot;</span>, BalanceBoardSetZero);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleBalanceBoard&quot;</span>, ToggleBalanceBoardHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;FullScreen&quot;</span>, FullScreenHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleVR920Stereo&quot;</span>, ToggleVR920Stereo);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;VR920SetEyeDistance&quot;</span>, VR920SetEyeDistance);</pre>
</div>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>BindingsSource bs = <span>new</span> BindingsSource(base.<span>GetType</span>());</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;Locations&quot;</span>, LocationsHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;LocationsMove&quot;</span>, LocationsMoveHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleVR920&quot;</span>, ToggleVR920Handler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;VR920SetZero&quot;</span>, VR920SetZero);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;BalanceBoardSetZero&quot;</span>, BalanceBoardSetZero);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleBalanceBoard&quot;</span>, ToggleBalanceBoardHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;FullScreen&quot;</span>, FullScreenHandler);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;ToggleVR920Stereo&quot;</span>, ToggleVR920Stereo);</pre>
<pre>_globeControl.Host.BindingsManager.RegisterAction(bs, <span>&quot;VR920SetEyeDistance&quot;</span>, VR920SetEyeDistance);</pre>
</div>
</div>
<p>With the actions registered and handlers associated with them, the actual handlers need to be implemented.&nbsp; All event handler methods must be of the following signature:</p>
<p><b>C#</b></p>
<div>
<pre><span>public</span> <span>bool</span> EventHandler(EventData cause)</pre>
</div>
<p><b>VB</b></p>
<div>
<pre><span>Public</span> <span>Function</span> EventHandler(<span>ByVal</span> cause <span>As</span> EventData) <span>As</span> Boolean</pre>
</div>
<p>Let's take a look at the <strong>FullScreen </strong>binding which simply turns the status bar at the bottom of the window on and off:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>bool</span> FullScreenHandler(EventData eventData)<br>{<br>    <span>if</span>(eventData.Activate)<br>        BeginInvoke(<span>new</span> UIEventHandlerDelegate(FullScreen), eventData);<br>    <span>return</span> <span>true</span>;<br>}</pre>
<br>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Function</span> FullScreenHandler(<span>ByVal</span> eventData <span>As</span> EventData) <span>As</span> <span>Boolean</span><br>    <span>If</span> eventData.Activate <span>Then</span><br>        BeginInvoke(<span>New</span> UIEventHandlerDelegate(<span>AddressOf</span> FullScreen), eventData)<br>    <span>End</span> <span>If</span><br>    <span>Return</span> <span>True</span><br><span>End</span> <span>Function</span><br><br><span>Private</span> <span>Sub</span> FullScreen(<span>ByVal</span> eventData <span>As</span> EventData)<br>    statusStrip1.Visible = <span>Not</span> statusStrip1.Visible<br><span>End</span> <span>Sub</span><br></pre>
<br>
</div>
<p>Because we are in the VE3D thread when this handler is called, we need to use <strong>
BeginInvoke</strong> to call the real method on the UI thread.</p>
<p>Be sure to check the source code for the full demo linked above for the location handler methods.&nbsp; I omitted them here since it is just more of the same type of code above.</p>
<h3></h3>
<h3></h3>
<h3><b>VR920 Head Tracker</b></h3>
<p>Once the VR920 glasses and driver are installed on your PC, getting the data required from the glasses is quite easy.&nbsp; We are going to create an object named
<strong>VR920Tracker</strong> which will pull data from the device and send it to VE3D.</p>
<p>First we need to setup a few P/Invoke signatures to talk to the glasses as follows:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>[DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError = <span>true</span>, CharSet = CharSet.<span>Auto</span>)]</pre>
<pre><span>private</span> <span>static</span> extern int IWROpenTracker();</pre>
<pre>&nbsp;</pre>
<pre>[DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError = <span>true</span>, CharSet = CharSet.<span>Auto</span>)]</pre>
<pre><span>private</span> <span>static</span> extern void IWRZeroSet();</pre>
<pre>&nbsp;</pre>
<pre>[DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError = <span>true</span>, CharSet = CharSet.<span>Auto</span>)]</pre>
<pre><span>private</span> <span>static</span> extern int IWRGetTracking(out int yaw, out int pitch, out int roll);</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>const</span> int ERROR_SUCCESS  = 0;</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>&lt;DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError := <span>True</span>, CharSet := CharSet.<span>Auto</span>)&gt; _</pre>
<pre><span>Private</span> <span>Shared</span> <span>Function</span> IWROpenTracker() <span>As</span> <span>Integer</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre>&lt;DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError := <span>True</span>, CharSet := CharSet.<span>Auto</span>)&gt; _</pre>
<pre><span>Private</span> <span>Shared</span> <span>Sub</span> IWRZeroSet()</pre>
<pre><span>End</span> <span>Sub</span></pre>
<pre>&nbsp;</pre>
<pre>&lt;DllImport(<span>&quot;IWEARDRV.dll&quot;</span>, SetLastError := <span>True</span>, CharSet := CharSet.<span>Auto</span>)&gt; _</pre>
<pre><span>Private</span> <span>Shared</span> <span>Function</span> IWRGetTracking(&lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> yaw <span>As</span> <span>Integer</span>, &lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> pitch <span>As</span> <span>Integer</span>, &lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> roll <span>As</span> <span>Integer</span>) <span>As</span> <span>Integer</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>const</span> int ERROR_SUCCESS  = 0;</pre>
</div>
</div>
<p>These 3 methods will allows to open access to the glasses, set its zero position, and get the roll, pitch and yaw information from the sensors.</p>
<p>In the constructor for this object, we will open a handle to the glasses and startup a timer that will poll the glasses at a regular interval to get the sensor data as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> <span>const</span> int TimerPeriod = 1;</pre>
<pre><span>private</span> MainForm _mainForm;</pre>
<pre><span>private</span> Timer _timer;</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> VR920Tracker(MainForm mainForm)</pre>
<pre>{</pre>
<pre>    _mainForm = mainForm;</pre>
<pre>&nbsp;</pre>
<pre>    int openResult = IWROpenTracker();</pre>
<pre>    <span>if</span>(openResult != ERROR_SUCCESS)</pre>
<pre>        <span>throw</span> <span>new</span> ApplicationException(<span>&quot;Could not connect to VR920: &quot;</span> &#43; openResult);</pre>
<pre>&nbsp;</pre>
<pre>    _timer = <span>new</span> Timer(VR920Poller, null, Timeout.Infinite, TimerPeriod);</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> <span>Const</span> TimerPeriod <span>As</span> <span>Integer</span> = 1</pre>
<pre><span>Private</span> _mainForm <span>As</span> MainForm</pre>
<pre><span>Private</span> _timer <span>As</span> Timer</pre>
<pre>&nbsp;</pre>
<pre><span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> mainForm <span>As</span> MainForm)</pre>
<pre>    _mainForm = mainForm</pre>
<pre>&nbsp;</pre>
<pre>    <span>Dim</span> openResult <span>As</span> <span>Integer</span> = IWROpenTracker()</pre>
<pre>    <span>If</span> openResult &lt;&gt; ERROR_SUCCESS <span>Then</span></pre>
<pre>        <span>Throw</span> <span>New</span> ApplicationException(<span>&quot;Could not connect to VR920: &quot;</span> &amp; openResult)</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>    _timer = <span>New</span> Timer(<span>AddressOf</span> VR920Poller, <span>Nothing</span>, Timeout.Infinite, TimerPeriod)</pre>
<pre><span>End</span> <span>Sub</span></pre>
</div>
</div>
<p>The <strong>VR920Poller</strong> method referenced above will be called at a specific interval and read the values from the glasses as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>// collection of values <span>for</span> averaging</pre>
<pre><span>private</span> List&lt;<span>double</span>&gt; _yawValues = <span>new</span> List&lt;<span>double</span>&gt;();</pre>
<pre><span>private</span> List&lt;<span>double</span>&gt; _rollValues = <span>new</span> List&lt;<span>double</span>&gt;();</pre>
<pre><span>private</span> List&lt;<span>double</span>&gt; _pitchValues = <span>new</span> List&lt;<span>double</span>&gt;();</pre>
<pre>&nbsp;</pre>
<pre>// last calculated values</pre>
<pre><span>private</span> <span>double</span> _lastYaw;</pre>
<pre><span>private</span> <span>double</span> _lastPitch;</pre>
<pre><span>private</span> <span>double</span> _lastRoll;</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> void VR920Poller(<span>object</span> state)</pre>
<pre>{</pre>
<pre>    lock(this)</pre>
<pre>    {</pre>
<pre>        int yaw, pitch, roll;</pre>
<pre>&nbsp;</pre>
<pre>        int result = IWRGetTracking(out yaw, out pitch, out roll);</pre>
<pre>&nbsp;</pre>
<pre>        <span>if</span>(result != ERROR_SUCCESS)</pre>
<pre>            <span>throw</span> <span>new</span> ApplicationException(<span>&quot;Could not get VR920 tracking information: &quot;</span> &#43; result);</pre>
<pre>&nbsp;</pre>
<pre>        _yawValues.Add(VR920ToRadians(yaw));</pre>
<pre>        _rollValues.Add(VR920ToRadians(roll));</pre>
<pre>        _pitchValues.Add(VR920ToRadians(pitch));</pre>
<pre>&nbsp;</pre>
<pre>        <span>if</span>(_yawValues.Count == 5)</pre>
<pre>        {</pre>
<pre>            <span>double</span> y = Average(_yawValues, _lastYaw);</pre>
<pre>            <span>if</span>(Math.Abs(y - _lastYaw) &gt; 0.026)</pre>
<pre>                _lastYaw = y;</pre>
<pre>&nbsp;</pre>
<pre>            <span>double</span> p = Average(_pitchValues, _lastPitch);</pre>
<pre>            <span>if</span>(Math.Abs(p - _lastPitch) &gt; 0.017)</pre>
<pre>                _lastPitch = p;</pre>
<pre>&nbsp;</pre>
<pre>            _lastRoll = Average(_rollValues, _lastRoll);</pre>
<pre>&nbsp;</pre>
<pre>            _yawValues.Clear();</pre>
<pre>            _pitchValues.Clear();</pre>
<pre>            _rollValues.Clear();</pre>
<pre>&nbsp;</pre>
<pre>            RollPitchYaw rollPitchYaw = <span>new</span> RollPitchYaw(_lastRoll, _lastPitch, _lastYaw);</pre>
<pre>            _mainForm.SetRollPitchYaw(rollPitchYaw);</pre>
<pre>&nbsp;</pre>
<pre>            _mainForm.lblAxes.Text = VR920ToDegrees(yaw) &#43; <span>&quot;, &quot;</span> &#43; VR920ToDegrees(pitch) &#43; <span>&quot;, &quot;</span> &#43; VR920ToDegrees(roll);</pre>
<pre>        }</pre>
<pre>    }</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>double</span> Average(List&lt;<span>double</span>&gt; values, <span>double</span> last)</pre>
<pre>{</pre>
<pre>    <span>double</span> total = 0;</pre>
<pre>&nbsp;</pre>
<pre>    foreach(<span>double</span> value <span>in</span> values)</pre>
<pre>        total &#43;= value;</pre>
<pre>&nbsp;</pre>
<pre>    total &#43;= last;</pre>
<pre>&nbsp;</pre>
<pre>    <span>return</span> total / (values.Count&#43;1);</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>double</span> VR920ToRadians(int vr920Value)</pre>
<pre>{</pre>
<pre>    <span>return</span> (vr920Value * .00549) * (Math.PI/180);</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>double</span> VR920ToDegrees(int vr920Value)</pre>
<pre>{</pre>
<pre>    <span>return</span> (vr920Value * .00549);</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>' collection of values for averaging</span></pre>
<pre><span>Private</span> _yawValues <span>As</span> List(Of <span>Double</span>) = <span>New</span> List(Of <span>Double</span>)()</pre>
<pre><span>Private</span> _rollValues <span>As</span> List(Of <span>Double</span>) = <span>New</span> List(Of <span>Double</span>)()</pre>
<pre><span>Private</span> _pitchValues <span>As</span> List(Of <span>Double</span>) = <span>New</span> List(Of <span>Double</span>)()</pre>
<pre>&nbsp;</pre>
<pre><span>' last calculated values</span></pre>
<pre><span>Private</span> _lastYaw <span>As</span> <span>Double</span></pre>
<pre><span>Private</span> _lastPitch <span>As</span> <span>Double</span></pre>
<pre><span>Private</span> _lastRoll <span>As</span> <span>Double</span></pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> <span>Sub</span> VR920Poller(<span>ByVal</span> state <span>As</span> <span>Object</span>)</pre>
<pre>    <span>SyncLock</span> <span>Me</span></pre>
<pre>        <span>Dim</span> yaw, pitch, roll <span>As</span> <span>Integer</span></pre>
<pre>&nbsp;</pre>
<pre>        <span>Dim</span> result <span>As</span> <span>Integer</span> = IWRGetTracking(yaw, pitch, roll)</pre>
<pre>&nbsp;</pre>
<pre>        <span>If</span> result &lt;&gt; ERROR_SUCCESS <span>Then</span></pre>
<pre>            <span>Throw</span> <span>New</span> ApplicationException(<span>&quot;Could not get VR920 tracking information: &quot;</span> &amp; result)</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>        _yawValues.Add(VR920ToRadians(yaw))</pre>
<pre>        _rollValues.Add(VR920ToRadians(roll))</pre>
<pre>        _pitchValues.Add(VR920ToRadians(pitch))</pre>
<pre>&nbsp;</pre>
<pre>        <span>If</span> _yawValues.Count = 5 <span>Then</span></pre>
<pre>            <span>Dim</span> y <span>As</span> <span>Double</span> = Average(_yawValues, _lastYaw)</pre>
<pre>            <span>If</span> Math.Abs(y - _lastYaw) &gt; 0.026 <span>Then</span></pre>
<pre>                _lastYaw = y</pre>
<pre>            <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>            <span>Dim</span> p <span>As</span> <span>Double</span> = Average(_pitchValues, _lastPitch)</pre>
<pre>            <span>If</span> Math.Abs(p - _lastPitch) &gt; 0.017 <span>Then</span></pre>
<pre>                _lastPitch = p</pre>
<pre>            <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>            _lastRoll = Average(_rollValues, _lastRoll)</pre>
<pre>&nbsp;</pre>
<pre>            _yawValues.Clear()</pre>
<pre>            _pitchValues.Clear()</pre>
<pre>            _rollValues.Clear()</pre>
<pre>&nbsp;</pre>
<pre>            <span>Dim</span> rollPitchYaw <span>As</span> <span>New</span> RollPitchYaw(_lastRoll, _lastPitch, _lastYaw)</pre>
<pre>            _mainForm.SetRollPitchYaw(rollPitchYaw)</pre>
<pre>&nbsp;</pre>
<pre>            _mainForm.lblAxes.Text = VR920ToDegrees(yaw) &amp; <span>&quot;, &quot;</span> &amp; VR920ToDegrees(pitch) &amp; <span>&quot;, &quot;</span> &amp; VR920ToDegrees(roll)</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>    <span>End</span> <span>SyncLock</span></pre>
<pre><span>End</span> <span>Sub</span></pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> <span>Function</span> Average(<span>ByVal</span> values <span>As</span> List(Of <span>Double</span>), <span>ByVal</span> last <span>As</span> <span>Double</span>) <span>As</span> <span>Double</span></pre>
<pre>    <span>Dim</span> total <span>As</span> <span>Double</span> = 0</pre>
<pre>&nbsp;</pre>
<pre>    <span>For</span> <span>Each</span> value <span>As</span> <span>Double</span> <span>In</span> values</pre>
<pre>        total &#43;= value</pre>
<pre>    <span>Next</span> value</pre>
<pre>&nbsp;</pre>
<pre>    total &#43;= last</pre>
<pre>&nbsp;</pre>
<pre>    <span>Return</span> total / (values.Count&#43;1)</pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> <span>Function</span> VR920ToRadians(<span>ByVal</span> vr920Value <span>As</span> <span>Integer</span>) <span>As</span> <span>Double</span></pre>
<pre>    <span>Return</span> (vr920Value *.00549) * (Math.PI/180)</pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> <span>Function</span> VR920ToDegrees(<span>ByVal</span> vr920Value <span>As</span> <span>Integer</span>) <span>As</span> <span>Double</span></pre>
<pre>    <span>Return</span> (vr920Value *.00549)</pre>
<pre><span>End</span> Function</pre>
</div>
</div>
<p>This chunk calls the <strong>IWRGetTracking</strong> method and tosses the results in 3 lists for roll, pitch and yaw.&nbsp; then, when the list has 5 members in it, the values are averaged and, if that resulting values is past a certain threshold, the values
 are passed back to the <strong>MainForm</strong>'s <strong>SetRollPitchYaw</strong> method as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> <span>double</span> _lastYaw;</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> <span>void</span> SetRollPitchYaw(RollPitchYaw rollPitchYaw)</pre>
<pre>{</pre>
<pre>    <span>if</span>(!_initialized || _globeControl.IsDisposed || (_globeControl.Host) == <span>null</span> || _globeControl.Host.CameraControllers.Current == <span>null</span>)</pre>
<pre>        <span>return</span>;</pre>
<pre>&nbsp;</pre>
<pre>    <span>double</span> y = ((_globeControl.Host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.LocalOrientation.Yaw - _lastYaw) &#43; rollPitchYaw.Yaw;</pre>
<pre>&nbsp;</pre>
<pre>    RollPitchYaw rpw = <span>new</span> RollPitchYaw(rollPitchYaw.Roll, rollPitchYaw.Pitch, y);</pre>
<pre>    (_globeControl.Host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.LocalOrientation.RollPitchYaw = rpw;</pre>
<pre>&nbsp;</pre>
<pre>    _lastYaw = rollPitchYaw.Yaw;</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> _lastYaw <span>As</span> <span>Double</span></pre>
<pre>&nbsp;</pre>
<pre><span>Public</span> <span>Sub</span> SetRollPitchYaw(<span>ByVal</span> rollPitchYaw <span>As</span> RollPitchYaw)</pre>
<pre>    <span>If</span> (<span>Not</span> _initialized) <span>OrElse</span> _globeControl.IsDisposed <span>OrElse</span> (_globeControl.Host) <span>Is</span> <span>Nothing</span> <span>OrElse</span> _globeControl.Host.CameraControllers.Current <span>Is</span> <span>Nothing</span> <span>Then</span></pre>
<pre>        <span>Return</span></pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>    <span>Dim</span> y <span>As</span> <span>Double</span> = ((<span>TryCast</span>(_globeControl.Host.CameraControllers.Current, ActionCameraController)).LastReportedViewpoint.LocalOrientation.Yaw - _lastYaw) &#43; rollPitchYaw.Yaw</pre>
<pre>&nbsp;</pre>
<pre>    <span>Dim</span> rpw <span>As</span> <span>New</span> RollPitchYaw(rollPitchYaw.Roll, rollPitchYaw.Pitch, y)</pre>
<pre>    <span>TryCast</span>(_globeControl.Host.CameraControllers.Current, ActionCameraController).LastReportedViewpoint.LocalOrientation.RollPitchYaw = rpw</pre>
<pre>&nbsp;</pre>
<pre>    _lastYaw = rollPitchYaw.Yaw</pre>
<pre><span>End</span> <span>Sub</span></pre>
</div>
</div>
<p>This method takes the roll, pitch and yaw values provided and applies them to the current
<strong>CameraController</strong> used by VE3D (which, by default, is an <strong>
ActionCameraController</strong>).</p>
<p>So, this code ultimately takes the roll, yaw and pitch of the user's head and translates that directly to the roll, yaw and pitch of the camera in VE3D providing an accurate, real-time view into the VE3D world.</p>
<h3></h3>
<h1></h1>
<h3>Stereoscopic Images</h3>
<p>The final piece of the puzzle is drawing frames to the VR920 glasses in such a way that the final view to the user will be three dimensional.&nbsp; This works similarly to those
<a href="http://www.magiceye.com/3dfun/stwkdisp.shtml" target="_blank">Magic Eye puzzles</a> you may have seen.&nbsp; Essentially, for every frame, we want to take the current VE3D camera position and move it several units to the left, render that to the left eye
 of the glasses, and then move the camera several units to the right and render that to the right eye of the glasses.&nbsp; To handle this we,&nbsp; can create an object named
<strong>VR920StereoStep</strong> which derives from the <strong>Step</strong> class provided by VE3D and add this to the
<strong>StepManager</strong>.&nbsp; When this is done, the <strong>VR920StereoStep</strong> will be called at the end of every frame drawn by VE3D.</p>
<p>As with the <strong>VR920Tracker</strong> class, we will need to setup a few P/Invoke method signatures to talk to the stereo driver as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>[DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint = <span>&quot;IWRSTEREO_Open&quot;</span>, SetLastError=<span>true</span>)]</pre>
<pre><span>public</span> <span>static</span> <span>extern</span> IntPtr OpenStereo();</pre>
<pre>&nbsp;</pre>
<pre>[DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint = <span>&quot;IWRSTEREO_SetStereo&quot;</span>)]</pre>
<pre><span>public</span> <span>static</span> <span>extern</span> Boolean SetStereoEnabled(IntPtr handle, Boolean enabled);</pre>
<pre>&nbsp;</pre>
<pre>[DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint = <span>&quot;IWRSTEREO_SetLR&quot;</span>)]</pre>
<pre><span>public</span> <span>static</span> <span>extern</span> Boolean SetStereoLR(IntPtr handle, Boolean eye);</pre>
<pre>&nbsp;</pre>
<pre>[DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint = <span>&quot;IWRSTEREO_WaitForAck&quot;</span>)]</pre>
<pre><span>public</span> <span>static</span> <span>extern</span> Byte WaitForOpenFrame(IntPtr handle, Boolean eye);</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre>&lt;DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint := <span>&quot;IWRSTEREO_Open&quot;</span>, SetLastError:=<span>True</span>)&gt; _</pre>
<pre><span>Public</span> <span>Shared</span> <span>Function</span> OpenStereo() <span>As</span> IntPtr</pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre>&lt;DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint := <span>&quot;IWRSTEREO_SetLR&quot;</span>)&gt; _</pre>
<pre><span>Public</span> <span>Shared</span> <span>Function</span> SetStereoLR(<span>ByVal</span> handle <span>As</span> IntPtr, <span>ByVal</span> eye <span>As</span> <span>Boolean</span>) <span>As</span> <span>Boolean</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre>&lt;DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint := <span>&quot;IWRSTEREO_SetStereo&quot;</span>)&gt; _</pre>
<pre><span>Public</span> <span>Shared</span> <span>Function</span> SetStereoEnabled(<span>ByVal</span> handle <span>As</span> IntPtr, <span>ByVal</span> enabled <span>As</span> <span>Boolean</span>) <span>As</span> <span>Boolean</span></pre>
<pre><span>End</span> <span>Function</span></pre>
<pre>&nbsp;</pre>
<pre>&lt;DllImport(<span>&quot;iWrstDrv.dll&quot;</span>, EntryPoint := <span>&quot;IWRSTEREO_WaitForAck&quot;</span>)&gt; _</pre>
<pre><span>Public</span> <span>Shared</span> <span>Function</span> WaitForOpenFrame(<span>ByVal</span> handle <span>As</span> IntPtr, <span>ByVal</span> eye <span>As</span> <span>Boolean</span>) <span>As</span> <span>Byte</span></pre>
<pre><span>End</span> <span>Function</span></pre>
</div>
</div>
<p>In the constructor for this object, we will open a handle to the stereo driver and turn on the stereo functionality of the glasses as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> <span>static</span> <span>readonly</span> IntPtr INVALID_FILE_HANDLE = (IntPtr)(-1);</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> IntPtr _hStereo = INVALID_FILE_HANDLE;</pre>
<pre><span>private</span> Host _host;</pre>
<pre><span>private</span> bool _stereoEnabled = <span>true</span>;</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> <span>double</span> EyeDistance { <span>get</span>; <span>set</span>; }</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> VR920StereoStep(StepManager manager, Host host) : base(manager)</pre>
<pre>{</pre>
<pre>    EyeDistance = 10;</pre>
<pre>    _host = host;</pre>
<pre>&nbsp;</pre>
<pre>    _hStereo = OpenStereo();</pre>
<pre>    <span>if</span>(_hStereo != INVALID_FILE_HANDLE)</pre>
<pre>        SetStereoEnabled(_hStereo, <span>true</span>);</pre>
<pre>    <span>else</span></pre>
<pre>        _stereoEnabled = <span>false</span>;</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> <span>Shared</span> <span>ReadOnly</span> INVALID_FILE_HANDLE <span>As</span> IntPtr = <span>CType</span>(-1, IntPtr)</pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> _hStereo <span>As</span> IntPtr = INVALID_FILE_HANDLE</pre>
<pre><span>Private</span> _host <span>As</span> Host</pre>
<pre><span>Private</span> _stereoEnabled <span>As</span> <span>Boolean</span> = <span>True</span></pre>
<pre>&nbsp;</pre>
<pre><span>Private</span> privateEyeDistance <span>As</span> <span>Double</span></pre>
<pre><span>Public</span> <span>Property</span> EyeDistance() <span>As</span> <span>Double</span></pre>
<pre>    <span>Get</span></pre>
<pre>        <span>Return</span> privateEyeDistance</pre>
<pre>    <span>End</span> <span>Get</span></pre>
<pre>    <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre>        privateEyeDistance = value</pre>
<pre>    <span>End</span> <span>Set</span></pre>
<pre><span>End</span> <span>Property</span></pre>
<pre>&nbsp;</pre>
<pre><span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> manager <span>As</span> StepManager, <span>ByVal</span> host <span>As</span> Host)</pre>
<pre>    <span>MyBase</span>.<span>New</span>(manager)</pre>
<pre>    EyeDistance = 10</pre>
<pre>    _host = host</pre>
<pre>&nbsp;</pre>
<pre>    _hStereo = OpenStereo()</pre>
<pre>    <span>If</span> _hStereo &lt;&gt; INVALID_FILE_HANDLE <span>Then</span></pre>
<pre>        SetStereoEnabled(_hStereo, <span>True</span>)</pre>
<pre>    <span>Else</span></pre>
<pre>        _stereoEnabled = <span>False</span></pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>End</span> Sub</pre>
</div>
</div>
<p>Next, we need to override the <strong>OnExecute</strong> method provided by the base
<strong>Step </strong>class as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> <span>bool</span> _rightEye = <span>true</span>;</pre>
<pre><span>private</span> Vector3D _position;</pre>
<pre>&nbsp;</pre>
<pre><span>public</span> <span>override</span> <span>void</span> OnExecute(SceneState state)</pre>
<pre>{</pre>
<pre>    <span>if</span>(_hStereo != INVALID_FILE_HANDLE &amp;&amp; _stereoEnabled &amp;&amp; (_host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint != <span>null</span>)</pre>
<pre>    {</pre>
<pre>        <span>if</span>(!_rightEye)</pre>
<pre>        {</pre>
<pre>            _position = (_host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.Position.Vector;</pre>
<pre>            (_host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.Position.Vector = _position &#43; <span>new</span> Vector3D(-EyeDistance, 0, 0);</pre>
<pre>        }</pre>
<pre>        <span>else</span></pre>
<pre>        {</pre>
<pre>            _position = (_host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.Position.Vector;</pre>
<pre>            (_host.CameraControllers.Current <span>as</span> ActionCameraController).LastReportedViewpoint.Position.Vector = _position &#43; <span>new</span> Vector3D(EyeDistance, 0, 0);;</pre>
<pre>        }</pre>
<pre>&nbsp;</pre>
<pre>        SetStereoLR(_hStereo, _rightEye);</pre>
<pre>        WaitForOpenFrame(_hStereo, _rightEye);</pre>
<pre>        _rightEye = !_rightEye;</pre>
<pre>    }</pre>
<pre>}</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> _rightEye <span>As</span> <span>Boolean</span> = <span>True</span></pre>
<pre><span>Private</span> _position <span>As</span> Vector3D</pre>
<pre>&nbsp;</pre>
<pre><span>Public</span> <span>Overrides</span> <span>Sub</span> OnExecute(<span>ByVal</span> state <span>As</span> SceneState)</pre>
<pre>    <span>If</span> _hStereo &lt;&gt; INVALID_FILE_HANDLE <span>AndAlso</span> _stereoEnabled <span>AndAlso</span> (<span>TryCast</span>(_host.CameraControllers.Current, ActionCameraController)).LastReportedViewpoint IsNot <span>Nothing</span> <span>Then</span></pre>
<pre>        <span>If</span> (<span>Not</span> _rightEye) <span>Then</span></pre>
<pre>            _position = (<span>TryCast</span>(_host.CameraControllers.Current, ActionCameraController)).LastReportedViewpoint.Position.Vector</pre>
<pre>            <span>TryCast</span>(_host.CameraControllers.Current, ActionCameraController).LastReportedViewpoint.Position.Vector = _position &#43; <span>New</span> Vector3D(-EyeDistance, 0, 0)</pre>
<pre>        <span>Else</span></pre>
<pre>            _position = (<span>TryCast</span>(_host.CameraControllers.Current, ActionCameraController)).LastReportedViewpoint.Position.Vector</pre>
<pre>            <span>TryCast</span>(_host.CameraControllers.Current, ActionCameraController).LastReportedViewpoint.Position.Vector = _position &#43; <span>New</span> Vector3D(EyeDistance, 0, 0)</pre>
<pre>&nbsp;</pre>
<pre>        <span>End</span> <span>If</span></pre>
<pre>&nbsp;</pre>
<pre>        SetStereoLR(_hStereo, _rightEye)</pre>
<pre>        WaitForOpenFrame(_hStereo, _rightEye)</pre>
<pre>        _rightEye = <span>Not</span> _rightEye</pre>
<pre>    <span>End</span> <span>If</span></pre>
<pre><span>End</span> Sub</pre>
</div>
</div>
<p><strong>OnExecute</strong> will be called at the end of each VE3D frame rendered.&nbsp; In this method, we obtain the current position of the VE3D camera and then set its position several units to the left or right (- or &#43;
<strong>EyeDistance</strong>).&nbsp; <strong>SetStereoLR</strong> from the VR920 API is called, setting the appropriate eye to be active (left = false, right = true).&nbsp; Then
<strong>WaitForOpenFrame</strong> is called which will pause the action long enough for the glasses to draw the entire frame to eye to avoid image tearing.&nbsp; Essentially, this call “sits and spins” at this location until the glasses report back that the entire
 frame is drawn in the proper eye and that we can continue on drawing the opposite eye for the next frame.&nbsp; Finally, the
<strong>_rightEye</strong> member variable is togged to the opposite value, so the next time through this method the opposite eye is drawn.</p>
<p>With this class in place, back in our <strong>MainForm</strong> in the <strong>
FirstFrameRendered</strong> event handler, we can instantiate the object and add it to the
<strong>StepManager</strong> as shown below:</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>private</span> VR920StereoStep _vr920StereoStep;</pre>
<pre>&nbsp;</pre>
<pre>_vr920StereoStep = <span>new</span> VR920StereoStep(_globeControl.Host.RenderEngine.StepManager, _globeControl.Host);</pre>
<pre>_globeControl.Host.RenderEngine.StepManager.Add(_vr920StereoStep);</pre>
</div>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<div id="codeSnippet">
<pre><span>Private</span> _vr920StereoStep <span>As</span> VR920StereoStep</pre>
<pre>&nbsp;</pre>
<pre>_vr920StereoStep = <span>New</span> VR920StereoStep(_globeControl.Host.RenderEngine.StepManager, _globeControl.Host)</pre>
<pre>_globeControl.Host.RenderEngine.StepManager.Add(_vr920StereoStep)</pre>
</div>
</div>
<p>&nbsp;</p>
<h3><b>Running the Application</b></h3>
<p>To run the demo, do the following:</p>
<ol>
<li>Copy <b>BindingsWiimote.xml</b> to the appropriate directory listed above </li><li>Pair the Wiimote and Balance Board to the computer.&nbsp; See the <a href="http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx" target="_blank">
WiimoteLib article</a> for more information on how to do that </li><li>Run the executable </li><li>Stand on the Balance Board </li><li>Put on the glasses </li><li>Zero both the Balance Board and glasses </li><li>Toggle everything on or off at will </li></ol>
<p><strong>Controls</strong></p>
<ul>
<li>F1 – Set VR920 glasses to zero position </li><li>F2 – Set Balance Board to zero position </li><li>F3 – Toggle stereo mode on and off </li><li>Wiimote 1 or B – Toggle Balance Board on or off </li><li>Wiimote 2 or V – Toggle VR920 head tracking on or off </li><li>F – Toggle full-screen on or off </li><li>Nunchuk joystick X/Y – Strafe/Move </li><li>Nunchuk C/Z buttons – Raise/lower altitude </li><li>Wiimote A – Open location menu/Select location (note that if a new location is selected, the Balance Board is turned off and must be re-enabled after “landing”
</li><li>Wiimote Dpad Up/Down – Move through List </li><li>Balance Board – Lean your body left or right to turn in the VE3D environment </li></ul>
<h3><b>Conclusion</b></h3>
<p>With the above code, we have created a very interesting interface for Virtual Earth 3D.&nbsp; The demo and source code linked above contain a few more features and bindings which enhance the application a bit more.&nbsp; Be sure to give the full demo a try and check
 out the full source code for a few more implementation details.</p>
<h3></h3>
<h3>Additional Information</h3>
<ul>
<li><a href="http://www.vr920.com/" target="_blank">Vuzix VR920 Glasses</a> </li><li><a href="http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx" target="_blank">Managed Library for Nintendo's Wiimote</a>
</li><li><a href="http://heptazane.spaces.live.com/default.aspx" target="_blank">Heptazane's Blog</a>
</li><li><a href="http://virtualearth.spaces.live.com/" target="_blank">Virtual Earth Blog</a>
</li><li><a href="http://blogs.msdn.com/virtualearth/" target="_blank">Virtual Earth Developer's Blog</a>
</li></ul>
<h3>Bio</h3>
<p>Brian is a <a href="https://mvp.support.microsoft.com/profile/Brian.Peek">Microsoft C# MVP</a> who has been actively developing in .NET since its early betas in 2000, and who has been developing solutions using Microsoft technologies and platforms for even
 longer. Along with .NET, Brian is particularly skilled in the languages of C, C&#43;&#43; and assembly language for a variety of CPUs. He is also well-versed in a wide variety of technologies including web development, document imaging, GIS, graphics, game development,
 and hardware interfacing. Brian has a strong background in developing applications for the health-care industry, as well as developing solutions for portable devices, such as tablet PCs and PDAs. Additionally, Brian has co-authored the book &quot;<a href="http://www.amazon.com/dp/0735711410/">Debugging
 ASP.NET</a>&quot; published by New Riders, and is currently co-authoring a book titled &quot;<a href="http://www.amazon.com/exec/obidos/ASIN/0596520743/brianpcom-20">Coding4Fun: 10 .NET Programming Projects for Wiimote, YouTube, World of Warcraft, and More</a>&quot; to be
 published by <a href="http://www.oreilly.com/">O'Reilly</a> in December 2008. Brian is also an author for MSDN's
<a href="http://blogs.msdn.com/coding4fun/">Coding4Fun</a> website.&nbsp; You can reach Brian via vis website at
<a href="http://www.brianpeek.com/">http://www.brianpeek.com/</a> .</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:b6e01f70d39f46a58b729e7600cdc83f">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/WiiEarthVR--A-Fully-Immersive-3D-Experience-with-Virtual-Earth-3D</comments>
      <itunes:summary>





In this article, Brian Peek will demonstrate how to use a Nintendo Wii Remote (Wiimote), a Wii Fit Balance Board, and Vuzix VR920 glasses as input devices for Microsoft Virtual Earth 3D, providing a fully immersive, 3D experience.



Brian Peek
ASPSOFT, Inc.

Difficulty: Intermediate
Time Required: 2-3 hours
Cost: $60 for Wiimote and Nunchuk, $90 for Wii Fit (which includes Balance Board), $400 for
Vuzix VR920 glasses
Software: Managed Library for Nintendo&#39;s Wiimote,
Visual Basic or Visual C# Express Editions
Hardware: Nintendo Wii Remote (Wiimote) with Nunchuk,

Wii Fit Balance Board, 
Vuzix VR920 glasses, a compatible PC Bluetooth adapter and stack
Download: Download
Discussion Forum: Forum




&amp;nbsp; 
Introduction
Virtual Earth is the 3D interface to 
Microsoft&#39;s Live Maps service.&amp;nbsp; Normally this control is loaded via the web browser and allows interaction with a keyboard, mouse, and Xbox 360 controller.&amp;nbsp; In this article, we will take the Virtual Earth 3D control out of the web browser, use it in a WinForms
 application, and control it with a Nintendo Wii Remote (Wiimote) and a pair of Vuzix VR920 glasses, while also providing a stereoscopic 3D image to the glasses, creating the illusion of a fully three dimensional environment.&amp;nbsp; Note that use of the Virtual Earth
 3D control in this way is undocumented and unsupported at the moment.&amp;nbsp; Because of this, some of the descriptions in this article are educated guesses and may not be 100% accurate… 
Originally, this project started as a simple Wiimote interface to Virtual Earth 3D as shown in the video below.&amp;nbsp; Since I wrote that application, I learned of the VR920 glasses and the Wii Fit Balance Board was released, so I&#39;ve decided to create a more immersive
 experience using all of these controls which was demonstrated at 
PDC2008, shown here: 
       Setup
Before we get started, you will need to install the Virtual Earth 3D control.&amp;nbsp; If you haven&#39;t done this already, browse to
http:/</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/WiiEarthVR--A-Fully-Immersive-3D-Experience-with-Virtual-Earth-3D</link>
      <pubDate>Fri, 14 Nov 2008 05:57:58 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/WiiEarthVR--A-Fully-Immersive-3D-Experience-with-Virtual-Earth-3D</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9068804_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9068804_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/WiiEarthVR--A-Fully-Immersive-3D-Experience-with-Virtual-Earth-3D/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Windows</category>
      <category>Mash Up</category>
      <category>hardwarehacks</category>
      <category>hardware miscellaneous</category>
    </item>
  <item>
      <title>Control Windows Media Center using a Windows Mobile 5 Device</title>
      <description><![CDATA[
<p>This article demonstrates how to use a smartphone running Windows Mobile 5 to remotely control a host machine running Windows Media Center. I will describe how to create an add-in application that runs within Windows Media Center, and how to create a Windows
 Mobile 5 application that you can use to communicate with the Media Center over a wireless internet connection. Finally, I will demonstrate how to use this implementation to manipulate Media Center using the Windows Media Center API.
</p>
<p><a href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx">Matt Ivers</a>
</p>
<p><b>Difficulty: </b>Intermediate </p>
<p><b>Time Required:</b> 6-10 hours</p>
<p><b>Cost: </b>$100-$200 </p>
<p><b>Software: </b><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;DisplayLang=en">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;displaylang=en">
Windows Media Center SDK 5.0</a>, <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;DisplayLang=en">
Windows Mobile 5.0 Smartphone SDK</a> </p>
<p><b>Hardware: </b>Mobile device running Windows Mobile 5.0 </p>
<p><b>Download: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/WMC_Remote_Code.zip">C# and VB.Net</a></p>
<ul>
</ul>
<h3>Introduction</h3>
Starting with Windows Media Center Edition 2005, Media Center added extensibility support through hosted add-in assemblies. By implementing an add-in interface and registering the assembly with Media Center, the add-in assembly is given access to the Microsoft.MediaCenter.Hosting.AddInHost
 object. Using this object model, an add-in assembly can programmatically inspect and manipulate various aspects of Windows Media Center. In addition to the exposed Media Center namespaces, the add-in has complete access to all the capabilities of the .NET
 Framework.
<p>&nbsp;</p>
<p>By combining the power of a Media Center add-in with a mobile device running Windows Mobile 5.0, we can extend the capabilities of a Media Center add-in even further. The add-in service I developed runs as a listener service within Windows Media Center on
 the host machine. It is initialized when Windows Media Center is started, runs invisibly in the background, and allows mobile devices to connect and submit requests to it. The mobile solution leverages an existing WiFi internet connection to communicate with
 the add-in via TCP socket connections. The mobile device runs a .NET Compact Framework 2.0 forms application designed for devices running Windows Mobile 5 or higher.</p>
<p>The included remote control application is capable of the following functionality:
</p>
<ul>
<li>Retrieve metadata about currently loaded media </li><li>Affect playback of currently loaded media – Play, Pause, Stop, Next Track, Previous Track
</li><li>Control Media Center volume </li><li>Retrieve a list of available media – Photos, Audio, Video </li><li>Explicitly load media for playback – Audio, Video </li></ul>
<h3>Creating a Windows Media Center add-in application</h3>
The first step in our implementation is creating an add-in that will run within Windows Media Center. This involves creating a new Windows Media Center Presentation Layer Application project, implementing an interface, signing the assembly, and creating a setup
 project to install the assembly and register it with Media center.
<p>&nbsp;</p>
<h4>Creating a new project – Windows Media Center Presentation Layer Application</h4>
Installing the Windows Media Center SDK makes this step simple. Once installed, you create this project like any other in Visual Studio:
<p><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/1_Create_new_WMC_presentation_layer_.jpg" width="500" height="351">&nbsp;</p>
<p><em>Figure 1 - Creating the project</em></p>
<p>Using the Windows Media Center Presentation Layer Application project template yields the following project skeleton:</p>
<p><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/2_AddIn_demo_project3.jpg" width="209" height="240">
</p>
<p><em>Figure&nbsp;2 - Solution Explorer for our new project</em></p>
<p>There are two files of interest here: AddIn.vb and App.xml. AddIn.vb contains our add-in class. Interface methods implemented in this class will be invoked by Windows Media Center when our add-in is launched. App.xml contains configuration information identifying
 our assemblies and add-in attributes. The setup project will use this XML to register our add-in with Windows Media Center during installation.
</p>
<h4>The AddIn class</h4>
Media Center add-in applications must implement two interfaces in order for Media Center to invoke them: Microsoft.MediaCenter.Hosting.IAddInEntryPoint, and Microsoft.MediaCenter.Hosting.IAddInModule. By using the project template, our add-in class already
 implements both (AddIn.vb):
<h5><span class="kwrd"><strong>Visual Basic</strong></span> .NET</h5>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Class1
    <span class="kwrd">Implements</span> IAddInModule
    <span class="kwrd">Implements</span> IAddInEntryPoint

    <span class="rem">' Initialize (IAddInModule)</span>
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Initialize(<span class="kwrd">ByVal</span> appInfo <span class="kwrd">As</span> Dictionary(Of <span class="kwrd">String</span>, <span class="kwrd">Object</span>), <span class="kwrd">ByVal</span> entryPointInfo <span class="kwrd">As</span> Dictionary(Of <span class="kwrd">String</span>, <span class="kwrd">Object</span>)) <span class="kwrd">Implements</span> IAddInModule.Initialize
        <span class="rem">' Initialization logic goes here</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="rem">' Uninitialize (IAddInModule)</span>
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Uninitialize() <span class="kwrd">Implements</span> IAddInModule.Uninitialize
        <span class="rem">' Clean-up logic goes here</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="rem">' Launch (IAddInEntryPoint)</span>
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Launch(<span class="kwrd">ByVal</span> host <span class="kwrd">As</span> AddInHost) <span class="kwrd">Implements</span> IAddInEntryPoint.Launch
        <span class="rem">' This is where normal execution begins</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Class1 : IAddInModule, IAddInEntryPoint 
{
    <span class="rem">//  Initialize (IAddInModule)</span>
    <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize(Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">object</span>&gt; appInfo, Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">object</span>&gt; entryPointInfo)
    {
        <span class="rem">//  Initialization logic goes here</span>
    }    
    <span class="rem">//  Uninitialize (IAddInModule)</span>
    <span class="kwrd">public</span> <span class="kwrd">void</span> Uninitialize() 
    {
        <span class="rem">//  Clean-up logic goes here</span>
    }    
    <span class="rem">//  Launch (IAddInEntryPoint)</span>
    <span class="kwrd">public</span> <span class="kwrd">void</span> Launch(AddInHost host) 
    {
        <span class="rem">//  This is where normal execution begins</span>
    }
}
</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The IAddInModule.Initialize and IAddInModule.Uninitialize interface methods are used by Media Center to signal the beginning and end of the add-in application's lifetime. Use Initialize to create any internal objects your application may require, and the
 Uninitialize to perform any clean-up. Keep in mind that since the add-in application runs within Media Center, it may decide to close your add-in application before it has a chance to exit on its own. In any case, Media Center will call the Uninitialize method
 and give the add-in a window of execution to exit as gracefully as possible. </p>
<p>The IAddInEntryPoint.Launch method is where normal execution code should begin. Media Center will pass an AddInHost object as an input parameter. Through this object, your add-in application can access all the features of the Media Center API.
</p>
<h4>Signing the assembly</h4>
Windows Media Center requires that all add-in assemblies be strongly-named. This requires that the assembly be signed using a key file. Thanks to Visual Studio 2005, signing an assembly is a straightforward process. From your add-in project's “Properties” menu,
 you can browse to the “Signing” tab to create a new strong name key file for the project:
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/3_Sign_an_assembly4.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/3_Sign_an_assembly_thumb2.jpg" width="500" height="327"></a>
</p>
<p><em>Figure 3 -&nbsp;Signing our assembly</em></p>
<p>Explicit instruction is also available here:<br>
<a href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx">How to: Sign an Assembly (Visual Studio)</a></p>
<h4>Tweaking the App.xml file</h4>
Media Center requires every add-in application to explicitly define a point of entry by which the application is to be launched. The App.xml file contains this configuration information. The Media Center project template used earlier generates the following
 sample:
<p>&nbsp;</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">application</span> <span class="attr">title</span><span class="kwrd">=&quot;DemoProject&quot;</span> <span class="attr">id</span><span class="kwrd">=&quot;{f6dd1141-f288-46fe-bcdb-2d9c5ffd986e}&quot;</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">entrypoint</span> <span class="attr">id</span><span class="kwrd">=&quot;{31a15ce9-0487-43bc-94de-a43409129641}&quot;</span> 
              <span class="attr">addin</span><span class="kwrd">=&quot;DemoProject.Class1, DemoProject,Culture=Neutral,Version=6.0.6000.0&quot;</span>
              <span class="attr">title</span><span class="kwrd">=&quot;DemoProject&quot;</span>
              <span class="attr">description</span><span class="kwrd">=&quot;DemoProject&quot;</span>
              <span class="attr">ImageUrl</span><span class="kwrd">=&quot;.\AppIcon.png&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">category</span> <span class="attr">category</span><span class="kwrd">=&quot;More Programs&quot;</span><span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">entrypoint</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">application</span><span class="kwrd">&gt;</span>
</pre>
<p>The XML definition specifies the add-in applications and their points of entry within Media Center. Add-in applications can be launched on demand from various locations within Media Center, such as from an icon in the “More Programs” group. A full listing
 of all the available points of entry can be found here. Add-in applications can also be launched in the background when Media Center starts. To indicate this, we specify “Background” in the “category” attribute. The “addin” attribute must also be modified
 to point to our add-in class in the format “Assemblyname.ClassName”. The “title”, “description”, and “ImageUrl” attributes are used primarily for on-demand add-ins.
</p>
<p>After making our changes, the Windows Media Center Remote application XML looks like this:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">application</span> <span class="attr">title</span><span class="kwrd">=&quot;WMCServerAddIn&quot;</span> <span class="attr">id</span><span class="kwrd">=&quot;{7b71a7ca-b459-4023-ab12-d5cc8c56b991}&quot;</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">entrypoint</span> <span class="attr">id</span><span class="kwrd">=&quot;{5fe9982b-ca4a-459e-b62c-40399e875d66}&quot;</span> 
              <span class="attr">addin</span><span class="kwrd">=&quot;WMCServerAddIn.ServerAddIn, WMCServerAddIn,Culture=Neutral,Version=6.0.6000.0&quot;</span>
              <span class="attr">title</span><span class="kwrd">=&quot;WMCServerAddIn&quot;</span>
              <span class="attr">description</span><span class="kwrd">=&quot;WMCServerAddIn&quot;</span>
              <span class="attr">ImageUrl</span><span class="kwrd">=&quot;.\AppIcon.png&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">category</span> <span class="attr">category</span><span class="kwrd">=&quot;Background&quot;</span><span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">entrypoint</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">application</span><span class="kwrd">&gt;</span></pre>
<h4>Creating the setup project</h4>
<p>With a basic interface implementation complete and a configuration XML created, we are ready to create the setup project. The setup project will install our assemblies into the Global Assembly Cache and register our XML-defined entry point with Media Center.
 A full step-by-step walkthrough can be found here:</p>
<p><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp">Creating a Windows Installer File for a Windows Media Center Add-in</a></p>
<p>Once the setup project is complete, it's time for a test. By using the Host.MediaCenterEnvironment.Dialog class off of the AddInHost object, we can present a dialog box to the user to ensure the add-in launches successfully. After compiling the solution,
 run the installer by right-clicking the setup project and choosing “Install”. Once installation has completed, run Windows Media Center. A few seconds after startup, the add-in is launched:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/4_Hello_world_demo_addin3.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/4_Hello_world_demo_addin_thumb1.jpg" width="500" height="374"></a>
</p>
<p><em>Figure 4 - Running our Hello World Media Center Add-in</em></p>
<h3>Creating a Windows Mobile 5.0 client application</h3>
The second step in our implementation is creating a .NET Compact Framework 2.0 forms application. This is a mobile application that will run on a mobile device running Windows Mobile 5 or higher.
<h4>Creating a new project – Windows Mobile CE 5.0 application</h4>
<p>Installing the Windows Mobile Smartphone SDK 5.0 makes this step simple. Once the SDK is installed, you can create a project in Visual Studio using the Windows CE 5.0 Project template.
</p>
<p>The only other typical setup required for developing mobile apps is to change the deployment settings to point to your WM5 device. This can be configured within the Visual Studio toolbar:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/6_Deploying_to_mobile3.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/6_Deploying_to_mobile_thumb1.jpg" width="345" height="201"></a>
</p>
<p><em>Figure&nbsp;5 - changing the deployment settings to target the mobile device</em></p>
<h3>Implementing the Media Center Add-in service</h3>
With a test harness in place at both ends of the implementation, it was time to get to the real code. To facilitate the control of Media Center through the hosted add-in, the service requires a few key components. These include choosing a server / client conversation
 protocol, creating a multithreaded socket server, implementing object serialization, and implementing the programmatic manipulation of Media Center.
<h4>Implementing the socket server</h4>
<p>The socket server uses the Socket object from the System.Networking.Sockets namespace for all of its communications. The listener service begins by binding to the host machine's local address and listening on a port of your choosing. Once the socket is instantiated
 and bound to a local port, it begins listening for and accepting inbound connections. When a new connection is established, a target method BeginSocketConversation will be invoked on a new thread, where the actual communication between the two parties will
 take place. Once the new thread has been invoked, execution will continue in the AcceptConnections method. At this time the newly launched thread notifies the listener to begin accepting new connections again. A ManualResetEvent from the System.Threading namespace
 can be used to communicate changes in state between two or more threads. Here is the code implementation of the socket listener:
</p>
<h5><span class="kwrd">Visual Basic .NET</span></h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> AcceptConnections()
        <span class="kwrd">Dim</span> localMachineInfo <span class="kwrd">As</span> IPHostEntry
        <span class="kwrd">Dim</span> localEndPoint <span class="kwrd">As</span> IPEndPoint
        <span class="kwrd">Dim</span> listener <span class="kwrd">As</span> <span class="kwrd">New</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        <span class="kwrd">Try</span>
            localMachineInfo = Dns.Resolve(<span class="kwrd">String</span>.Empty)
            localEndPoint = <span class="kwrd">New</span> IPEndPoint(localMachineInfo.AddressList(0), _port)
            listener.Bind(localEndPoint)
            listener.Listen(10)
            <span class="kwrd">While</span> <span class="kwrd">True</span>
                threadEvent.Reset()
                listener.BeginAccept(<span class="kwrd">New</span> AsyncCallback(<span class="kwrd">AddressOf</span> BeginSocketConversation), listener)
                threadEvent.WaitOne()
            <span class="kwrd">End</span> <span class="kwrd">While</span>
        <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception
          Log.Write(ex)
    <span class="kwrd">End</span> <span class="kwrd">Try</span>
<span class="kwrd">End</span> <span class="kwrd">Sub</span>
</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h5>Visual C#</h5>
<pre class="csharpcode">Public Class Class1
    Implements IAddInModule
    Implements IAddInEntryPoint

    <span class="str">' Initialize (IAddInModule)
    Public Sub Initialize(ByVal appInfo As Dictionary(Of String, Object), ByVal entryPointInfo As Dictionary(Of String, Object)) Implements IAddInModule.Initialize
        '</span> Initialization logic goes here
    End Sub

    <span class="str">' Uninitialize (IAddInModule)
    Public Sub Uninitialize() Implements IAddInModule.Uninitialize
        '</span> Clean-up logic goes here
    End Sub

    <span class="str">' Launch (IAddInEntryPoint)
    Public Sub Launch(ByVal host As AddInHost) Implements IAddInEntryPoint.Launch
        '</span> This <span class="kwrd">is</span> <span class="kwrd">where</span> normal execution begins
    End Sub
End Class</pre>
<p>Once a connection has been established, the server begins to listen for inbound messages. When new data is received, it is parsed into a custom Message object for easy inspection by a consuming class. An event is then raised to any consuming classes, passing
 a reference to the newly created Message object. The server then resumes listening for new data on the same socket. Here is the code implementation:</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> BeginSocketConversation(<span class="kwrd">ByVal</span> ar <span class="kwrd">As</span> IAsyncResult)
    threadEvent.<span class="kwrd">Set</span>()
    <span class="kwrd">RaiseEvent</span> ClientConnected()
    <span class="kwrd">Dim</span> listener <span class="kwrd">As</span> Socket = <span class="kwrd">CType</span>(ar.AsyncState, Socket)
    _socket = listener.EndAccept(ar)
    <span class="kwrd">Dim</span> buffer(PACKET_SIZE) <span class="kwrd">As</span> <span class="kwrd">Byte</span>
    <span class="kwrd">Dim</span> bytesReadCount <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0
    <span class="kwrd">While</span> <span class="kwrd">True</span>
        <span class="kwrd">Dim</span> sb <span class="kwrd">As</span> <span class="kwrd">New</span> System.Text.StringBuilder
        <span class="kwrd">Do</span>
            <span class="kwrd">Try</span>
                bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None)
            <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception
                _socket.Close()
                <span class="kwrd">Exit</span> <span class="kwrd">While</span>
            <span class="kwrd">End</span> <span class="kwrd">Try</span>
            sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount))
        <span class="kwrd">Loop</span> <span class="kwrd">While</span> _socket.Available &gt; 0
        <span class="kwrd">Dim</span> requestMessage <span class="kwrd">As</span> <span class="kwrd">New</span> RequestMessage()
        requestMessage.DeSerialize(sb.ToString())
        <span class="kwrd">RaiseEvent</span> MessageReceived(requestMessage)
    <span class="kwrd">End</span> <span class="kwrd">While</span>
    <span class="kwrd">RaiseEvent</span> ClientDisconnected()
<span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<h5><span class="kwrd">Visual C#</span></h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> BeginSocketConversation(IAsyncResult ar)
{
    threadEvent.Set();
    ClientConnected();
    Socket listener = ((Socket)(ar.AsyncState));
    _socket = listener.EndAccept(ar);
    <span class="kwrd">byte</span>[,] buffer;
    <span class="kwrd">int</span> bytesReadCount = 0;
    <span class="kwrd">while</span> (<span class="kwrd">true</span>)
    {
        System.Text.StringBuilder sb = <span class="kwrd">new</span> System.Text.StringBuilder();
        <span class="kwrd">for</span> (
        ; (_socket.Available &gt; 0);
        )
        {
            <span class="kwrd">try</span>
            {
                bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None);
            }
            <span class="kwrd">catch</span> (Exception ex)
            {
                _socket.Close();
                <span class="kwrd">break</span>;
            }
            sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount));
        }
        RequestMessage requestMessage = <span class="kwrd">new</span> RequestMessage();
        requestMessage.DeSerialize(sb.ToString());
        MessageReceived(requestMessage);
    }
    ClientDisconnected();
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h4>Object serialization</h4>
The limited resources of a mobile device require an efficient method of transferring data and commands between the device and the host machine. Due to their large size, the .NET remoting libraries and the binary serialization libraries provided by .NET 2.0
 are not available in the .NET Mobile Framework. I chose custom serialization to facilitate the transfer of objects. While less flexible, this enabled objects to be transferred using very little bandwidth.
<p>&nbsp;</p>
<h4>Implementing the AddIn.Launch method</h4>
<p>The custom server object created in the previous section encapsulates all the grunt work of socket-level protocol, accepting connections, serializing / deserializing message objects, and data transfer. Within the AddIn class implementation, all we have to
 do now is instantiate the Server class, indicating the port to listen on: </p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> Launch(<span class="kwrd">ByVal</span> host <span class="kwrd">As</span> AddInHost) <span class="kwrd">Implements</span> IAddInEntryPoint.Launch
    _wmcHost = host
    _waitForExit = <span class="kwrd">New</span> System.Threading.ManualResetEvent(<span class="kwrd">False</span>)
    _server.Start(DEFAULT_PORT)
    System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest
    _waitForExit.WaitOne()
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> Launch(AddInHost host) 
{
    _wmcHost = host;
    _waitForExit = <span class="kwrd">new</span> System.Threading.ManualResetEvent(<span class="kwrd">false</span>);
    _server.Start(DEFAULT_PORT);
    System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest;
    _waitForExit.WaitOne();
}</pre>
<p>We also perform two other critical tasks at this time. First, we assign a reference to the AddInHost to a private member variable for later use. Second, we reduce the priority of the add-in's main thread and use a ManualResetEvent to put it to sleep until
 Media Center is closed. The reason for this relates to the nature of an add-in's lifetime within Media Center. The Media Center add-in hosting process will only allow an add-in to execute for the duration of its Launch method. This means that as soon as the
 Launch method returns, the add-in and any child threads it has spawned will be terminated. For this reason, we must keep the add-in alive by blocking the Launch method from exiting.
</p>
<h4>Media Center manipulation</h4>
<p>Using the communications layer and socket listener developed in the previous sections, we can finally get to the task of performing something useful with the input requests. By subscribing to the custom Server object's MessageReceived event, the AddIn class's
 OnDataReceived method will automatically be invoked when a new request message is received from the listener:
</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> OnDataReceived(<span class="kwrd">ByVal</span> message <span class="kwrd">As</span> RequestMessage) <span class="kwrd">Handles</span> _server.MessageReceived
    <span class="kwrd">Select</span> <span class="kwrd">Case</span> message.RequestAction
        <span class="kwrd">Case</span> RequestMessage.Action.PauseMedia
_wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE
        <span class="kwrd">Case</span> RequestMessage.Action.VolumeUp
           _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp()
        <span class="kwrd">Case</span> RequestMessage.Action.VolumeDown
           _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown()
        <span class="kwrd">Case</span> RequestMessage.Action.NextMedia _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward()
        <span class="kwrd">Case</span> <span class="kwrd">Else</span>
    <span class="kwrd">End</span> <span class="kwrd">Select</span>
    SendAcknowledgement(message)
<span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> OnDataReceived(RequestMessage message) 
{
    <span class="kwrd">switch</span> (message.RequestAction) 
    {
        <span class="kwrd">case</span> RequestMessage.Action.PauseMedia:
            _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE;
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> RequestMessage.Action.VolumeUp:
            _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp();
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> RequestMessage.Action.VolumeDown:
            _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown();
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> RequestMessage.Action.NextMedia:
            _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward();
            <span class="kwrd">break</span>;
    }
    SendAcknowledgement(message);
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p>The RequestMessage class shown above is a custom object, originally created by Windows Mobile 5 application running on a connected mobile device. The transport object was then serialized on the device, transmitted, deserialized in the listener service, and
 raised to the add-in class via the MessageReceived event. The RequestAction property is an enumerable type indicating the type of action to take within Media Center. The Media Center API exposed by the AddInHost object (_wmcHost) can then be used to actually
 perform the desired Media Center operation. Finally, we send an acknowledgement message to the mobile device.<br>
</p>
<h3>Implementing the Windows Mobile 5 remote client application</h3>
After completing the Media Center add-in, the mobile application is relatively simple by comparison. The remote application's role is to present the user with a user interface similar to that of an actual remote control. The remote application directs user
 input to the listener add-in, and displays any response data if necessary.
<p>&nbsp;</p>
<h4>Implementing the socket client</h4>
<p>The design of the socket client is much simpler than that of the socket server. All execution will be performed on the primary thread. The client begins by establishing a connection with an add-in server. Once established, the socket client sends and receives
 data synchronously over the socket. Consumers of the socket client need only call the Send method, which will return with the transactional response:
</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> Send(<span class="kwrd">ByVal</span> request <span class="kwrd">As</span> Message) <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">Dim</span> responseString <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Nothing</span>
    <span class="kwrd">Try</span>
        <span class="kwrd">If</span> ((<span class="kwrd">Not</span> (_socket) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) _
                    <span class="kwrd">AndAlso</span> _socket.Connected) <span class="kwrd">Then</span>
            <span class="kwrd">Dim</span> requestString <span class="kwrd">As</span> <span class="kwrd">String</span> = request.Serialize
            Send(requestString)
            responseString = RecvSynchronous
            <span class="kwrd">Return</span> responseString
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception
        <span class="kwrd">Return</span> <span class="kwrd">Nothing</span>
    <span class="kwrd">End</span> <span class="kwrd">Try</span>
    <span class="kwrd">Return</span> responseString
<span class="kwrd">End</span> <span class="kwrd">Function</span>
</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">string</span> Send(Message request)
{
    <span class="kwrd">string</span> responseString = <span class="kwrd">null</span>;
    <span class="kwrd">try</span>
    {
        <span class="kwrd">if</span> (_socket != <span class="kwrd">null</span> &amp;&amp; _socket.Connected)
        {
            <span class="kwrd">string</span> requestString = request.Serialize();
            Send(requestString);
            responseString = RecvSynchronous();
            <span class="kwrd">return</span> responseString;
        }
    }
    <span class="kwrd">catch</span> (Exception ex)
    {
        <span class="kwrd">return</span> <span class="kwrd">null</span>;
    }
    <span class="kwrd">return</span> responseString;
}
</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h4>Adding the UI layer</h4>
With the communications layer in place the next step in our remote implementation is the user interface. In this final stage, we hook up UI controls to construct the request messages that will be sent to the host service. However, before we do that we must
 first connect with the Media Center host machine. Here's a look at the connection configuration screen:
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/7_Config2.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/7_Config_thumb.jpg" width="239" height="319"></a>
</p>
<p><em>Figure 6 - The configuration screen on the mobile device</em></p>
<p>Once we've specified the host and port of our running Media Center add-in service, we can click the “Connect” button to initialize the TCP/IP socket connection. Using the TCP Client class developed earlier, the code required to handle this event is simple:</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btnConnect_Click(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> EventArgs)
    <span class="kwrd">Dim</span> host <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtHost.Text.Trim
    <span class="kwrd">Dim</span> port <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtPort.Text.Trim
    _client.Connect(host, Convert.ToInt32(port))
<span class="kwrd">End</span> Sub</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> btnConnect_Click(<span class="kwrd">object</span> sender, EventArgs e)
{
     <span class="kwrd">string</span> host = <span class="kwrd">this</span>.txtHost.Text.Trim();
     <span class="kwrd">string</span> port = <span class="kwrd">this</span>.txtPort.Text.Trim();
     _client.Connect(host, Convert.ToInt32(port));
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Once connected, the user can navigate the application using the provided tabs at the bottom of the screen. Since this application is intended to function as a remote control, there is a standard media control screen:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/8_Controls2.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/8_Controls_thumb.jpg" width="241" height="319"></a>
</p>
<p><em>Figure 8: The control screen on the mobile device</em></p>
<p>Nothing exotic here, but the basic media control functionality you'd expect from a remote is available. Here's a sample of the code required to support the “Stop” button's click event:</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btnConnect_Click(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> EventArgs)
    <span class="kwrd">Dim</span> host <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtHost.Text.Trim
    <span class="kwrd">Dim</span> port <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtPort.Text.Trim
    _client.Connect(host, Convert.ToInt32(port))
<span class="kwrd">End</span> Sub</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> btnStop_Click(<span class="kwrd">object</span> sender, EventArgs e)
{
    RequestMessage message = <span class="kwrd">new</span> RequestMessage();
    message.RequestAction = RequestMessage.Action.StopMedia;
    message.Data = String.Empty;
    <span class="kwrd">string</span> responseString = client.Send(message);
    ResponseMessage response = <span class="kwrd">new</span> ResponseMessage(responseString);
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The UI form uses the connected Client object to execute the Stop command. First, the form constructs a Request message, populating the type of action desired (StopMedia). Next, the Request message is passed to the Client class, where it is serialized for
 transport and sent over the connected TCP socket. From there, the running Media Center service will receive the request, perform the media stop, and send an acknowledgement. The Client then returns a Response message, which will contain a Boolean indicating
 if the request was successful or not. </p>
<p>On a Media Stop request, examining the Response object is not very informative. However, for other commands, the Media Center add-in service can be designed to return any kind of information required of the host. The Detail screen is a good example:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/9_Detail2.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/9_Detail_thumb.jpg" width="240" height="321"></a>
</p>
<p><em>Figure 9 - The detail page&nbsp;</em> </p>
<p>When a song or video is currently playing, the above screen can be used to retrieve any metadata associated with it. The event handler for the screen's “Refresh” button looks similar in form to the Stop button's handler:
</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btnRefreshDetail_Click(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> EventArgs)
    <span class="kwrd">Dim</span> request <span class="kwrd">As</span> RequestMessage = <span class="kwrd">New</span> RequestMessage
    request.RequestAction = RequestMessage.Action.GetMediaMetadata
    <span class="kwrd">Dim</span> responseString <span class="kwrd">As</span> <span class="kwrd">String</span> = _client.Send(request)
    <span class="kwrd">Dim</span> response <span class="kwrd">As</span> MediaMetadataMessage = <span class="kwrd">New</span> MediaMetadataMessage(responseString)
    <span class="kwrd">For</span> <span class="kwrd">Each</span> item <span class="kwrd">As</span> MediaMetadataMessage.MediaMetadataItem <span class="kwrd">In</span> message.Data
        <span class="kwrd">If</span> ((<span class="kwrd">Not</span> (item.Value) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">AndAlso</span> (item.Value.Length &gt; 0)) <span class="kwrd">Then</span>
            <span class="kwrd">Me</span>.txtDetail.Text = (<span class="kwrd">Me</span>.txtDetail.Text &#43; (item.Key &#43; (<span class="str">&quot;: &quot;</span> &#43; item.Value)))
            <span class="kwrd">Me</span>.txtDetail.Text = (<span class="kwrd">Me</span>.txtDetail.Text &#43; <span class="str">&quot;&quot;</span> &amp; vbCrLf)
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Next</span>
<span class="kwrd">End</span> Sub</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> btnRefreshDetail_Click(<span class="kwrd">object</span> sender, EventArgs e)
{
    RequestMessage request = <span class="kwrd">new</span> RequestMessage();
    request.RequestAction = RequestMessage.Action.GetMediaMetadata;
    <span class="kwrd">string</span> responseString = _client.Send(request);
    MediaMetadataMessage response = <span class="kwrd">new</span> MediaMetadataMessage(responseString);
    <span class="kwrd">foreach</span> (MediaMetadataMessage.MediaMetadataItem item <span class="kwrd">in</span> message.Data) {
        <span class="kwrd">if</span> (item.Value != <span class="kwrd">null</span> &amp;&amp; item.Value.Length &gt; 0){
            <span class="kwrd">this</span>.txtDetail.Text &#43;= item.Key &#43; <span class="str">&quot;: &quot;</span> &#43; item.Value;
            <span class="kwrd">this</span>.txtDetail.Text &#43;= <span class="str">&quot;\r\n&quot;</span>;
        }
    }
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This time, however, the Response object has a list of metadata keys and values, which are then enumerated and displayed in a textbox. This Response object was originally populated by the Media Center add-in service:
</p>
<h5>Visual Basic .NET</h5>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SendMediaMetadata()
    <span class="kwrd">Dim</span> response <span class="kwrd">As</span> <span class="kwrd">New</span> MediaMetadataMessage()
    <span class="kwrd">Dim</span> val <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">For</span> <span class="kwrd">Each</span> key <span class="kwrd">As</span> <span class="kwrd">String</span> <span class="kwrd">In</span> _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys
    val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item(key).ToString()
    response.Data.Add(<span class="kwrd">New</span> MediaMetadataMessage.MediaMetadataItem(key, val))
    <span class="kwrd">Next</span>
    response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success
    _server.Send(response)
<span class="kwrd">End</span> Sub</pre>
<h5>Visual C#</h5>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SendMediaMetadata() 
{
    MediaMetadataMessage response = <span class="kwrd">new</span> MediaMetadataMessage();
    <span class="kwrd">string</span> val;
    <span class="kwrd">foreach</span> (<span class="kwrd">string</span> key <span class="kwrd">in</span> _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys) 
    {
        val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item[key].ToString();
        response.Data.Add(<span class="kwrd">new</span> MediaMetadataMessage.MediaMetadataItem(key, val));
    }
    response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success;
    _server.Send(response);
}</pre>
<style type="text/css">
<!--
.csharpcode
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{background-color:#ffffff;
	font-family:consolas,"Courier New",courier,monospace;
	color:black;
	font-size:small}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	margin:0em;
	width:100%}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>After receiving a request from the mobile device for the currently playing media's metadata, the Media Center add-in service constructs a list of custom objects (MediaMetadataItem). It populates this list by enumerating properties of the AddInHost object,
 through the namespace MediaCenterEnvironment.MediaExperience.MediaMetadata. It then sends this list on the Response object, where the mobile device will inspect and display the data, as shown above.
</p>
<p>The last feature that the mobile remote application provides is the ability to select specific media to play based on a list of available media on the host. This functionality is provided for audio, video, and images:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/10_Music2.jpg"><img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/10_Music_thumb.jpg" width="240" height="320"></a>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/11_Video2.jpg">
<img border="0" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/2632164/11_Video_thumb.jpg" width="240" height="320"></a>
</p>
<p><em>Figure 10 - Music and Video&nbsp;list management&nbsp;</em> </p>
<p>The mobile application requests the list of available media in a similar fashion to the Details screen implementation. The resulting list of files is then bound and displayed in a DataGrid. The Media Center add-in service can then be instructed to play individual
 songs or videos using the AddInHost's MediaCenterEnvironment.PlayMedia method. </p>
<h4><strong>Mobile Application UI design considerations</strong></h4>
<p>Developing on the mobile platform introduces design challenges not found in Windows Forms applications due to the small amount of screen real estate available. Many typical form layouts found in Windows Forms applications won't work well on a mobile device's
 small screen. When developing for a mobile application, try to keep the user interface as simple as possible. Window containers and managers such as a tabbed control enable the developer to functionally divide an application into logical components. This alleviates
 the clutter created by having too many controls in a single window. Also try to keep your text and controls as simple and large as possible. This makes the application easier to view and manipulate, especially in outdoor or bright conditions.</p>
<h3>Conclusion</h3>
<p>Once complete, the remote application gives you a level of control simply not available on hardware-based remote controls. I really enjoyed working on this application because it gave me a chance to integrate a number of different technologies into a single
 implementation. Be sure to download the code and take the remote for a spin. For those not familiar with all of the components used in this article (Media Center add-in services, socket communication, installer and assembly signing, etc.), don't be intimidated.
 The Microsoft-provided SDK packages for both parts of the solution make creating your own add-in projects a snap. Plus, the technical challenges unique to this project have already been overcome! Feel free to modify my implementation, or reuse the included
 socket classes to create an add-in all your own. Finally, please post feedback or questions here or at my
<a href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx">blog</a>.</p>
<h3>About the Author</h3>
<p>Matt Ivers is a software engineer at Chicago-based <a href="http://www.claritycon.com/">
Clarity Consulting</a>. He has extensive professional experience developing .NET solutions in both Visual C# .NET and VB.NET. Check him out at his
<a href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx">blog</a> or through the Clarity blog site,
<a href="http://blogs.claritycon.com/">Clarity Blogs</a>. </p>
<h3>References</h3>
<p><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;displaylang=en">Windows Media Center SDK 5.0</a><br>
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;DisplayLang=en">Windows Mobile 5.0 Smartphone SDK</a>
</p>
<p><a href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx">How to: Sign an Assembly using Visual Studio 2005</a><br>
<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp">How to: Create a Windows Installer File for a Windows Media Center Add-in</a>
</p>
<p><a href="http://msdn2.microsoft.com/en-gb/library/ms816327.aspx">Windows Media Center - SDK Overview</a><br>
<a href="http://msdn2.microsoft.com/en-us/library/bb189667.aspx">Windows Media Center - Understanding the Basics</a><br>
<a href="http://msdn2.microsoft.com/en-us/library/bb189733.aspx">Windows Media Center - Development Tools</a><br>
<a href="http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnxpmce/html/positionchangeraddin.asp">Windows Media Center - AddIn example: &quot;Time Travel&quot;</a>
</p>
<p><a href="http://msdn2.microsoft.com/en-us/library/5w7b7x5f.aspx">Using an Asynchronous Server Socket</a></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:5f3aee551c9a4099a3d29e7600d3e5ee">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Control-Windows-Media-Center-using-a-Windows-Mobile-5-Device</comments>
      <itunes:summary>
This article demonstrates how to use a smartphone running Windows Mobile 5 to remotely control a host machine running Windows Media Center. I will describe how to create an add-in application that runs within Windows Media Center, and how to create a Windows
 Mobile 5 application that you can use to communicate with the Media Center over a wireless internet connection. Finally, I will demonstrate how to use this implementation to manipulate Media Center using the Windows Media Center API.
 
Matt Ivers
 
Difficulty: Intermediate  
Time Required: 6-10 hours 
Cost: $100-$200  
Software: Visual Basic or Visual C# Express Editions,

Windows Media Center SDK 5.0, 
Windows Mobile 5.0 Smartphone SDK  
Hardware: Mobile device running Windows Mobile 5.0  
Download: C# and VB.Net 


Introduction
Starting with Windows Media Center Edition 2005, Media Center added extensibility support through hosted add-in assemblies. By implementing an add-in interface and registering the assembly with Media Center, the add-in assembly is given access to the Microsoft.MediaCenter.Hosting.AddInHost
 object. Using this object model, an add-in assembly can programmatically inspect and manipulate various aspects of Windows Media Center. In addition to the exposed Media Center namespaces, the add-in has complete access to all the capabilities of the .NET
 Framework.
&amp;nbsp; 
By combining the power of a Media Center add-in with a mobile device running Windows Mobile 5.0, we can extend the capabilities of a Media Center add-in even further. The add-in service I developed runs as a listener service within Windows Media Center on
 the host machine. It is initialized when Windows Media Center is started, runs invisibly in the background, and allows mobile devices to connect and submit requests to it. The mobile solution leverages an existing WiFi internet connection to communicate with
 the add-in via TCP socket connections. The mobile device runs a .NET Compact Framework 2.0 forms application designed </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Control-Windows-Media-Center-using-a-Windows-Mobile-5-Device</link>
      <pubDate>Mon, 14 May 2007 17:08:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Control-Windows-Media-Center-using-a-Windows-Mobile-5-Device</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/2632164_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/2632164_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Matt Ivers</dc:creator>
      <itunes:author>Matt Ivers</itunes:author>
      <slash:comments>25</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Control-Windows-Media-Center-using-a-Windows-Mobile-5-Device/RSS</wfw:commentRss>
      <category>Media</category>
      <category>Home Automation</category>
      <category>audiovideo</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Managed Library for Nintendo&#39;s Wiimote</title>
      <description><![CDATA[<span id="c4fmetadata">
<table border="0" cellpadding="1" cellspacing="0" width="100%">
<tbody>
<tr class="entry_overview">
<td width="50"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1879033/wiimote4.jpg" height="50" width="41">&nbsp;</td>
<td><span class="entry_description">In this article, Brian Peek demonstrates how to connect to and use the Nintendo Wiimote from C# and VB.NET. The final output is an easy-to-use managed API for the Wiimote that can be used in any managed application.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author"><a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a></div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Less Than $50 (Free if you already own a Wiimote)</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual C# or Visual Basic 2008 Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"><a href="http://wii.nintendo.com/controller.jsp">Nintendo Wii Remote (Wiimote)</a>, a compatible PC Bluetooth adapter and stack</span></div>
<div class="entry_details"><b>Download: </b><a href="http://www.codeplex.com/WiimoteLib" target="_blank">CodePlex</a>
</div>
<div class="entry_details">&nbsp;</div>
</td>
</tr>
</tbody>
</table>
<h3><b>Updates</b></h3>
<p><b>1/19/09</b> - Version 1.7 now up at <a href="http://www.codeplex.com/WiimoteLib">
CodePlex</a>. <br>
</p>
<p><b>6/15/08 – </b>Version 1.5.2 is now up at <a href="http://www.codeplex.com/WiimoteLib" target="_blank">
CodePlex</a>.&nbsp; The Balance Board should really work this time….</p>
<p><b>6/12/08</b> - Version 1.5.1 has been removed from CodePlex...it has proven to be too buggy for most users (though it continues to work just fine for me).&nbsp; Look for version 1.5.2 soon...
<br>
</p>
<p><b>6/11/08 – </b>Version 1.5.1 posted at <a href="http://www.codeplex.com/WiimoteLib" target="_blank">
CodePlex</a>.&nbsp; Fixed a bug with the Balance Board…&nbsp; <b>UPDATE:&nbsp; It appears some people are still having issues with this build as well due to some Balance Boards being a bit finicky in their response times.&nbsp; Stay tuned for build 1.5.2 soon…</b></p>
<p><b>6/9/08</b> – Version 1.5 posted at <a href="http://www.codeplex.com/WiimoteLib" target="_blank">
CodePlex</a>.&nbsp; The <a href="http://en.wikipedia.org/wiki/Wii_Balance_Board" target="_blank">
Wii Fit Balance Board</a> is now supported.</p>
<p><b>6/3/08</b> – New version 1.4 posted at the download link above.&nbsp; The big change is multiple Wiimotes are now finally supported.</p>
<p><b>5/27/08</b> - New version 1.3 posted at the download link above.&nbsp; Lots of changes, so be sure to read the included docs!</p>
<p><b>1/29/08</b> - New version 1.2.1.0 posted at the download link above.&nbsp; The only change for this release is adding support for IR3 and IR4 since I've gotten so many questions about it.<br>
</p>
<p><b>10/22/07</b> - New version 1.2.0.0 posted at the download link above.&nbsp; There are a variety of fixes and new features added.&nbsp; The source code and binary releases are now hosted at CodePlex.&nbsp; A .chm help file is also included documenting the API itself.&nbsp;
 Please note that a license is now included with the library which explicitly defines how the library can be used.&nbsp; For 99% of you, this won't change anything, but I've received tons of emails asking about restrictions, so now there's something official attached.&nbsp;
 Check out the readme.txt and license.txt in the docs directory included with the official distribution for more information.</p>
<p><b>6/12/07</b> - New version 1.1.0.0 posted at the download link above.&nbsp; This fixes several issues, adds an alternate writing method which
<b>may</b> help those with troubled bluetooth stacks/adapters, adds Vista/XP x64 support, and a Microsoft Robotics Studio service version of the library.&nbsp; See the included readme.txt for more information.&nbsp; Additionally, see my new article on using the new MSRS
 service to create a Wiimote-controlled car!</p>
<p><b>3/17/07</b> - New version 1.0.1.0 posted at the download link above.&nbsp; This fixes a bug with the calibration data being stored by the API.&nbsp; Thanks to James Darpinian for the catch!</p>
<h3>Introduction</h3>
<p>Nintendo's Wii Remote (forever known as the Wiimote) is a fantastic little controller for the Nintendo Wii system.&nbsp; Because it uses Bluetooth to communicate with the Wii, it can be connected to and used by practically any Bluetooth capable device.</p>
<p>If you care to just use the library and are not concerned with the implementation details, skip down to the
<a href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=4539&amp;postid=1879033#usage">
usage section</a>.</p>
<p>Before we get started, there are two websites that one should peruse before reading the code contained here.&nbsp; These two sites have done 99% of the work of figuring out the data that is sent and received with the Wiimote.&nbsp; I am not going to repeat most of
 this information here since both of the these sites explain the protocol so thoroughly.&nbsp; Without the work of the people posting to these sites, none of this would have been possible.</p>
<ul>
<li><a href="http://www.wiili.org/index.php/Wiimote" target="_blank">WiiLi Wiki</a>
</li><li><a href="http://www.wiibrew.org/index.php?title=Wiimote" target="_blank">WiiBrew Wiki</a></li></ul>
<h3><b>Getting Connected</b></h3>
<p>This will likely be the biggest sticking point.&nbsp; The Wiimote will not pair and communicate successfully with every Bluetooth device and stack on the planet.&nbsp;&nbsp; There's little I can do to help get you connected if the following steps do not work.&nbsp; Either it's
 going to work, or it isn't.&nbsp; Cross your fingers...</p>
<ol>
<li>Start up your Bluetooth software and have it search for a device. </li><li>Hold down the 1 and 2 buttons on the Wiimote.&nbsp; You should see the LEDs at the bottom start flashing.&nbsp;
<b>Do not let go of these buttons until this procedure is complete.</b>&nbsp; If pairing the Wii Fit Balance Board, open the battery cover on the underside of the balance board and hold the little red sync button.
</li><li>Wiimotes should show up in the list of devices found as <b>Nintendo RVL-CNT-01</b>.&nbsp; Balance Boards will show up as
<b>Nintendo RVL-WBC-01</b>.&nbsp; If it's not there, start over and try again. </li><li>Click <b>Next</b> to move your way through the wizard.&nbsp; If at any point you are asked to enter a security code or PIN, leave the number blank or click
<b>Skip</b>.&nbsp; Do not enter a number. </li><li>You may be asked which service to use from the Wiimote.&nbsp; Select the keyboard/mouse/HID service if prompted (you should only see one service available).
</li><li>Finish the wizard.</li></ol>
<p>That's it.&nbsp; The LEDs at the bottom should continue to flash and you should see the device listed in your list of connected Bluetooth devices.&nbsp; If you run the test application included with the source code and you see the numbers change, you are all set.&nbsp;
 If you don't see them change or you get an error, try the above again.&nbsp; If it continues to not function, you are likely stuck with an incompatible device or stack.</p>
<h3><b>The Exciting World of HID and P/Invoke</b></h3>
<p>When the Wiimote is paired with your PC, it will be identified as a HID-compliant device.&nbsp; Therefore, to connect to the device, we must use the HID and Device Management Win32 APIs.&nbsp; Unfortunately there is no built-in support for these APIs in the current
 .NET runtime, so we must enter the realm of P/Invoke.&nbsp; These APIs are defined in the Windows Driver Kit (WDK) so if you wish to see the original C header files or read the API documentation, you will need to download and install the latest
<a href="http://www.microsoft.com/whdc/devtools/wdk/default.mspx" target="_blank">
WDK</a>.</p>
<p>P/Invoke, as you probably know, allows one to directly call methods of the Win32 API from .NET.&nbsp; The difficulty of this is finding the right method signatures and structure definitions which will properly marshal the data through to Win32.&nbsp; A great resource
 for these signatures is the <a href="http://pinvoke.net/" target="_blank">P/Invoke wiki</a>.&nbsp; Almost all of the methods used in this project were defined by this resource.&nbsp; For this project, all P/Invoke'd methods live in the
<b>HIDImports</b> class.</p>
<p>The process to begin communication with the Wiimote is as follows:</p>
<ol>
<li>Get the GUID of the HID class defined by Windows </li><li>Get a handle to the list of all devices which are part of the HID class </li><li>Enumerate through those devices and get detailed information about each </li><li>Compare the Vendor ID and Product ID of each device to the known Wiimote's VID and PID
</li><li>When found, create a FileStream to read/write to the device </li><li>Clean up the device list</li></ol>
<p>&nbsp;</p>
</span>In code, the process is as follows (shortened from the original code for space):
<p><b>VB</b></p>
<div>
<pre><span>' read/write handle to the device</span><br><span>Private</span> mHandle <span>As</span> SafeFileHandle<br><br><span>' a pretty .NET stream to read/write from/to</span><br><span>Private</span> mStream <span>As</span> FileStream<br><span>Private</span> found <span>As</span> <span>Boolean</span> = <span>False</span><br><span>Private</span> guid <span>As</span> Guid<br><span>Private</span> index <span>As</span> UInteger = 0<br><br><span>' 1. get the GUID of the HID class</span><br>HIDImports.HidD_GetHidGuid(guid)<br><br><span>' 2. get a handle to all devices that are part of the HID class</span><br><span>Dim</span> hDevInfo <span>As</span> IntPtr = HIDImports.SetupDiGetClassDevs(guid, <span>Nothing</span>, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE) <span>' | HIDImports.DIGCF_PRESENT);</span><br><br><span>' create a new interface data struct and initialize its size</span><br><span>Dim</span> diData <span>As</span> HIDImports.SP_DEVICE_INTERFACE_DATA = <span>New</span> HIDImports.SP_DEVICE_INTERFACE_DATA()<br>diData.cbSize = Marshal.SizeOf(diData)<br><br><span>' 3. get a device interface to a single device (enumerate all devices)</span><br><span>Do</span> <span>While</span> HIDImports.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, guid, index, diData)<br>    <span>' create a detail struct and set its size</span><br>    <span>Dim</span> diDetail <span>As</span> HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA = <span>New</span> HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA()<br>    diDetail.cbSize = 5 <span>'should be: (uint)Marshal.SizeOf(diDetail);, but that's the wrong size</span><br><br>    <span>Dim</span> size <span>As</span> UInt32 = 0<br><br>    <span>' get the buffer size for this device detail instance (returned in the size parameter)</span><br>    HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, diData, IntPtr.Zero, 0, size, IntPtr.Zero)<br><br>    <span>' actually get the detail struct</span><br>    <span>If</span> HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, diData, diDetail, size, size, IntPtr.Zero) <span>Then</span><br>        <span>' open a read/write handle to our device using the DevicePath returned</span><br>        mHandle = HIDImports.CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, HIDImports.EFileAttributes.Overlapped, IntPtr.Zero)<br><br>        <span>' 4. create an attributes struct and initialize the size</span><br>        <span>Dim</span> attrib <span>As</span> HIDImports.HIDD_ATTRIBUTES = <span>New</span> HIDImports.HIDD_ATTRIBUTES()<br>        attrib.Size = Marshal.SizeOf(attrib)<br><br>        <span>' get the attributes of the current device</span><br>        <span>If</span> HIDImports.HidD_GetAttributes(mHandle.DangerousGetHandle(), attrib) <span>Then</span><br>            <span>' if the vendor and product IDs match up</span><br>            <span>If</span> attrib.VendorID = VID <span>AndAlso</span> attrib.ProductID = PID <span>Then</span><br>                <span>' 5. create a nice .NET FileStream wrapping the handle above</span><br>                mStream = <span>New</span> FileStream(mHandle, FileAccess.ReadWrite, REPORT_LENGTH, <span>True</span>)<br>            <span>Else</span><br>                mHandle.Close()<br>            <span>End</span> <span>If</span><br>        <span>End</span> <span>If</span><br>    <span>End</span> <span>If</span><br><br>    <span>' move to the next device</span><br>    index &#43;= 1<br><span>Loop</span><br><br><span>' 6. clean up our list</span><br>HIDImports.SetupDiDestroyDeviceInfoList(hDevInfo)</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>C#</b></p>
<div>
<pre><span>// read/write handle to the device</span><br><span>private</span> SafeFileHandle mHandle;<br><br><span>// a pretty .NET stream to read/write from/to</span><br><span>private</span> FileStream mStream;<br><span>bool</span> found = <span>false</span>;<br>Guid guid;<br><span>uint</span> index = 0;<br><br><span>// 1. get the GUID of the HID class</span><br>HIDImports.HidD_GetHidGuid(<span>out</span> guid);<br><br><span>// 2. get a handle to all devices that are part of the HID class</span><br>IntPtr hDevInfo = HIDImports.SetupDiGetClassDevs(<span>ref</span> guid, <span>null</span>, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE);<span>// | HIDImports.DIGCF_PRESENT);</span><br><br><span>// create a new interface data struct and initialize its size</span><br>HIDImports.SP_DEVICE_INTERFACE_DATA diData = <span>new</span> HIDImports.SP_DEVICE_INTERFACE_DATA();<br>diData.cbSize = Marshal.SizeOf(diData);<br><br><span>// 3. get a device interface to a single device (enumerate all devices)</span><br><span>while</span>(HIDImports.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, <span>ref</span> guid, index, <span>ref</span> diData))<br>{<br>    <span>// create a detail struct and set its size</span><br>    HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = <span>new</span> HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA();<br>    diDetail.cbSize = 5; <span>//should be: (uint)Marshal.SizeOf(diDetail);, but that's the wrong size</span><br><br>    UInt32 size = 0;<br><br>    <span>// get the buffer size for this device detail instance (returned in the size parameter)</span><br>    HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, <span>ref</span> diData, IntPtr.Zero, 0, <span>out</span> size, IntPtr.Zero);<br><br>    <span>// actually get the detail struct</span><br>    <span>if</span>(HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, <span>ref</span> diData, <span>ref</span> diDetail, size, <span>out</span> size, IntPtr.Zero))<br>    {<br>        <span>// open a read/write handle to our device using the DevicePath returned</span><br>        mHandle = HIDImports.CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, HIDImports.EFileAttributes.Overlapped, IntPtr.Zero);<br><br>        <span>// 4. create an attributes struct and initialize the size</span><br>        HIDImports.HIDD_ATTRIBUTES attrib = <span>new</span> HIDImports.HIDD_ATTRIBUTES();<br>        attrib.Size = Marshal.SizeOf(attrib);<br><br>        <span>// get the attributes of the current device</span><br>        <span>if</span>(HIDImports.HidD_GetAttributes(mHandle.DangerousGetHandle(), <span>ref</span> attrib))<br>        {<br>            <span>// if the vendor and product IDs match up</span><br>            <span>if</span>(attrib.VendorID == VID &amp;&amp; attrib.ProductID == PID)<br>            {<br>                <span>// 5. create a nice .NET FileStream wrapping the handle above</span><br>                mStream = <span>new</span> FileStream(mHandle, FileAccess.ReadWrite, REPORT_LENGTH, <span>true</span>);<br>            }<br>            <span>else</span><br>                mHandle.Close();<br>        }<br>    }<br><br>    <span>// move to the next device</span><br>    index&#43;&#43;;<br>}<br><br><span>// 6. clean up our list</span><br>HIDImports.SetupDiDestroyDeviceInfoList(hDevInfo);</pre>
</div>
<p><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><b></b></p>
<h3><b><b>CreateFile and SafeFileHandles</b></b></h3>
<p>If you read through the above code, you may have noticed that the handle to the Wiimote is opened using Win32's
<b>CreateFile</b> function instead of directly using a <b>FileStream</b> object or some other managed way.&nbsp; This is required due to the way that the handle needs to be created.&nbsp; The
<b>DevicePath</b> member of the detail struct contains a non-file system path that Win32 can use to open a handle to the device.&nbsp; The .NET methods for performing this action will only allow file system paths, so we must use the Win32 method instead.</p>
<p>You will also notice that we use the <b>SafeFileHandle</b> object to wrap the handle returned from the call to
<b>CreateFile</b>.&nbsp; The <b>SafeFileHandle</b> object wraps a native Win32 handle and allows one to safely manage the native type and cleanly close things up at the end of the application.&nbsp; One could just as easily use an
<b>IntPtr</b>, but I have found that this is a much cleaner method for dealing with the native type.</p>
<h3><b>Wiimote I/O and HID Reports</b></h3>
<p>In the world of HID, data is sent and received as &quot;reports&quot;.&nbsp; Simply, it is a data buffer of a pre-defined length with a header that determines the report contained in the buffer.&nbsp; The Wiimote will send and can receive various reports, all of which are 22
 bytes in length, and all of which are explained at the links above.&nbsp; Given the number and complexity, I suggest you read through the wikis above if you wish to know more about the Wiimote's reports and the data they contain.</p>
<p>Now that we have a a <b>FileStream</b> on which to communicate with the Wiimote, we can start communication.&nbsp; Because reports will be sent and received almost constantly, it is essential that asynchronous I/O operations are used.&nbsp; In .NET, this is quite
 simple.&nbsp; The process is to start an asynchronous read operation and provide a callback method to be run when the buffer is full.&nbsp; When the callback is run, the data is handled and the process is repeated.</p>
<p><b>VB</b>&nbsp;</p>
<div>
<pre><span>' sure, we could find this out the hard way using HID, but trust me, it's 22</span><br><span>Private</span> <span>Const</span> REPORT_LENGTH <span>As</span> <span>Integer</span> = 22<br><br><span>' report buffer</span><br><span>Private</span> mBuff <span>As</span> <span>Byte</span>() = <span>New</span> <span>Byte</span>(REPORT_LENGTH - 1){}<br><br><span>Private</span> <span>Sub</span> BeginAsyncRead()<br>    <span>' if the stream is valid and ready</span><br>    <span>If</span> mStream.CanRead <span>Then</span><br>        <span>' create a read buffer of the report size</span><br>        <span>Dim</span> buff <span>As</span> <span>Byte</span>() = <span>New</span> <span>Byte</span>(REPORT_LENGTH - 1){}<br><br>        <span>' setup the read and the callback</span><br>        mStream.BeginRead(buff, 0, REPORT_LENGTH, <span>New</span> AsyncCallback(<span>AddressOf</span> OnReadData), buff)<br>    <span>End</span> <span>If</span><br><span>End</span> <span>Sub</span><br><br><span>Private</span> <span>Sub</span> OnReadData(<span>ByVal</span> ar <span>As</span> IAsyncResult)<br>    <span>' grab the byte buffer</span><br>    <span>Dim</span> buff <span>As</span> <span>Byte</span>() = <span>CType</span>(ar.AsyncState, <span>Byte</span>())<br><br>    <span>' end the current read</span><br>    mStream.EndRead(ar)<br><br>    <span>' start reading again</span><br>    BeginAsyncRead()<br><br>    <span>' handle data....</span><br><span>End</span> Sub</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>C#</b></p>
<div>
<pre><span>// sure, we could find this out the hard way using HID, but trust me, it's 22</span><br><span>private</span> <span>const</span> <span>int</span> REPORT_LENGTH = 22;<br><br><span>// report buffer</span><br><span>private</span> <span>byte</span>[] mBuff = <span>new</span> <span>byte</span>[REPORT_LENGTH];<br><br><span>private</span> <span>void</span> BeginAsyncRead()<br>{<br>    <span>// if the stream is valid and ready</span><br>    <span>if</span>(mStream.CanRead)<br>    {<br>        <span>// create a read buffer of the report size</span><br>        <span>byte</span>[] buff = <span>new</span> <span>byte</span>[REPORT_LENGTH];<br><br>        <span>// setup the read and the callback</span><br>        mStream.BeginRead(buff, 0, REPORT_LENGTH, <span>new</span> AsyncCallback(OnReadData), buff);<br>    }<br>}<br><br><span>private</span> <span>void</span> OnReadData(IAsyncResult ar)<br>{<br>    <span>// grab the byte buffer</span><br>    <span>byte</span>[] buff = (<span>byte</span>[])ar.AsyncState;<br><br>    <span>// end the current read</span><br>    mStream.EndRead(ar);<br><br>    <span>// start reading again</span><br>    BeginAsyncRead();<br>    <br>    <span>// handle data....</span><br>}<br></pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3><b>That's it!</b></h3>
<p>You may not believe it, but that code is enough to open and start communicating with the Wiimote.&nbsp; The rest of the code involves parsing the data sent from the Wiimote and writing properly formed data to the Wiimote.&nbsp; As I said, I'm not going to go into
 the detail of the reports as the sites above will do a much better job than I, but one can write any command to the Wiimote simply by doing the following:</p>
<p><b>VB</b></p>
<pre class="csharpcode"></pre>
<div>
<pre>mStream.Write(mBuff, 0, REPORT_LENGTH)</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>C#</b></p>
<pre class="csharpcode"></pre>
<div>
<pre>mStream.Write(mBuff, 0, REPORT_LENGTH);</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Reading is done with the async code you see above.&nbsp; When a report of 22 bytes is received, the
<b>OnReadData</b> method is called, and the data can be properly parsed and used.</p>
<h3><b><a class="" title="usage" name="usage"></a>Usage of the API</b></h3>
<p>If you don't care about the implementation details, you've likely skipped down to this section to learn how to use the API in your own application.&nbsp; The easiest way to learn how it all works is to look at the
<b>WiimoteTest</b> application included with the source code.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1879033/captured_Image.png.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1879033/captured_Image.png_thumb.png" title="captured_Image.png" alt="captured_Image.png" border="0" height="172" width="244"></a>
</p>
<p>First, you will need to add a reference to the <b>WiimoteLib.dll</b> included with the source code.&nbsp; Next, you will need to pull the namespace into your application with the standard
<b>using/Imports</b> statement.&nbsp; With that in place, you can now create an instance of the Wiimote class and start using it.&nbsp; Simply instantiate a new instance of the Wiimote class, setup events if you wish to use them, setup the report type of the data you
 want to be returned, and call the <b>Connect</b> method.</p>
<p><b>VB</b></p>
<div>
<pre><span>Imports</span> WiimoteLib<br><br><span>Private</span> <span>Sub</span> Form1_Load(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)<br>    <span>' create a new instance of the Wiimote</span><br>    <span>Dim</span> wm <span>As</span> Wiimote = <span>New</span> Wiimote()<br><br>    <span>' setup the event to handle state changes</span><br>    <span>AddHandler</span> wm.WiimoteChanged, <span>AddressOf</span> wm_WiimoteChanged<br><br>    <span>' setup the event to handle insertion/removal of extensions</span><br>    <span>AddHandler</span> wm.WiimoteExtensionChanged, <span>AddressOf</span> wm_WiimoteExtensionChanged<br><br>    <span>' connect to the Wiimote</span><br>    wm.Connect()<br><br>    <span>' set the report type to return the IR sensor and accelerometer data (buttons always come back)</span><br>    wm.SetReportType(Wiimote.InputReport.IRAccel, <span>True</span>)<br><span>End</span> <span>Sub</span><br><br><br><span>Private</span> <span>Sub</span> wm_WiimoteExtensionChanged(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> args <span>As</span> WiimoteExtensionChangedEventArgs)<br>    <span>If</span> args.Inserted <span>Then</span><br>        wm.SetReportType(Wiimote.InputReport.IRExtensionAccel, <span>True</span>) <span>' return extension data</span><br>    <span>Else</span><br>        wm.SetReportType(Wiimote.InputReport.IRAccel, <span>True</span>) <span>' back to original mode</span><br>    <span>End</span> <span>If</span><br><span>End</span> <span>Sub</span><br><br><span>Private</span> <span>Sub</span> wm_OnWiimoteChanged(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> args <span>As</span> WiimoteChangedEventArgs)<br>    <span>' current state information</span><br>    <span>Dim</span> ws <span>As</span> WiimoteState = args.WiimoteState<br><br>    <span>' write out the state of the A button    </span><br>    Debug.WriteLine(ws.ButtonState.A)<br><span>End</span> Sub</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>C#</b></p>
<div>
<pre><span>using</span> WiimoteLib;<br><br><span>private</span> <span>void</span> Form1_Load(<span>object</span> sender, EventArgs e)<br>{<br>    <span>// create a new instance of the Wiimote</span><br>    Wiimote wm = <span>new</span> Wiimote();<br>    <br>    <span>// setup the event to handle state changes</span><br>    wm.WiimoteChanged &#43;= wm_WiimoteChanged;<br>    <br>    <span>// setup the event to handle insertion/removal of extensions</span><br>    wm.WiimoteExtensionChanged &#43;= wm_WiimoteExtensionChanged;<br>    <br>    <span>// connect to the Wiimote</span><br>    wm.Connect();<br>    <br>    <span>// set the report type to return the IR sensor and accelerometer data (buttons always come back)</span><br>    wm.SetReportType(Wiimote.InputReport.IRAccel, <span>true</span>);<br>}<br><br><br><span>void</span> wm_WiimoteExtensionChanged(<span>object</span> sender, WiimoteExtensionChangedEventArgs args)<br>{<br>    <span>if</span>(args.Inserted)<br>        wm.SetReportType(Wiimote.InputReport.IRExtensionAccel, <span>true</span>);    <span>// return extension data</span><br>    <span>else</span><br>        wm.SetReportType(Wiimote.InputReport.IRAccel, <span>true</span>);            <span>// back to original mode</span><br>}<br><br><span>void</span> wm_WiimoteChanged(<span>object</span> sender, WiimoteChangedEventArgs args)<br>{<br>    <span>// current state information</span><br>    WiimoteState ws = args.WiimoteState;<br><br>    <span>// write out the state of the A button    </span><br>    Debug.WriteLine(ws.ButtonState.A);<br>}<br></pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>If you wish to use multiple Wiimotes, instantiate a <b>WiimoteCollection</b> object, call the
<b>FindAllWiimotes</b> method to initialize it, and then use each individual Wiimote object in the collection as a separate instance.</p>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Dim</span> wc <span>As</span> <span>New</span> WiimoteCollection()<br>wc.FindAllWiimotes()<br><br><span>For</span> <span>Each</span> wm <span>As</span> Wiimote <span>In</span> wc<br>    <span>AddHandler</span> wm.WiimoteChanged, <span>AddressOf</span> wm_WiimoteChanged<br>    <span>AddHandler</span> wm.WiimoteExtensionChanged, <span>AddressOf</span> wm_WiimoteExtensionChanged<br>    <br>    wm.Connect()<br>    wm.SetReportType(InputReport.IRAccel, <span>True</span>)<br><span>Next</span> wm<br></pre>
<br>
</div>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">WiimoteCollection wc = <span>new</span> WiimoteCollection();<br>wc.FindAllWiimotes();<br><br><span>foreach</span>(Wiimote wm <span>in</span> wc)<br>{<br>    wm.WiimoteChanged &#43;= wm_WiimoteChanged;<br>    wm.WiimoteExtensionChanged &#43;= wm_WiimoteExtensionChanged;<br>    <br>    wm.Connect();<br>    wm.SetReportType(InputReport.IRAccel, <span>true</span>);<br>}</pre>
<br>
</div>
<p>Data can be retrieved from the API in two ways:&nbsp; events and polling.&nbsp; In event mode, one must subscribe to the
<b>WiimoteChanged</b> event as shown above.&nbsp; Then, when data is sent from the Wiimote to the PC, an event will be posted to your event handler for processing in your application.&nbsp; If you elect to not use the event model, you may simply retrieve state information
 at any time from the <b>WiimoteState</b> property of the <b>Wiimote</b> class.</p>
<p><b>Report Types</b></p>
<p>The library currently supports only a handful of the many report types the Wiimote is capable of producing, however the ones that are implemented are enough to get all required data for the Wiimote and all current extensions.&nbsp; Specifically, these reports
 are:</p>
<ul>
<li><b>Buttons</b> - Button data only </li><li><b>ButtonsAccel</b> - Button and accelerometer data </li><li><b>IRAccel</b> - Button, accelerometer and IR data </li><li><b>ButtonsExtension</b> – Button and extension data </li><li><b>ExtensionAccel</b> - Button, accelerometer and extension data </li><li><b>IRExtensionAccel</b> - Button, accelerometer, extension and IR data</li></ul>
<p>The report type can be set by calling the <b>SetReportType</b> method using the appropriate report type and whether or not you would like the data to be sent continuously or only when the state of the controller has changed.</p>
<h3><b>Extensions</b></h3>
<p>There are currently three Wii extensions supported by the library: the Nunchuk, the Classic Controller, and the Guitar Hero controller.&nbsp; If you wish to use these, you must setup an event handler for the
<b>WiimoteExtensionChanged</b> event.&nbsp; When this event is called, you can check the event argument to determine if an extension was inserted or removed, and what type extension was inserted.&nbsp; In this event handler, you will need to change the report type with
 the <b>SetReportType</b> method to one that supports extension data, otherwise the data will not be returned to you.</p>
<p>If you are using a strictly polled method, you may also check the <b>Extension</b> and
<b>ExtensionType</b> parameters of the <b>WiimoteState</b> property to determine when an extension has been inserted or removed.</p>
<p>The Wii Fit Balance Board will show up as a Wiimote controller with an extension attached.&nbsp; The report type is set internally and any attempt to set a new report type on this device will be ignored.&nbsp; The power button maps to the Wiimote's
<b>A</b> button, and the LED maps to the Wiimote's <b>LED1</b>.&nbsp; The rest of the Wiimote's properties are ignored.&nbsp; The remainder of the balance board information can be found in the
<b>BalanceBoard</b> struct inside the <b>WiimoteState</b> object.</p>
<h3><b>State Information</b></h3>
<p>The heart of the entire library is contained in the <b>WiimoteState</b> object.&nbsp; Check the download's included .chm help file for the full set of properties available.&nbsp;
</p>
<h3><b>To Do...</b></h3>
<p>At the moment, usage of the speaker on the Wiimote is not supported.&nbsp; I will likely add this in a future update.&nbsp; Additionally, there are several report types which are not implemented, however the reports which are implemented return all necessary information.&nbsp;
 I would also like to add some &quot;higher level&quot; functionality that will return pitch/roll angles, mouse cursor position for the IR sensor, etc.&nbsp; Check this article and my
<a href="http://www.brianpeek.com/" target="_blank">blog</a> for information on updates to the library.</p>
<h3><b>Conclusion</b></h3>
<p>And there we have it.&nbsp; A fully functional managed library for the Wiimote.&nbsp; Give it a try and integrate it into your existing applications or build something new!&nbsp; I'm looking forward to some creative uses of the library...</p>
<p>If you have any issues using the library, or have any feature requests (other than sound), please don't hesitate to
<a href="http://www.brianpeek.com/blog/contact.aspx" target="_blank">contact me</a> directly or post a message in my
<a href="http://www.brianpeek.com/forums/24/ShowForum.aspx" target="_blank">forum</a> dedicated to the project.</p>
<p>Enjoy!</p>
<h3><b>Links</b></h3>
<ul>
<li><a href="http://www.wiili.org/index.php/Wiimote" target="_blank">WiiLi Wiki</a>
</li><li><a href="http://www.wiibrew.org/index.php?title=Wiimote" target="_blank">WiiBrew Wiki</a>
</li><li><a href="http://www.vsj.co.uk/articles/display.asp?id=600" target="_blank">Making USB C# Friendly</a>
</li><li><a href="http://www.pinvoke.net/" target="_blank">P/Invoke Wiki</a> </li><li><a href="http://www.brianpeek.com/blogs/pages/net-based-wiimote-applications.aspx" target="_blank">Applications Using This Library</a></li></ul>
<h3>Bio</h3>
<p>Brian is a <a href="https://mvp.support.microsoft.com/profile/Brian.Peek">Microsoft C# MVP</a> who has been actively developing in .NET since its early betas in 2000, and who has been developing solutions using Microsoft technologies and platforms for even
 longer. Along with .NET, Brian is particularly skilled in the languages of C, C&#43;&#43; and assembly language for a variety of CPUs. He is also well-versed in a wide variety of technologies including web development, document imaging, GIS, graphics, game development,
 and hardware interfacing. Brian has a strong background in developing applications for the health-care industry, as well as developing solutions for portable devices, such as tablet PCs and PDAs. Additionally, Brian has co-authored the book &quot;<a href="http://www.amazon.com/dp/0735711410/">Debugging
 ASP.NET</a>&quot; published by New Riders, and is currently co-authoring a book titled &quot;<a href="http://www.amazon.com/exec/obidos/ASIN/0596520743/brianpcom-20">10 Coding4Fun Projects with .NET for Programmers, Hobbyists, and Game Developers</a>&quot; to be published
 by <a href="http://www.oreilly.com/">O'Reilly</a> in late 2008. Brian also writes for MSDN's
<a href="http://blogs.msdn.com/coding4fun/">Coding4Fun</a> website, contributing articles on a monthly basis.
</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:5dee6dc9857b45c1abf49e7600d4fe73">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Managed-Library-for-Nintendos-Wiimote</comments>
      <itunes:summary>



&amp;nbsp;
In this article, Brian Peek demonstrates how to connect to and use the Nintendo Wiimote from C# and VB.NET. The final output is an easy-to-use managed API for the Wiimote that can be used in any managed application.



Brian Peek
ASPSOFT, Inc.

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Less Than $50 (Free if you already own a Wiimote)
Software: Visual C# or Visual Basic 2008 Express Editions
Hardware: Nintendo Wii Remote (Wiimote), a compatible PC Bluetooth adapter and stack
Download: CodePlex

&amp;nbsp;




Updates
1/19/09 - Version 1.7 now up at 
CodePlex. 
 
6/15/08 – Version 1.5.2 is now up at 
CodePlex.&amp;nbsp; The Balance Board should really work this time…. 
6/12/08 - Version 1.5.1 has been removed from CodePlex...it has proven to be too buggy for most users (though it continues to work just fine for me).&amp;nbsp; Look for version 1.5.2 soon...

 
6/11/08 – Version 1.5.1 posted at 
CodePlex.&amp;nbsp; Fixed a bug with the Balance Board…&amp;nbsp; UPDATE:&amp;nbsp; It appears some people are still having issues with this build as well due to some Balance Boards being a bit finicky in their response times.&amp;nbsp; Stay tuned for build 1.5.2 soon… 
6/9/08 – Version 1.5 posted at 
CodePlex.&amp;nbsp; The 
Wii Fit Balance Board is now supported. 
6/3/08 – New version 1.4 posted at the download link above.&amp;nbsp; The big change is multiple Wiimotes are now finally supported. 
5/27/08 - New version 1.3 posted at the download link above.&amp;nbsp; Lots of changes, so be sure to read the included docs! 
1/29/08 - New version 1.2.1.0 posted at the download link above.&amp;nbsp; The only change for this release is adding support for IR3 and IR4 since I&#39;ve gotten so many questions about it.
 
10/22/07 - New version 1.2.0.0 posted at the download link above.&amp;nbsp; There are a variety of fixes and new features added.&amp;nbsp; The source code and binary releases are now hosted at CodePlex.&amp;nbsp; A .chm help file is also included documenting the API itself.&amp;nbsp;
 Please note that a lic</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Managed-Library-for-Nintendos-Wiimote</link>
      <pubDate>Wed, 14 Mar 2007 05:05:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Managed-Library-for-Nintendos-Wiimote</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1879033_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1879033_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>25</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Managed-Library-for-Nintendos-Wiimote/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>Hardware</category>
      <category>Windows</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Hardware Boneyard - Using the CueCat with .NET</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td><span class="entry_description">In this installment of &quot;Some Assembly Required&quot; column, Scott Hanselman borrows Travis Illig's CueCat BarCode scanner and creates a plugin for Windows Live Writer than lets him blog more easily about books he's reading. We
 decode the bar code info, change UPCs into ISBNs, call Amazon's Web Service via REST and integrate with Windows Live Writer all in one article. Whew!</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Scott Hanselman</div>
<div class="entry_company"><a href="http://www.hanselman.com/blog/">Scott's Blog</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Easy</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
Less than 1 hour</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Less Than $50</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">A CueCat - try eBay or your garage</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=288404">Download</a>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p><strong><img height="114" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815618/180pxCuecat14.jpg" width="180" align="right" border="0"> Summary:</strong> In this installment of &quot;Some Assembly Required&quot; column, Scott Hanselman borrows Travis Illig's CueCat
 BarCode scanner and creates a plugin for Windows Live Writer than lets him blog more easily about books he's reading. We decode the bar code info, change UPCs into ISBNs, call Amazon's Web Service via REST and integrate with Windows Live Writer all in one
 article. Whew!</p>
<h3><strong>The CueCat BarCode Scanner</strong></h3>
<p>Here's what Wikipedia has to say about the CueCat BarCode scanner:</p>
<blockquote>
<p><em>The :CueCat is a cat-themed handheld barcode reader developed in the late 1990s by the now-defunct DigitalConvergence Corporation, which connected to computers using the PS/2 keyboard port and later USB. The :CueCat enabled users to link to an Internet
 URL by scanning a barcode appearing in an article, catalog or on some other printed matter. In this way a user could be directed to a web page containing related information. The system that supported this functionality is no longer in operation.</em></p>
</blockquote>
<p>Ah, nothing like the smell of obsolete hardware to get me thinking. You can get CueCats all over, there are millions of them, including on
<a href="http://search.ebay.com/search/search.dll?sofocus=unknown&amp;sbrftog=1&amp;from=R10&amp;satitle=cuecat&amp;sacat=-1%26catref%3DC6&amp;sargn=-1%26saslc%3D2&amp;sadis=200&amp;fpos=ZIP%2FPostal&amp;ftrt=1&amp;ftrv=1&amp;saprclo=&amp;saprchi=&amp;fsop=1%26fsoo%3D1&amp;coaction=compare&amp;copagenum=1&amp;coentrypage=search">
ebay</a>. I asked around and my buddy <a href="http://www.paraesthesia.com/blog/weblog.php">
Travis Illig</a> loaned me his. It's ripe for hacking.</p>
<h3><strong>Decoding the CueCat Output</strong></h3>
<p>The CueCat speaks a funky encoded format that it &quot;types&quot; as if it were a keyboard. For all intents, it IS a keyboard as the PS2 version we're using is installed in series with your existing (if you have one) keyboard.</p>
<p>For example, my copy of Neil Gaiman's excellent &quot;Stardust&quot; produces this output:</p>
<blockquote>
<p>.C3nZC3nZC3nZE3r0Chr3CNnY.cGf2.ENr7C3n1C3PWD3rYCxzYChnZ.</p>
</blockquote>
<p>Which can be broken up into a series of tokens, some are one character and some are two. The periods are delimiters, so we'll toss them for now.</p>
<blockquote>
<p>&nbsp;C3 n Z C3 n Z C3 n Z E3 r 0 Ch r 3 CN n Y EN r 7 C3 n 1 C3 P W D3 r Y Cx z Y Ch n Z</p>
</blockquote>
<p>The first part is the serial number of CueCat itself, which freaked a log of privacy folks out in the past. The scanned barcode is actually the last part after the third . delimiter:</p>
<blockquote>
<p>EN r 7 C3 n 1 C3 P W D3 r Y Cx z Y Ch n Z</p>
</blockquote>
<p>Each of these tokens&nbsp;is a key to a lookup table. The encoding is pretty lame, and very arbitrary, but it confounded folks for a few hours at least. There's dozens of implementations of this decoding to be found on the Web, although none in .NET, which is
 where we come in. Here's a resource page that includes several implementations in C, Perl and Python,
<a href="http://www.beau.lib.la.us/~jmorris/linux/cuecat/">http://www.beau.lib.la.us/~jmorris/linux/cuecat/</a>&nbsp;but it hasn't been updated in at least six years. There's also some very old but interesting discussion here
<a href="http://cexx.org/cuecat.htm">http://cexx.org/cuecat.htm</a>.</p>
<p>The lookup table looks like this (a C# example):</p>
<div>
<p><span>static</span> Decoder()</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable = <span>new</span> <span>Dictionary</span>&lt;<span>string</span>,
<span>int</span>&gt;[3];</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0] = <span>new</span> <span>Dictionary</span>&lt;<span>string</span>,
<span>int</span>&gt;();</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1] = <span>new</span> <span>Dictionary</span>&lt;<span>string</span>,
<span>int</span>&gt;();</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2] = <span>new</span> <span>Dictionary</span>&lt;<span>string</span>,
<span>int</span>&gt;();</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;Z&quot;</span>] = 0;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;Y&quot;</span>] = 1;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;X&quot;</span>] = 2;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;W&quot;</span>] = 3;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;3&quot;</span>] = 4;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;2&quot;</span>] = 5;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;1&quot;</span>] = 6;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;0&quot;</span>] = 7;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;7&quot;</span>] = 8;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[0][<span>&quot;6&quot;</span>] = 9;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;C3&quot;</span>] = 0;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;CN&quot;</span>] = 1;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;Cx&quot;</span>] = 2;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;Ch&quot;</span>] = 3;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;D3&quot;</span>] = 4;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;DN&quot;</span>] = 5;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;Dx&quot;</span>] = 6;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;Dh&quot;</span>] = 7;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;E3&quot;</span>] = 8;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[1][<span>&quot;EN&quot;</span>] = 9;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;n&quot;</span>] = 0;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;j&quot;</span>] = 1;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;f&quot;</span>] = 2;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;b&quot;</span>] = 3;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;D&quot;</span>] = 4;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;z&quot;</span>] = 5;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;v&quot;</span>] = 6;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;r&quot;</span>] = 7;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;T&quot;</span>] = 8;</p>
<p>&nbsp;&nbsp;&nbsp; decodingTable[2][<span>&quot;P&quot;</span>] = 9;</p>
<p>}</p>
<p>&nbsp;</p>
<p><span>private</span> <span>static</span> <span>Dictionary</span>&lt;<span>string</span>,
<span>int</span>&gt;[] decodingTable;</p>
</div>
<p><strong></strong></p>
<p>See how some tokens are two chars and some are one? We'll run through the tokens testing to see if they are in each dictionary and creating the result. For my Gaiman book, we end up with:</p>
<p>978006093471251300</p>
<p>Now what do we do with it?</p>
<h3><strong>UPCs and ISBN</strong></h3>
<p>Universal Product Codes or UPCs are different from ISBNs. This page at the <a href="http://www.eblong.com/zarf/bookscan/#convert">
Book-Scanning Project</a>&nbsp;gave me the&nbsp;algorithm I needed to convert&nbsp;a UPC code into an ISBN that I could use to talk to Amazon.com. Most books have a bar code with 13 digits starting with &quot;978.&quot; Turns out that the first 3 digits of a UPC are the country of
 origin, but &quot;978&quot; is &quot;Bookland.&quot; Apparently the UPC number for a book is called the &quot;Bookland EAN.&quot;</p>
<p>Here's the Javascript taken from <a href="http://isbn.nu/">http://isbn.nu</a>.</p>
<p>if (indexisbn.indexOf(&quot;978&quot;) == 0) {<br>
&nbsp;&nbsp; isbn = isbn.substr(3,9);<br>
&nbsp;&nbsp; var xsum = 0;<br>
&nbsp;&nbsp; var add = 0;<br>
&nbsp;&nbsp; var i = 0;<br>
&nbsp;&nbsp; for (i = 0; i &lt; 9; i&#43;&#43;) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add = isbn.substr(i,1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xsum &#43;= (10 - i) * add;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; xsum %= 11;<br>
&nbsp;&nbsp; xsum = 11 - xsum;<br>
&nbsp;&nbsp; if (xsum == 10) { xsum = &quot;X&quot;; }<br>
&nbsp;&nbsp; if (xsum == 11) { xsum = &quot;0&quot;; }<br>
&nbsp;&nbsp; isbn &#43;= xsum;<br>
}</p>
<p>Now, converted into C#</p>
<div>
<p><span>public</span> <span>static</span> <span>string</span> ConvertUPCtoISBN(<span>string</span> code)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; <span>if</span> (code.StartsWith(<span>&quot;978&quot;</span>) == <span>false</span>)</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>throw</span> <span>new</span> <span>ArgumentOutOfRangeException</span>(<span>&quot;UPCs that might be books have length 13 and start with 978&quot;</span>);</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; code = code.Substring(3,9);</p>
<p>&nbsp;&nbsp;&nbsp; <span>int</span> xsum = 0;</p>
<p>&nbsp;&nbsp;&nbsp; <span>for</span> (<span>int</span> i = 0; i &lt; 9; i&#43;&#43;)</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; xsum &#43;= (10 - i) * <span>int</span>.Parse(code[i].ToString());</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; xsum %= 11;</p>
<p>&nbsp;&nbsp;&nbsp; xsum = 11 - xsum;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; <span>String</span> val = xsum.ToString();</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; <span>switch</span> (xsum)</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>case</span> 10: val = <span>&quot;X&quot;</span>; <span>break</span>;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>case</span> 11: val = <span>&quot;0&quot;</span>; <span>break</span>;</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; code &#43;= val;</p>
<p>&nbsp;&nbsp;&nbsp; <span>return</span> code; <span>//Now an ISBN</span></p>
<p>&nbsp;}</p>
</div>
<p>So, my Gaiman UPC of&nbsp;978006093471251300&nbsp;turns into an ISBN of 0060934719. This ISBN can be used to talk to Amazon. Note that the source code to this article includes both C# and VB.</p>
<h2><strong>Calling Amazon's REST Web Service</strong></h2>
<p>Amazon.com has a rich <a href="http://www.amazon.com/b?ie=UTF8&amp;node=3435361">Web Services platform</a>&nbsp;that includes formal SOAP-based Web Services, but for our project, their HTTP GET-based system will work nicely. I visited the
<a href="http://www.amazon.com/b?ie=UTF8&amp;node=3435361">Amazon Web Services Home Page</a>&nbsp;and applied for a free Amazon Web Service Developer Key. You'll need to do the same if you want to get the code to work. Amazon has some create documentation on&nbsp;their site
 that makes this really easy.</p>
<p>I'll make an HTTP GET call to Amazon like this (broken up for readability):</p>
<blockquote>
<p><em>http://webservices.amazon.com/onca/xml?<br>
Service=AWSECommerceService&amp;<br>
AWSAccessKeyId=<strong>YOURAWSKEYHERE</strong>&amp;<br>
Operation=ItemLookup&amp;<br>
ItemId=<strong>0060934719</strong>&amp;<br>
IdType=ASIN</em></p>
</blockquote>
<p>This HTTP GET will result in an XML document as seen in this screenshot.</p>
<p>&nbsp;<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815618/hanselmancuecataws4.png"><img height="398" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815618/hanselmancuecataws_thumb2.png" width="450"></a>
</p>
<p>Ah! Just the kind of information I was looking for.</p>
<h3><strong>A CueCatConsole</strong></h3>
<p>Before we integrate with Windows Live Writer, let's make a little test console to make sure this all works together. I put the CueCatDecoder into a small reusable assembly and called it from the Console Application. I also pull the Amazon Web Services key
 from the configuration file. Note that VS.NET 2005 creates a strongly typed accessor for the &quot;AWSAccessKeyId&quot; automatically.</p>
<p>I've removed the error handling in this listing for clarity. </p>
<div>
<p>CueCatDecoder.<span>Product</span> product = <span>null</span>;</p>
<p>product = CueCatDecoder.<span>Decoder</span>.Decode(input);</p>
<p><span>Console</span>.WriteLine(<span>&quot;Type: {0}.&quot;</span>, product.Type.ToString());</p>
<p><span>string</span> amazonType = <span>&quot;ASIN&quot;</span>;</p>
<p><span>string</span> amazonUrl = <span>String</span>.Format(<span>&quot;http://webservices.amazon.com/onca/xml<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?Service=AWSECommerceService&amp;AWSAccessKeyId={0}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;Operation=ItemLookup&amp;ItemId={1}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;IdType={2}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;SearchIndex=&quot;</span>,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Properties.<span>Settings</span>.Default.AWSAccessKeyId,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; product.ID,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; amazonType);</p>
<p>&nbsp;</p>
<p>System.Net.<span>WebClient</span> web = <span>new</span> <span>WebClient</span>();</p>
<p><span>string</span> amazonData = web.DownloadString(amazonUrl);</p>
<p><span>XmlDocument</span> xmlDocument = <span>new</span> <span>XmlDocument</span>();</p>
<p><span>XmlNamespaceManager</span> xnm = <span>new</span> <span>XmlNamespaceManager</span>(xmlDocument.NameTable);</p>
<p>xnm.AddNamespace(<span>&quot;def&quot;</span>, <span>&quot;http://webservices.amazon.com/AWSECommerceService/2005-10-05&quot;</span>);</p>
<p>xmlDocument.Load(<span>new</span> System.IO.<span>StringReader</span>(amazonData));</p>
<p><span>XmlNode</span> itemNode = xmlDocument.SelectSingleNode(<span>&quot;/def:ItemLookupResponse/def:Items/def:Item&quot;</span>, xnm);</p>
<p><span>Console</span>.WriteLine(<span>String</span>.Format(<span>&quot;FOUND a {0} called {1} by {2}&quot;</span>,
</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; itemNode.SelectSingleNode(<span>&quot;//def:ProductGroup&quot;</span>, xnm).InnerText,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; itemNode.SelectSingleNode(<span>&quot;//def:Title&quot;</span>, xnm).InnerText,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; itemNode.SelectSingleNode(<span>&quot;//def:Author&quot;</span>, xnm).InnerText));</p>
</div>
<p>Notice that since the Amazon XML includes a default namespace, we have to let SelectSingleNode know about that namespace by registering a namespace prefix - in this case &quot;def:&quot; - that we use later in our XPath. There are many ways to query XML within the
 .NET Base Class Library that are faster, but for a small application like this the XmlDocument is a reasonable choice when performance doesn't matter.</p>
<p>Here's the output from my CueCatConsole:</p>
<blockquote>
<p>Coding4Fun: CueCatDecoder by Scott Hanselman @ <a href="http://www.hanselman.com/">
http://www.hanselman.com</a><br>
Scan item with CueCat now or press Q then Enter to exit<br>
.C3nZC3nZC3nZE3r0Chr3CNnY.cGen.ENr7C3T7D3f0C3vYDW.<br>
Type: ISBN.<br>
FOUND a Book called The Goal: A Process of Ongoing Improvement by Eliyahu M. Goldratt<br>
Scan item with CueCat now or press Q then Enter to exit<br>
.C3nZC3nZC3nZE3r0Chr3CNnY.cGf2.ENr7CNz6C3z6DxvXChzXD3P6.<br>
Type: ISBN.<br>
FOUND a Book called Programming Sudoku (Technology in Action) by Wei-Meng Lee<br>
Scan item with CueCat now or press Q then Enter to exit<br>
.C3nZC3nZC3nZE3r0Chr3CNnY.cGf2.ENr7C3n1C3PWD3rYCxzYChnZ.<br>
Type: ISBN.<br>
FOUND a Book called Stardust by Neil Gaiman<br>
Scan item with CueCat now or press Q then Enter to exit</p>
</blockquote>
<p>Fantastic. It works. Let's integrate it with Windows Live Writer, the new Offline Blogging Editor in BETA (at the time of this writing) from
<a href="http://www.live.com/">http://www.live.com</a>.</p>
<h3><strong>Integrating with Windows Live Writer</strong></h3>
<p>Windows Live Writer (<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815618/Writer.msi">download</a>) is a new desktop application that folks with blogs can use to write their blog posts offline. I use
<a href="http://www.dasblog.info/">DasBlog</a>&nbsp;for my blog at <a href="http://www.hanselman.com/">
http://www.hanselman.com</a>, and since DasBlog supports the standard MetaWebLog API also supported by Live Writer, I was in&nbsp;business right away.
</p>
<p>Windows Live Writer&nbsp;<a href="http://g.msn.com/8SEENUS030000TBR/WriterSDK">also has an SDK</a>&nbsp;that supports &quot;Content Source Plugins&quot; to extend the capabilities of the application and let folks insert new kinds of data. That's exactly what I want to do! I'd
 like to click &quot;Blog about Book&quot; and have the book title and author appear linked with an image of the book cover. I'd also like have the Amazon.com URL to include my Amazon Associates ID so I could make a few cents if someone clicks my link and buys the book.</p>
<p>Writing a plugin for Windows Live Writer couldn't be easier. The SDK includes step-by-step instructions. I created a class that derived from WindowsLive.Writer.Api.ContentSource and overrode the CreateContent method, returning my new snippet of HTML in the
 newContent string variable.</p>
<p>Here's the gist of the source, again with error handling removed for clarity. VB is included in the download.</p>
<div>
<p><span>using</span> System;</p>
<p><span>using</span> System.Collections.Generic;</p>
<p><span>using</span> System.Windows.Forms;</p>
<p><span>using</span> WindowsLive.Writer.Api;</p>
<p><span>using</span> CueCatDecoder;</p>
<p>&nbsp;</p>
<p><span>namespace</span> AmazonLiveWriterPlugin</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; [<span>WriterPlugin</span>(<span>&quot;605EEA63-B74B-4e9d-A290-F5E9E8229FC1&quot;</span>,
<span>&quot;Amazon Links with CueCat&quot;</span>,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ImagePath = <span>&quot;Images.CueCat.png&quot;</span>,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; PublisherUrl = <span>&quot;http://www.hanselman.com&quot;</span>,</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Description = <span>&quot;Amazon Links with a CueCat.&quot;</span>)]</p>
<p>&nbsp;&nbsp;&nbsp; [<span>InsertableContentSource</span>(<span>&quot;Amazon Links&quot;</span>)]</p>
<p>&nbsp;&nbsp;&nbsp; <span>public</span> <span>class</span> <span>Plugin</span> : <span>ContentSource</span></p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>const</span> <span>string</span> AMAZONASSOCIATESID = <span>&quot;amazonassociatesid&quot;</span>;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>const</span> <span>string</span> AMAZONWEBSERVICESID = <span>&quot;amazonwebservicesid&quot;</span>;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>public</span> <span>override</span> System.Windows.Forms.<span>DialogResult</span> CreateContent(System.Windows.Forms.<span>IWin32Window</span> dialogOwner,
<span>ref</span> <span>string</span> newContent)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>using</span>(<span>InsertForm</span> form = <span>new</span>
<span>InsertForm</span>())</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; form.AmazonAssociatesID = <span>this</span>.Options[AMAZONASSOCIATESID];</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; form.AmazonWebServicesID = <span>this</span>.Options[AMAZONWEBSERVICESID];</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>DialogResult</span> result = form.ShowDialog();</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>if</span> (result == <span>DialogResult</span>.OK)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>this</span>.Options[AMAZONASSOCIATESID] = form.AmazonAssociatesID;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>this</span>.Options[AMAZONWEBSERVICESID] = form.AmazonWebServicesID;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Product</span> p = <span>Decoder</span>.Decode(form.CueCatData);</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>AmazonBook</span> book = <span>AmazonBookPopulator</span>.CreateAmazonProduct(p, form.AmazonWebServicesID);</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>string</span> associatesId = form.AmazonAssociatesID.Trim();</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>string</span> builtAmazonUrl = <span>&quot;&lt;a href=\&quot;http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/{0}&amp;tag={1}&amp;camp=1789&amp;creative=9325\&quot;&gt;{2} by {3}&lt;/a&gt;&lt;a href=\&quot;http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/{0}&amp;tag={1}&amp;camp=1789&amp;creative=9325\&quot;&gt;&lt;img
 border=\&quot;0\&quot; src=\&quot;http://images.amazon.com/images/P/{0}.01._AA_SCMZZZZZZZ_.jpg\&quot;&gt;&lt;/a&gt;&lt;img src=\&quot;http://www.assoc-amazon.com/e/ir?t={1}&amp;l=as2&amp;o=1&amp;a={0}\&quot; width=\&quot;1\&quot; height=\&quot;1\&quot; border=\&quot;0\&quot; alt=\&quot;\&quot; style=\&quot;border:none !important; margin:0px !important;\&quot;
 /&gt;&quot;</span>;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; newContent = <span>string</span>.Format(builtAmazonUrl, book.ID, associatesId, book.Title, book.Author);</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>return</span> result;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
</div>
<p>Notice the crazy Amazon.com URL. Most folks with blogs become <a href="http://associates.amazon.com/">
Amazon Associates</a>&nbsp;to make a little money to pay for hosting (you won't get rich doing this, believe me). The Amazon Associates site includes link builders that create these complex snippets of HTML. I selected the large image, basic HTML option, then inserted
 String.Format tokens like {0} in the appropriate places.</p>
<p>Installation is simple, just copy Coding4Fun.AmazonLiveWriterPlugin.dll and Coding4Fun.CueCatDecoder.dll&nbsp;to C:\Program Files\Windows Live Writer\Plugins and they will be automatically detected.
</p>
<p>Our plugin appears automatically in the Windows Live Writer sidebar. Notice the text and the icon was picked up from the Plugin class attributes. My Amazon Web Services ID and Associates ID are both stored internally by an Options bag managed by Windows
 Live Writer, making management of preferences very easy for the plugin developer. Once the CueCat data is scanned, we decode it and make the HTTP GET Web Services call using our external CueCat assembly created earlier.</p>
<p>&nbsp;<img height="616" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815618/hanselmancuecatplugin5.png" width="685">
</p>
<h3><strong>Conclusion</strong></h3>
<p>There's things that could be&nbsp;extended, added,&nbsp;and improved on with this project.&nbsp;Here are&nbsp;some ideas to get you started:</p>
<ul>
<li>Include support for CDs and other products available on Amazon. </li><li>Add support for more web-based databases with UPC codes. </li><li>Support different Amazon&nbsp;link styles.&nbsp; </li><li>Create a system to print out product tags for a Garage Sale.</li></ul>
<p>Have fun and have no fear when faced with the words - Some Assembly Required!</p>
<hr>
<p>Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C&#43;&#43;, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture
 MVP. He is co-author of Professional ASP.NET 2.0&nbsp;with Bill Evjen, available on BookPool.com and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at
<a href="http://www.computerzen.com/">http://www.computerzen.com</a>.&nbsp;He thanks his wife and&nbsp;son Zenzo for indulging him in these hobbies!</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:72d8c323143f4f84b5399e7600d55096">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Hardware-Boneyard-Using-the-CueCat-with-NET</comments>
      <itunes:summary>



&amp;nbsp;
In this installment of &amp;quot;Some Assembly Required&amp;quot; column, Scott Hanselman borrows Travis Illig&#39;s CueCat BarCode scanner and creates a plugin for Windows Live Writer than lets him blog more easily about books he&#39;s reading. We
 decode the bar code info, change UPCs into ISBNs, call Amazon&#39;s Web Service via REST and integrate with Windows Live Writer all in one article. Whew!



Scott Hanselman
Scott&#39;s Blog

Difficulty: Easy
Time Required: 
Less than 1 hour
Cost: Less Than $50
Software: Visual Basic or Visual C# Express Editions
Hardware: A CueCat - try eBay or your garage
Download: Download






 Summary: In this installment of &amp;quot;Some Assembly Required&amp;quot; column, Scott Hanselman borrows Travis Illig&#39;s CueCat
 BarCode scanner and creates a plugin for Windows Live Writer than lets him blog more easily about books he&#39;s reading. We decode the bar code info, change UPCs into ISBNs, call Amazon&#39;s Web Service via REST and integrate with Windows Live Writer all in one
 article. Whew! 
The CueCat BarCode Scanner
Here&#39;s what Wikipedia has to say about the CueCat BarCode scanner: 

The :CueCat is a cat-themed handheld barcode reader developed in the late 1990s by the now-defunct DigitalConvergence Corporation, which connected to computers using the PS/2 keyboard port and later USB. The :CueCat enabled users to link to an Internet
 URL by scanning a barcode appearing in an article, catalog or on some other printed matter. In this way a user could be directed to a web page containing related information. The system that supported this functionality is no longer in operation. 

Ah, nothing like the smell of obsolete hardware to get me thinking. You can get CueCats all over, there are millions of them, including on

ebay. I asked around and my buddy 
Travis Illig loaned me his. It&#39;s ripe for hacking. 
Decoding the CueCat Output
The CueCat speaks a funky encoded format that it &amp;quot;types&amp;quot; as if it were a keyboard. For all intents, it IS a keyboard as </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Hardware-Boneyard-Using-the-CueCat-with-NET</link>
      <pubDate>Tue, 06 Mar 2007 06:26:53 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Hardware-Boneyard-Using-the-CueCat-with-NET</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1815618_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1815618_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Scott Hanselman</dc:creator>
      <itunes:author>Scott Hanselman</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Hardware-Boneyard-Using-the-CueCat-with-NET/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Web Services</category>
      <category>hardwarehacks</category>
      <category>hardware miscellaneous</category>
    </item>
  <item>
      <title>Don&#39;t touch me! - Interfacing with a Fingerprint Reader</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td><span class="entry_description">In this installment of the &quot;Some Assembly Required&quot; column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the Microsoft Fingerprint Reader and the GrFinger SDK from Griaule.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Scott Hanselman</div>
<div class="entry_company"><a href="http://www.hanselman.com/blog/">Scott's Blog</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">$50-$100</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://www.griaule.com/page/en-us/grfinger_fingerprint_sdk">GrFinger</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">Microsoft FingerPrint Reader</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=288397">Download</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p><em>Scott Hanselman</em></p>
<p><strong>Summary:</strong> In this installment of the &quot;Some Assembly Required&quot; column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the
<a href="http://www.microsoft.com/hardware/mouseandkeyboard/productlist.aspx?type=Fingerprint">
Microsoft Fingerprint Reader</a> and the <a href="http://www.griaule.com/page/en-us/grfinger_sdk">
GrFinger SDK from Griaule</a>.</p>
<h3><strong>The Microsoft Fingerprint Reader</strong></h3>
<p><strong></strong></p>
<p><img height="240" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815291/fingerprintreader18.jpg" width="196" align="right"></p>
<p>I love my Microsoft Fingerprint Reader and when I got it I knew I had to <strike>
hack it</strike> write some software for it. Since there's already a lot of great security software out there like the Digital Persona software that Microsoft shipped with it as well as 3rd party software like
<a href="http://www.griaule.com/page/en-us/desktop_identity">GrFinger's Desktop Identity</a>, I wanted to write something a little different.</p>
<p>My wife and I made a <a href="http://www.hanselman.com/blog/2006ResolutionPrepare.aspx">
New Year's Resolution to be more prepared for emergencies</a> and the like in the wake of Hurricane Katrina. I figured, since we've moved all our identification and important papers into the a safety deposit box, why not a copy of our fingerprints as well?
</p>
<p>There are do-it-yourself-at-home fingerprinting kits one can buy, but I had this nice Fingerprint&nbsp;Reader lying around....<img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' /></p>
<h3><strong>Interfacing with the Reader</strong></h3>
<p><a href="http://www.griaule.com/page/en-us/grfinger_sdk">Griaule Software</a> out of Brazil has a nice, clean
<a href="http://www.griaule.com/page/en-us/grfinger_sdk">COM API SDK</a> that abstracts away the fingerprint hardware supporting a
<a href="http://www.griaule.com/page/en-us/grfinger_sdk#reader">number of readers</a>&nbsp;including Microsoft's. You can download a trial of
<a href="http://www.griaule.com/page/en-us/downloads">their SDK software and use it for 90 days</a>. They also include an open-source driver for the Microsoft Fingerprint Reader so you don't have to use the Digital Persona standard stuff if you don't want to.
 They've got an excellent sample code section with details on how to interface with a read using VB.NET, C#, Java, VB6, even Excel.</p>
<p><img height="296" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815291/controlproperties18.png" width="522">
</p>
<p>I started by adding references to their COM APIs and generating an interop assembly as seen in the picture at left. The AxGrFinger control library includes a small control that you can drag on to your WinForms design surface that exposes a number of Fingerprint-related
 events like FingerDown and ImageRequired that make interfacing with the hardware incredibly easy.</p>
<p><img height="248" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815291/references10.png" width="262" align="right">I created a PictureBox on my WinForm that would display the fingerprint being acquired along with ten other
 PictureBoxes, one for each finger. The large picture box will appear only when an image is being acquired then disappear after we copy the large acquired image into one of the smaller &quot;fingertip&quot; images.</p>
<p>The large PictureBox is passed in to a utility class along with a reference to the AxGrFinger control. As the image is acquired a valid &quot;Handle to a Device Context&quot; or HDC (remember those?) is passed into the CapRawImageToHandle method on the AxGrFinger
 control. When that handle comes back, we just update the large picture box and it displays the newly received image. Once the image has move into the world of WinForms, it's considerably easier to manipulate using the System.Drawing APIs.</p>
<div>
<p>&nbsp;&nbsp;&nbsp; <span>' Display fingerprint image on screen</span></p>
<p>&nbsp;&nbsp;&nbsp; <span>Public</span> <span>Sub</span> PrintBiometricDisplay()</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>' handle to finger image</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> handle <span>As</span> System.Drawing.Image = <span>Nothing</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>' screen HDC</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> hdc <span>As</span> <span>Integer</span> = GetDC(0)</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>' get raw image</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _GrFingerX.CapRawImageToHandle(raw.img, raw.width, raw.height, hdc, handle)</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>' draw image on picture box</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> <span>Not</span> (handle <span>Is</span> <span>Nothing</span>)
<span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _pbPic.Image = handle</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _pbPic.Update()</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>' release screen HDC</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ReleaseDC(0, hdc)</p>
<p>&nbsp;&nbsp;&nbsp; <span>End</span> <span>Sub</span></p>
</div>
<p>The images from the large picture box are of very high quality and are copied into the smaller fingers one at a&nbsp;time.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815291/maininterface10.png" target="_new"><img height="432" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1815291/maininterface_thumb4.png" width="600"></a>
</p>
<h3><strong>Loading and Saving the Fingerprints</strong></h3>
<p>There's ten fingerprints (assuming you have ten fingers) to save, but should we save them as one file or ten? I decided that folks would probably want one file per family member using File|Open and File|Save method, but they'd want to reserve the right to
 export all the fingers as individual (PNG) images.</p>
<p>I created a very simple in-memory representation of a Fingerprint Database like this. It's actually slightly&nbsp;more complex with custom constructors as such in the actual code, but this is the general idea. I'm going to be storing the high-quality image as
 a byte array rather than a System.Drawing.Bitmap or Image because a byte array is very easily serialized as XML.
</p>
<div>
<p>&nbsp;&nbsp;&nbsp; <span>Public</span> <span>Class</span> Fingerprints</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Public</span> FingerImages(10) <span>As</span> FingerImage</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Public</span> <span>Sub</span> <span>New</span>()</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>For</span> i <span>As</span> <span>Integer</span> = 0 <span>
To</span> 10</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; FingerImages(i) = <span>New</span> FingerImage()</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Next</span> i</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>Sub</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Public</span> <span>Sub</span> AddFingerImage(<span>ByVal</span> finger
<span>As</span> <span>String</span>, <span>ByVal</span> image() <span>As</span> <span>
Byte</span>)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> i <span>As</span> Int32 = Int32.Parse(finger)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; FingerImages(i - 1) = <span>New</span> FingerImage(image, finger)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>Sub</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Public</span> <span>Function</span> GetImageFromFinger(<span>ByVal</span> finger
<span>As</span> <span>String</span>) <span>As</span> <span>Byte</span>()</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>For</span> <span>Each</span> fi <span>As</span> FingerImage <span>
In</span> <span>Me</span>.FingerImages</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> (fi.Finger = finger) <span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Return</span> fi.Image</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Next</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Return</span> <span>Nothing</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>Function</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; <span>End</span> <span>Class</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; <span>Public</span> <span>Class</span> FingerImage</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>Public </span>_image() <span>As</span> <span>Byte</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>Public </span>_finger <span>As</span> <span>String</span></p>
<p>&nbsp;&nbsp;&nbsp; <span>End</span> <span>Class</span></p>
</div>
<p>Each per-person finger database, like scott.finger for example, will be saved as XML similar to the example below. The byte[] is automatically turned into a BASE64'ed string by the XmlSerializer. This might be considered inelegant by some, but disk space
 is cheap, and the code was fantastically simple. An easy enhancement would ZIP up the file,&nbsp;but the savings would only be about 30-40%.</p>
<blockquote>
<p>&lt;?xml version=&quot;1.0&quot;?&gt;<br>
&lt;Fingerprints xmlns:xsi=&quot;<a href="http://www.w3.org/2001/xmlschema-instance">http://www.w3.org/2001/XMLSchema-instance</a>&quot; xmlns:xsd=&quot;<a href="http://www.w3.org/2001/xmlschema">http://www.w3.org/2001/XMLSchema</a>&quot;&gt;<br>
&nbsp; &lt;FingerImages&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;FingerImage&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Image&gt;iVBOR...big opaque BASE64'ed image&lt;/Image&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Finger&gt;L1&lt;/Finger&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/FingerImage&gt;<br>
&lt;/FingerPrints&gt;</p>
</blockquote>
<p>Loading the fingers back into the Form is the exact opposite of saving. We use&nbsp;a standard Windows File Dialog with the filter set to show only .finger files. The file is deserialized using the XmlSerializer and the images are loaded back into the appropriate
 PictureBox. </p>
<div>
<p>&nbsp;&nbsp; <span>Private</span> <span>Sub</span> MenuLoad_Click(<span>ByVal</span> sender
<span>As</span> System.Object, <span>ByVal</span> e <span>As</span> System.EventArgs)
<span>Handles</span> MenuLoad.Click</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> OpenFileDialog1 <span>As</span> <span>New</span> OpenFileDialog</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>'' open &quot;load&quot; dialog</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OpenFileDialog1.Filter = <span>&quot;FINGER files (*.finger)|*.finger|All files (*.*)|*.*&quot;</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OpenFileDialog1.FilterIndex = 1</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OpenFileDialog1.RestoreDirectory = <span>True</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OpenFileDialog1.CheckFileExists = <span>True</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>'' load image</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK
<span>Then</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> x <span>As</span> <span>New</span> XmlSerializer(<span>GetType</span>(Fingerprints))</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> newdb <span>As</span> Fingerprints</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Using</span> fs <span>As</span> FileStream = File.OpenRead(OpenFileDialog1.FileName)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; newdb = <span>CType</span>(x.Deserialize(fs), Fingerprints)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>Using</span></p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>For</span> <span>Each</span> item <span>As</span> Control <span>
In</span> <span>Me</span>.Controls</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> IsFingerprintPictureBox(item) <span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> pic <span>As</span> PictureBox = <span>CType</span>(item, PictureBox)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> b <span>As</span> <span>Byte</span>() = newdb.GetImageFromFinger(pic.Tag)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> (<span>Not</span> b <span>Is</span> <span>
Nothing</span>) <span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pic.Image = Image.FromStream(<span>New</span> MemoryStream(b))</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Next</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; <span>End</span> <span>Sub</span></p>
</div>
<p>I used the Tag Property of the PictureBox to store the name of the finger. The name is also stored in the .finger file and used to correlate the fingers and PictureBoxes.
</p>
<p>The export works similarly, except I save the contents of each PictureBox to the selected directory using the given name as a basefilename. For example, if the user said they wanted to export to Foo.png, I'd create 10 files with names like Foo.l1.png, Foo.r2.png,
 etc.&nbsp;You can see how easy it is to change image formats using System.Drawing.Image.</p>
<div>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>For</span> <span>Each</span> item <span>As</span> Control <span>
In</span> <span>Me</span>.Controls</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> IsFingerprintPictureBox(item) <span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> pic <span>As</span> PictureBox = <span>CType</span>(item, PictureBox)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>If</span> <span>Not</span> pic.Image <span>Is</span>
<span>Nothing</span> <span>Then</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Dim</span> filename <span>As</span> <span>String</span> = Path.Combine(Path.GetDirectoryName(ExportFileDialog1.FileName), (Path.GetFileNameWithoutExtension(ExportFileDialog1.FileName) &amp;
<span>&quot;.&quot;</span> &amp; pic.Name &amp; <span>&quot;.png&quot;</span>))</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Using</span> m <span>As</span> <span>New</span> MemoryStream</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pic.Image.Save(filename, Imaging.ImageFormat.Png)</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>Using</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>End</span> <span>If</span></p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>Next</span></p>
</div>
<p>To get this sample to work, you'll need a Microsoft Fingerprint Reader (or other compatible reader) and the
<a href="http://www.griaule.com/page/en-us/grfinger_sdk">Griaule SDK</a>&nbsp;installed. I recommend you uninstall the Digital Persona drivers that came with the Fingerprint Reader otherwise this application may compete for the same hardware if the Digital Persona
 software is running in the background. </p>
<h3><strong>Conclusion</strong></h3>
<p>There's a number of fun things that could be&nbsp;extended, added,&nbsp;and improved on with this project.&nbsp;Here are&nbsp;some ideas to get you started:</p>
<ul>
<li>Adding a PDF export feature using an open-source .NET PDF Library </li><li>...or export to Word using Office Automation and the Microsoft Office Interop Assemblies.
</li><li>Add security by using DPAPI or encrypt the Fingerprint files directly. </li><li>Add compression by zipping the .finger files up programmatically.</li></ul>
<p>Have fun and have no fear when faced with the words - Some Assembly Required! </p>
<p>If you do extend this application, be sure to release the source. Thanks again to
<a href="http://www.griaule.com/page/en-us/grfinger_sdk">Griaule</a> for the use of their SDK.</p>
<hr>
<p>Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C&#43;&#43;, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture
 MVP. He is co-author of Professional ASP.NET 2.0&nbsp;with Bill Evjen, available on BookPool.com and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at
<a href="http://www.computerzen.com/">http://www.computerzen.com</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:a1eaf816b1cd48f79cde9e7600d55b75">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Dont-touch-me-Interfacing-with-a-Fingerprint-Reader</comments>
      <itunes:summary>



&amp;nbsp;
In this installment of the &amp;quot;Some Assembly Required&amp;quot; column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the Microsoft Fingerprint Reader and the GrFinger SDK from Griaule.



Scott Hanselman
Scott&#39;s Blog

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: $50-$100
Software: GrFinger
Hardware: Microsoft FingerPrint Reader
Download: Download








Scott Hanselman 
Summary: In this installment of the &amp;quot;Some Assembly Required&amp;quot; column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the

Microsoft Fingerprint Reader and the 
GrFinger SDK from Griaule. 
The Microsoft Fingerprint Reader
 
 
I love my Microsoft Fingerprint Reader and when I got it I knew I had to 
hack it write some software for it. Since there&#39;s already a lot of great security software out there like the Digital Persona software that Microsoft shipped with it as well as 3rd party software like
GrFinger&#39;s Desktop Identity, I wanted to write something a little different. 
My wife and I made a 
New Year&#39;s Resolution to be more prepared for emergencies and the like in the wake of Hurricane Katrina. I figured, since we&#39;ve moved all our identification and important papers into the a safety deposit box, why not a copy of our fingerprints as well?
 
There are do-it-yourself-at-home fingerprinting kits one can buy, but I had this nice Fingerprint&amp;nbsp;Reader lying around.... 
Interfacing with the Reader
Griaule Software out of Brazil has a nice, clean
COM API SDK that abstracts away the fingerprint hardware supporting a
number of readers&amp;nbsp;including Microsoft&#39;s. You can download a trial of
their SDK software and use it for 90 days. They also include an open-source driver for the Microsoft Fingerprint Reader so you don&#39;t have to use the Digital Persona standard stuff if you don&#39;t want to.
 They&#39;ve got an excellent sample code section with details on how to interface with a read using VB.NET,</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Dont-touch-me-Interfacing-with-a-Fingerprint-Reader</link>
      <pubDate>Tue, 06 Mar 2007 05:07:55 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Dont-touch-me-Interfacing-with-a-Fingerprint-Reader</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1815291_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1815291_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Scott Hanselman</dc:creator>
      <itunes:author>Scott Hanselman</itunes:author>
      <slash:comments>16</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Dont-touch-me-Interfacing-with-a-Fingerprint-Reader/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>hardwarehacks</category>
      <category>hardware miscellaneous</category>
    </item>
  <item>
      <title>Part 2: Controlling a Microbric Viper Robot with an IR Serial Port using .NET and PowerShell</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td><span class="entry_description">In this Part Two of &quot;Some Assembly Required&quot;, Scott Hanselman extends his original Microbric Viper Robot/Iguanaworks IR solution to script-enable control of the robot with Lee Holme's &quot;PowerShell LOGO.&quot; Background</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Scott Hanselman</div>
<div class="entry_company"><a href="http://www.hanselman.com/blog">Scott's Blog</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Advanced</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">$100-$200</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://blogs.msdn.com/PowerShell/">Windows PowerShell</a> </span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">MicroBric Viper, Iguanaworks IR Serial Port</span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=284223">C# Download</a>
</li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p><b>Summary:</b> In this Part Two of &quot;Some Assembly Required&quot;, Scott Hanselman&nbsp;extends his original
<a href="http://www.microbric.com/page.php?sId=17">Microbric</a>&nbsp;Viper Robot/<a href="http://iguanaworks.net/ir/">Iguanaworks</a>&nbsp;IR solution to&nbsp;script-enable control of the robot with Lee Holme's &quot;PowerShell LOGO.&quot;
</p>
<h2><b>Background</b></h2>
<p><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=284221#284221"><img height="227" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1720128/viperscreenshot7.png" width="300" align="right"></a> The Microbric Viper is a robot construction kit based on
 a new solderless construction technique. The Viper uses a <a href="http://www.microbric.com/page.php?sId=26">
Basic Atom</a> microcontroller that you program, shockingly,&nbsp;using BASIC. Modules like an
<a href="http://www.microbric.com/page.php?sId=31">Infrared Receiver</a>, motors and switches can be fairly easily controlled as you just screw them directly into the mainboard and address them by number. Once I got my hands on a Microbric, I started trying
 to talk to the robot using my laptop's Infrared Port. It turns out after a number of failed attempts that Windows doesn't expose standard laptop IR ports as Serial Ports or in any way other than via the
<a href="http://en.wikipedia.org/wiki/IrDA">IRDA</a>&nbsp;protocol. IRDA was not only overkill for this kind of communication but also a hassle to program to. What I really needed was an IR transmitter that I could talk to using an interface that was clear and clean
 like the Serial Port&nbsp;interface exposed by System.IO.Ports. </p>
<p>I approached the guys at <a href="http://iguanaworks.net/ir/">Iguanaworks</a>&nbsp;as they make an infrared transceiver that is addressable via a standard Serial Port. The Viper comes with a Sony Remote Control so I set off to figure out how to get the Iguanaworks
 IR transmitter to speak to the Viper using .NET. </p>
<p>There's <a href="http://channel9.msdn.com/ShowPost.aspx?PostID=284221#284221">
<strong>Video of the whole thing working together</strong> posted in the Channel 9 Forums Screencast topic</a>&nbsp;as seen in the screenshot above.
</p>
<h2><b>Remote Scripting the Microbric Viper Robot</b> </h2>
<p>I used the custom IR Serial Port and created a console application that let me control the Microbric Viper using the keyboard of my computer. Now I'll create an application that'll let me control the Viper with script. What better script to use than Windows
 PowerShell? </p>
<p>Rather than just writing some PowerShell script that sends IR commands, I thought it'd be more interesting to
<strong><em>host </em></strong>PowerShell within a WinForms application and write script that controls both the Viper and an an on screen &quot;turtle,&quot; just like the
<a href="http://en.wikipedia.org/wiki/Logo_programming_language">LOGO Programming Language</a>&nbsp;you may have learned in school.</p>
<h2><b>Hosting Windows PowerShell</b></h2>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1720128/viperrobotlogo7.png" target="_new"><img height="346" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1720128/viperrobotlogo_thumb5.png" width="300" align="right"></a>Hosting PowerShell within your
 own WinForms application is amazingly easy. Almost embarrassingly easy. Since I wanted a LOGO-like experience, I started by calling
<a href="http://www.leeholmes.com/blog/MSHLogoAllowingUsersToExtendItsFunctionality.aspx">
Lee Holmes</a>&nbsp;who has a deeply technical blog dedicated to PowerShell. He happily let me extend his existing application to include support for the Microbric Viper.
</p>
<p>Lee's application is a simple WinForms project with an Image control and a textbox. There's a .NET object called
<em>turtle </em>that you can think of as the &quot;pen.&quot; The turtle has methods like Forward, Left, Right, etc.
</p>
<p>The turtle can be controlled on the Actions tab via a series of links. Moving the turtle forward 10 pixels is as trivial as:</p>
<pre class="csharpcode">turtle.Forward(10);</pre>
<p>Controlling the turtle via the UI is simple enough, but <em>scripting </em>the turtle is the interesting part.</p>
<p>It's very significant to note that PowerShell is much more than a shell. It's not a shell at all at its heart - It's a UI-non-specific &quot;runspace&quot; for executing commands. PowerShell doesn't need to be seen in order to do its work. You can host PowerShell
 in any of your applications and instantly script enable them.</p>
<p>The first step is adding a .NET Assembly reference to System.Management.Automation. Within this assembly we'll be focused on the System.Management.Automation.Runspaces namespace.</p>
<p>We create a Runspace where our script will run like this:</p>
<pre class="csharpcode">runspace = RunspaceFactory.CreateRunspace();
runspace.Open();</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Runspaces host Pipelines of commands strung together. We can create a pipeline within our Runspace and pass in the contents of the scriptText textbox from the main WinForm.</p>
<pre class="csharpcode">Pipeline pipeline = runspace.CreatePipeline(scriptText.Text);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The pipeline can be executed with </p>
<pre class="csharpcode">pipeline.Invoke()</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>But we need to let PowerShell have access to an instance of our Turtle class so that it can call methods like turtle.Forward(). You can pass any object from your application into the PowerShell runspace like this:</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>runspace = RunspaceFactory.CreateRunspace();</pre>
<pre><span class="lnum">   2:  </span>runspace.Open();</pre>
<pre class="alt"><span class="lnum">   3:  </span>runspace.SessionStateProxy.SetVariable(<span class="str">&quot;turtle&quot;</span>, turtle);</pre>
<pre><span class="lnum">   4:  </span>Pipeline pipeline = runspace.CreatePipeline(scriptText.Text);</pre>
<pre class="alt"><span class="lnum">   5:  </span>pipeline.Invoke();</pre>
<pre><span class="lnum">   6:  </span>runspace.Close();</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In this snippet an instance of the turtle class is passed into the SetVariable method along with the string &quot;turtle.&quot; The string is the name of the PowerShell variable you want. If we'd passed in &quot;foo&quot;,turtle then there'd be an instance of a turtle in a
 PowerShell variable accessible as &quot;$foo.&quot;</p>
<p>Now that I've got access to the turtle from PowerShell, I could draw a square in PowerShell script however I like:</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>$turtle.Reset() </pre>
<pre><span class="lnum">   2:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   3:  </span>$a = 30</pre>
<pre><span class="lnum">   4:  </span>$turtle.Forward($a)</pre>
<pre class="alt"><span class="lnum">   5:  </span>$turtle.Right(90) </pre>
<pre><span class="lnum">   6:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   7:  </span>$turtle.Forward($a)</pre>
<pre><span class="lnum">   8:  </span>$turtle.Right(90) </pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span>$turtle.Forward($a)</pre>
<pre class="alt"><span class="lnum">  11:  </span>$turtle.Right(90) </pre>
<pre><span class="lnum">  12:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  13:  </span>$turtle.Forward($a)</pre>
<pre><span class="lnum">  14:  </span>$turtle.Right(90)</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>At this point, I've got full control of the turtle, so I can write whatever script I like. If you're going to host PowerShell in your own application be sure to consider the security ramifications. Someone could certainly include &quot;dir&quot; or &quot;format c:&quot; in
 the script, so you might consider a whitelist of allowed commands.</p>
<h2><strong>Extending the Turtle</strong></h2>
<p>In the current version on Lee's website the turtle doesn't update <em>as he draws.
</em>Instead the image is updated after the turtle has finished. Changing this won't make our robot integration work any better, but it would certainly be nice to see the robot move in the real world as it draws on screen.</p>
<p>To solve this we need to understand the relationship between our application and the PowerShell runspace we're hosting. When we pass the turtle instance in PowerShell,&nbsp;that instance is being accessed on another&nbsp;thread, in the &quot;PowerShell world.&quot;
</p>
<p>Since the PowerShell script is going to be accessing the turtle instance, and the turtle instance will be drawing to a Canvas object that we passed in, we'll need a way to refresh the WinForm's image. First we need to invoke the PowerShell pipeline
<em>asynchronously. </em>The pipeline will fire off and immediately return control to our application. It will continue executing, accessing the turtle, while a Timer control refreshes the Image control on the WinForm every 1/4 second or so.</p>
<p>The turtle class is changed to a ViperTurtle class and we'll <a href="http://msdn.microsoft.com/coding4fun/hardware/robotics/article.aspx?articleid=1192168&amp;title=Controlling&#43;a&#43;Microbric&#43;Viper&#43;Robot&#43;with&#43;a&#43;custom&#43;IR&#43;Serial&#43;Port&#43;using&#43;.NET">
add the IR class from the last article</a>. When the turtle moves, we'll not only draw to the canvas but also send Viper-specific IR codes to move the robot.</p>
<h2><b>Problems with Timing</b></h2>
<p>I had a few timing-related problem with this project. </p>
<p>First, since the IR transmitter is going as fast as I can send signals to it, I had to add a &quot;WaitASec&quot; method that sleeps for a a third of a second. The commands were coming so fast that the robot would get &quot;stuck&quot; as if a real person was pressing buttons
 too fast on a remote control. If a Forward command is followed by a Left command too quickly, the robot thinks that the Forward command is continuing...as if the button were being held down. If we wait a fraction of a second for the IR beam to shut off, it
 works much better. </p>
<p>The second issue was that the commands the Viper understands are relative - like &quot;turn left.&quot; The longer we &quot;hold down,&quot; or continue to send, a command, the longer the robot turns. However, the LOGO-like PowerShell script thinks in absolutes, like &quot;left(90)&quot;
 where 90 means ninety degrees exactly. If the robot skids or slides on the floor, it can also throw the turns off. I could, and can still, deal with this in a number of ways. First, I could create new IR commands for the Viper to respond to and program its
 firmware with these custom commands, like &quot;TurnLeft5Degrees&quot; or even at 1 or 2 degree increments. Then I'd need to calculate the circumference of the wheels on the robot and do the math backwards in order to find the correct number of milliseconds to pulse
 the Viper's onboard motors to turn those wheels. Whew! </p>
<p>Or, I could just build in a &quot;fudge factor&quot; and get it working by trial and error. This is a classic software engineering problem, isn't it? The amount of effort required to get 100% perfect turning weighed against how long it would take to get it working
 85-90%. </p>
<p>I came up with these two constant values that worked pretty well for me. You might need to try different values based on the kind of surface you're using, or if you've built your own IR transmitter.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">const</span> <span class="kwrd">double</span> VIPERADJUST = 0.35;</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">const</span> <span class="kwrd">double</span> VIPERADJUSTTURN = 0.06;</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> Left(<span class="kwrd">int</span> degrees)</pre>
<pre class="alt"><span class="lnum">   5:  </span>{</pre>
<pre><span class="lnum">   6:  </span>    direction = (direction &#43; degrees) % 360;</pre>
<pre class="alt"><span class="lnum">   7:  </span>    WaitASec();</pre>
<pre><span class="lnum">   8:  </span>    ir.Send(LEFT, (<span class="kwrd">int</span>)(VIPERADJUSTTURN * degrees));</pre>
<pre class="alt"><span class="lnum">   9:  </span>}</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The IR's send method takes a Repeat value as its second parameter. This indicates how many times the IR command should repeat. I found that multiplying the number of degrees I wanted the robot to turn by a value of 0.06 would get me the correct turn. However,
 I can't send fractional packets, so I'm forced to lose precision as I cast the result of the double calculation down to an int. So a 90 degree turn becomes 5.4, which becomes the left command sent via IR 5 times. In practice it works pretty well, though. If
 I were to hook a pen up to the Viper in the future and create PenUp and PenDown commands in its firmware, I'd want to get tighter, more accurate turning.
</p>
<p>Again, here's <a href="http://channel9.msdn.com/ShowPost.aspx?PostID=284221#284221">
<strong>Video of the whole thing working together</strong> posted in the Channel 9 Forums Screencast topic</a>&nbsp;as seen in the screenshot above.
</p>
<h2><strong>Purchasing these Parts</strong></h2>
<p>The Microbric Viper can be ordered online in North America, check out <a href="http://www.microbric.com/page.php?sId=17">
www.microbric.com</a> for North American distributors. It's only <a href="http://www.saelig.com/miva/merchant.mvc?Screen=PROD&amp;Product_Code=RO001&amp;Category_Code=">
US$89 at Saelig</a>&nbsp;and <a href="http://www.robotshop.ca/home/suppliers/microbric-en/microbric-viper-robot-kit.html">
CAD$99 at RobotShop</a>. They have a number of educational robots that can be assembled by kids of all ages and skill levels. They're great for the classroom, and include projects like Sumo Robots, and a line-following bot, as well as a Spiderbot that climbs
 rope - all from the same kit. </p>
<p>You can order the <a href="http://iguanaworks.net/ir/">IR Transmitter/Receiver from IguanaWorks</a>. The
<a href="http://iguanaworks.net/ir/serial/">serial version</a> works on Windows or Linux, and there's a
<a href="http://iguanaworks.net/ir/usb/">Linux USB version</a>. It's not just a Transmitter, but also a learning receiver that works with WinLIRC&nbsp;and turns your computer into a learning remote control and can be used for nearly any project that utilizes IR.
</p>
<h2><b>Conclusion</b> </h2>
<p>As with all my projects, there's things that could be&nbsp;extended, added,&nbsp;and improved on with this project.&nbsp;Here are&nbsp;some ideas to get you started.
</p>
<ul>
<li>Extend the IR program running&nbsp;inside the Viper to support other commands.&nbsp; </li><li>Integrate the Viper with the Microsoft Robotics Toolkit. </li><li>Use the IR class to control your home theater and television.&nbsp; </li><li>Change this program to control a Roomba, or any IR-controllable robot.</li></ul>
<p>Have fun and have no fear when faced with the words - Some Assembly Required! </p>
<hr align="center" width="100%" size="2">
<p>Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C&#43;&#43;, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture
 MVP. He is co-author of Professional ASP.NET 2.0&nbsp;with Bill Evjen, available on BookPool.com and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at
<a href="http://www.computerzen.com/">http://www.computerzen.com</a>.&nbsp;He thanks his wife and&nbsp;Zenzo for indulging him in these hobbies!</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:472c91804c0a4c55be1d9e7600d5dc50">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Part-2-Controlling-a-Microbric-Viper-Robot-with-an-IR-Serial-Port-using-NET-and-PowerShell</comments>
      <itunes:summary>



&amp;nbsp;
In this Part Two of &amp;quot;Some Assembly Required&amp;quot;, Scott Hanselman extends his original Microbric Viper Robot/Iguanaworks IR solution to script-enable control of the robot with Lee Holme&#39;s &amp;quot;PowerShell LOGO.&amp;quot; Background



Scott Hanselman
Scott&#39;s Blog

Difficulty: Advanced
Time Required: 
3-6 hours
Cost: $100-$200
Software: Visual Basic or Visual C# Express Editions,
Windows PowerShell 
Hardware: MicroBric Viper, Iguanaworks IR Serial Port
Download: 

C# Download







Summary: In this Part Two of &amp;quot;Some Assembly Required&amp;quot;, Scott Hanselman&amp;nbsp;extends his original
Microbric&amp;nbsp;Viper Robot/Iguanaworks&amp;nbsp;IR solution to&amp;nbsp;script-enable control of the robot with Lee Holme&#39;s &amp;quot;PowerShell LOGO.&amp;quot;
 
Background
 The Microbric Viper is a robot construction kit based on
 a new solderless construction technique. The Viper uses a 
Basic Atom microcontroller that you program, shockingly,&amp;nbsp;using BASIC. Modules like an
Infrared Receiver, motors and switches can be fairly easily controlled as you just screw them directly into the mainboard and address them by number. Once I got my hands on a Microbric, I started trying
 to talk to the robot using my laptop&#39;s Infrared Port. It turns out after a number of failed attempts that Windows doesn&#39;t expose standard laptop IR ports as Serial Ports or in any way other than via the
IRDA&amp;nbsp;protocol. IRDA was not only overkill for this kind of communication but also a hassle to program to. What I really needed was an IR transmitter that I could talk to using an interface that was clear and clean
 like the Serial Port&amp;nbsp;interface exposed by System.IO.Ports.  
I approached the guys at Iguanaworks&amp;nbsp;as they make an infrared transceiver that is addressable via a standard Serial Port. The Viper comes with a Sony Remote Control so I set off to figure out how to get the Iguanaworks
 IR transmitter to speak to the Viper using .NET.  
There&#39;s 
Video of the whole thing working together posted</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Part-2-Controlling-a-Microbric-Viper-Robot-with-an-IR-Serial-Port-using-NET-and-PowerShell</link>
      <pubDate>Mon, 19 Feb 2007 22:17:40 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Part-2-Controlling-a-Microbric-Viper-Robot-with-an-IR-Serial-Port-using-NET-and-PowerShell</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1720128_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1720128_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Scott Hanselman</dc:creator>
      <itunes:author>Scott Hanselman</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Part-2-Controlling-a-Microbric-Viper-Robot-with-an-IR-Serial-Port-using-NET-and-PowerShell/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Robotics</category>
      <category>hardwarehacks</category>
      <category>hardware miscellaneous</category>
    </item>
  <item>
      <title>Computer-Controlled R/C Car with Camera</title>
      <description><![CDATA[
<p>&nbsp;</p>
<span id="c4fmetadata">
<table border="0" cellpadding="1" cellspacing="0" width="100%">
<tbody>
<tr class="entry_overview">
<td width="50"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/thumb2.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/thumb_thumb.jpg" border="0" height="33" width="50"></a>
</td>
<td><span class="entry_description">Control a remote controlled car with your computer using Microsoft Robotics Studio. Then, add a wireless IP camera for stealthy remote operation.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Brian Peek</div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Advanced</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">$50-$100</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://msdn.microsoft.com/robotics/" target="_blank">Microsoft Robotics Studio</a>,
<a href="http://www.phidgets.com/modules.php?op=modload&amp;name=Downloads&amp;file=index&amp;req=viewdownload&amp;cid=3">
Phidgets .NET and MSRS libraries</a> </span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">A remote-controlled car,
<a href="http://www.trossenrobotics.com/store/p/3203-InterfaceKit-0-0-4.aspx" target="_blank">
PhidgetInterfaceKit 0/0/4</a> <b>OR</b> <a href="http://www.trossenrobotics.com/store/p/3201-InterfaceKit-0-16-16.aspx" target="_blank">
PhidgetInterfaceKit 0/16/16</a>, <a href="http://www.airlink101.com/products/aic250w.html" target="_blank">
Airlink101 AIC-250W</a> wireless camera (optional), <a href="http://www.microsoft.com/hardware/gaming/productdetails.aspx?pid=091" target="_blank">
Xbox 360 Controller for Windows</a> (optional), batteries, wire, and solder</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=274650" target="_blank">Download</a></div>
<div class="entry_details">&nbsp;</div>
<div class="entry_details">In 2005, we at ASPSOFT built the world's first .NET-powered battlebot known as
<a href="http://www.finalizer.net" target="_blank">The Finalizer</a>. Since then, many robotics enthusiasts and hobbyists have become intrigued with the idea of a .NET-controlled robot, but don't have the cash or hardware required to build something as elaborate
 as The Finalizer. With that in mind, I set out to create a very simple and very cheap computer controlled vehicle that anyone with a couple bucks and a computer could build.</div>
<div class="entry_details">&nbsp;</div>
</td>
</tr>
</tbody>
</table>
</span>
<h3><b>What You Will Need</b></h3>
<ul>
<li>A remote-controlled vehicle with a digital controller. That is, a controller that uses switches for forward/backward/left/right, not potentiometers. The car used in this article is a vehicle from the “<a href="http://www.jadatoys.com/products.php?id=1380&amp;list=RC&amp;category=Dub%20City&amp;scale=16&amp;dir=-1" target="_blank">Dub
 City</a>” collection by <a href="http://www.jadatoys.com/" target="_blank">Jada Toys</a>.
</li><li><a href="http://www.trossenrobotics.com/store/p/3203-InterfaceKit-0-0-4.aspx" target="_blank">PhidgetInterfaceKit 0/0/4</a> – a USB-controlled board with 4 relays,
<b>OR</b> <a href="http://www.trossenrobotics.com/store/p/3201-InterfaceKit-0-16-16.aspx" target="_blank">
PhidgetInterfaceKit 0/16/16</a>, -&nbsp;USB-controlled digital IO boards (if you need to control more than 4 controls on your remote controlled car)
</li><li>A soldering iron and some solder </li><li>Some spare wire </li><li><a href="http://msdn.microsoft.com/vstudio/express/" target="_blank">Microsoft Visual C# or Visual Basic 2005 Express Edition</a>
</li><li><a href="http://msdn.microsoft.com/robotics/" target="_blank">Microsoft Robotics Studio</a>
</li><li>Optional: WiFi-enabled webcam. This article uses the <a href="http://www.airlink101.com/products/aic250w.html" target="_blank">
Airlink101 AIC-250W</a> wireless camera. </li><li>Optional: 4 AA battery holder (6V total) to power the webcam. I used a battery holder from Radio Shack with part number
<a href="http://www.radioshack.com/product/index.jsp?productId=2062244" target="_blank">
270-391A</a>. </li><li>Optional: DC Power Plug to connect to AA battery holder above. The size required is 5.5mm outer diameter and 2.5mm inner diameter. The Radio Shack “Size N” connector with part number
<a href="http://www.radioshack.com/product/index.jsp?productId=2102488" target="_blank">
274-1573</a> is the one I chose. </li><li>Optional: <a href="http://www.microsoft.com/hardware/gaming/productdetails.aspx?pid=091" target="_blank">
Xbox 360 Controller for Windows</a></li></ul>
<h3><b>The Car</b></h3>
<p>First, we will modify the remote controlled car so that it can be interfaced with the Phidget controller. The easiest way to accomplish this is to modify the hand-held controlling unit to receive input from the Phidget controller instead of a human driver.
</p>
<p>Start by unscrewing all screws on the back of the unit and&nbsp;then open up the controller.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02014.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02013.jpg" border="0" height="180" width="240"></a>
</p>
<p>If you have chosen the right type of controller, that is, one with digital inputs, you will see that the joysticks simply push down on contacts on the board, closing the circuit for forward/backward/left/right. We will be wiring these contacts to our Phidget
 board so when the relays/IO ports&nbsp;open and close, they will be closing and opening the circuits.
</p>
<p>To do this, cut 8 equal lengths of wire of about 6 inches. Strip off a bit of insulation from each end.
</p>
<p>Next, solder one end of each wire to each contact of the controller. You will need to connect one wire to both the ground and the active points of the contact as shown in the picture.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02084.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02083.jpg" border="0" height="180" width="240"></a>
</p>
<p>When all wires are soldered, insert the opposite ends into the screw terminals of the Phidget interface board.
</p>
<p><b>Phidget 0/0/4 Interface Kit</b></p>
<p>You'll notice on the Phidget board that there are 3 terminals per relay, labeled NO, XC, and NC, where “X” is a number from 0 to 3. These stand for “Normally Open”, “Relay X Common”, and “Normally Closed”. Since our circuits are normally open and closed
 when you press the joystick, you will want to connect one wire from each contact to the NO and the XC terminals of each relay. Wire the relays as follows:
</p>
<p>0 – Forward </p>
<p>1 – Backward </p>
<p>2 – Left </p>
<p>3 - Right </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02024.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02023.jpg" border="0" height="180" width="240"></a>
</p>
<p>&nbsp;</p>
<p><b>Phidget 0/16/16 Interface Kit</b></p>
<p>This board is divided into two sections and is labeled as such: Inputs and Outputs.&nbsp; On the Output side, there are 16 outputs, numbered 0 through 15.&nbsp; There are also 8 common ground terminals labeled &quot;G&quot;.&nbsp; As with the above board, you will want to connect
 one wire from each contact to a&nbsp;numbered output, and one to a common ground contact.&nbsp; Wire them using the same numbering scheme as above.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG04604.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG04603.jpg" border="0" height="180" width="240"></a></p>
<br>
<h3><b>The Camera</b></h3>
<p>If you decide to add the network camera to the project continue reading. If you choose to skip the camera, move on to the next section.
</p>
<p>The camera will need to be battery powered. The camera I used in this project is the Airlink101 AIC-250W. This camera requires 5V to operate. Getting 5V out of a series of standard batteries isn't easy without a voltage regulator, so I cheated and decided
 to try pumping 6V (4 AA batteries at 1.5V each) to the device. I have run the cam for over 2 hours on one set of batteries with no ill effects.
</p>
<p>To easily connect the batteries to the camera, I used a 4 AA battery holder and a power connector that matched the size of the connector on the included AC power supply. As stated above, the size required is a 5.5mm outer diameter with a 2.5mm inner diameter.
</p>
<p>On the back of the camera, above the power connector, there is a symbol showing the positive and negative connections for the power connector.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG04634.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG04633.jpg" border="0" height="180" width="240"></a>
</p>
<p>The symbol shows that the negative terminal is&nbsp;the outside ring and the positive terminal is the inside. With that in mind, we will solder the black wire of the holder to the outside connector, and the red to the ring connector. The wires from the battery
 holder can be easily soldered onto the power connector as shown. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG01904.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG01903.jpg" border="0" height="180" width="240"></a>
</p>
<p>When all is said and done, you will have a battery holder with a DC power end that can be plugged directly into the camera. Pop 4 AA batteries into the holder and you should see the Power light on the camera turn on. I chose to mount the battery pack to
 the top of the camera using some double-sided tape as shown. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG01964.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG01963.jpg" border="0" height="240" width="180"></a>
</p>
<p>Finally, mount the camera to the vehicle with some double-sided tape or velcro.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02194.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/CIMG02193.jpg" border="0" height="180" width="240"></a>
</p>
<h3>The Software</h3>
<p>Now that the hardware is complete, we need to write the software to control the car. First, the required software must be installed.&nbsp; Install the software in the following order:</p>
<ol>
<li><a href="http://msdn.microsoft.com/vstudio/express/" target="_blank">Microsoft C# or Visual Basic 2005 Express Edition</a>
</li><li><a href="http://msdn.microsoft.com/robotics/downloads/default.aspx" target="_blank">Microsoft Robotics Studio</a>
</li><li><a href="http://www.phidgets.com/modules.php?op=modload&amp;name=Downloads&amp;file=index&amp;req=viewdownload&amp;cid=3" target="_blank">Phidgets libraries</a>
</li><li><a href="http://www.phidgets.com/modules.php?op=modload&amp;name=Downloads&amp;file=index&amp;req=viewdownload&amp;cid=3" target="_blank">Phidgets Services for Microsoft Robotics Studio</a></li></ol>
<p>Once all of the software is installed,&nbsp;the files <b>phidget21.dll </b>and&nbsp;<b>Phidget21.NET.dll</b>&nbsp;must be copied from the
<b>\Program Files\Phidgets</b> directory to the <b>bin</b> directory of your MSRS installation.&nbsp; If this is not done,&nbsp;the Phidget services will all fail to start&nbsp;when requested, causing you as much pain and torment as it caused me.
</p>
<h3><b>The Code</b></h3>
<p>Before we get started, it is essential that you have some familiarity with Microsoft Robotics Studio. Please read through the included help file as well as the base tutorials. I have also included several links at the bottom of this article with even more
 information on the internals of MSRS.&nbsp; The documentation&nbsp;and tutorials will be your best guidance for understanding what we are about to build.
</p>
<p>At its core, the MSRS runtime aids in developing applications where concurrency and performance are key issues. In a robot where there are multiple sensors receiving input that needs to be concurrently handled, MSRS excels.&nbsp; While our remote controlled car
 may not fit into that mold exactly, it is a great way to delve into Robotics Studio and learn about what it has to offer.
</p>
<p>To start, we must first create a service for our car. This can be done by opening the
<b>Microsoft Robotics Studio Command Prompt</b> from the <b>Microsoft Robotics Studio (1.0)</b> program group on the Start menu.
</p>
<p>To generate the template for our service, the command <b>dssnewservice.exe</b> is used. Change to the directory where you wish to create your project and type one of the following commands, depending on the language you wish to use,&nbsp;to create a new service
 named “RCCar”: </p>
<p><b>C#:</b> </p>
<p><b>dssnewservice /service:RCCar</b> </p>
<p><b>VB</b> </p>
<p><b>dssnewservice /language:VB /service:RCCar</b> </p>
<p>This will generate a folder with several items, including project and solution files.&nbsp; Note that it will lower-case RCCar to Rccar in various places.&nbsp; This is normal.
</p>
<p>Open the generated RCCar.sln file in Microsoft C# 2005 Express Edition or Microsoft Visual Basic 2005 Express Edition. You will see that several files were generated.
</p>
<p><b><a href="http://RCCar.cs/.vb" class="linkification-ext" title="Linkification: http://RCCar.cs/.vb">RCCar.cs/.vb</a></b> – Contains actual implementation of the RCCar service
</p>
<p><b><a href="http://RCCarTypes.cs/.vb" class="linkification-ext" title="Linkification: http://RCCarTypes.cs/.vb">RCCarTypes.cs/.vb</a></b> – Contains list of messages and default state object
</p>
<p><b>RCCar.manifest.xml </b>– A description of the services started when the application is run
</p>
<p>Take some time to review the base generated code. This will help as we move forward.
</p>
<p>Open the <b>RCCar.sln</b> file to start working.&nbsp; The first thing we will need to do is access the service which controls our Phidget Interface Kit. Robotics Studio includes a built-in service for this device. To access it, first, set a reference to the
<b>PhidgetBoards.Y2006.M08.proxy</b> namespace. This can be done by right-clicking on the project name in the Solution Explorer&nbsp;and selecting
<b>Add Reference</b> from the context menu. When the <b>Add Reference</b> dialog appears, select
<b>PhidgetBoards.Y2006.M08.proxy</b> and click the <b>OK</b> button. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/addref4.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/addref3.png" border="0" height="197" width="240"></a>
</p>
<p>To use the contents of this library in our code, we need to import the library.&nbsp;&nbsp;This can be done by adding the&nbsp;following line to&nbsp;the
<b>Rccar</b> class. </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> phidgetinterfacekit = Phidgets.Robotics.Services.PhidgetInterfaceKitBoards.Proxy;<br><span class="kwrd">using</span> phidgetcommon = Phidgets.Robotics.Services.Proxy;<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Imports</span> phidgetinterfacekit = Phidgets.Robotics.Services.PhidgetInterfaceKitBoards.Proxy<br><span class="kwrd">Imports</span> phidgetcommon = Phidgets.Robotics.Services.Proxy<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, we need to setup a partner relationship with the PhidgetInterfaceKit service and declare a port on which to communicate with it. At the top of the
<b>RccarService </b>class implementation, add the following code to the service: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">[Partner(<span class="str">&quot;PhidgetInterfaceKit&quot;</span>, Contract = phidgetinterfacekit.Contract.Identifier,<br>CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate)]<br><span class="kwrd">private</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations _ikPort = <br>    <span class="kwrd">new</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations();</pre>
<pre class="csharpcode"><b>VB</b></pre>
<pre class="csharpcode">&lt;Partner(<span class="str">&quot;PhidgetInterfaceKit&quot;</span>, Contract:=phidgetinterfacekit.Contract.Identifier, _<br>CreationPolicy:=PartnerCreationPolicy.UseExistingOrCreate)&gt; _<br><span class="kwrd">Private</span> _ikPort <span class="kwrd">As</span> <span class="kwrd">New</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations()</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, we will setup a few items that will be required to talk to the Phidget controller.&nbsp; First, we must subscribe to the
<b>PhidgetInterfaceKit</b> service.&nbsp; We will be subscribing to additional services later on, so create a
<b>SubscribeToServices</b> method in the <b>RccarService</b> class and then call this method from the bottom of the
<b>Start</b> method: </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SubscribeToServices()<br>{<br>    _ikPort.SelectiveSubscribe(<span class="kwrd">null</span>, <br>        <span class="kwrd">new</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations());<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SubscribeToServices()<br>    _ikPort.SelectiveSubscribe(<span class="kwrd">Nothing</span>, <span class="kwrd">New</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations())<br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This will subscribe to the PhidgetInterfaceKit service without requesting any notifications on&nbsp;events, as they will not be needed for this project.
</p>
<p>Next, create an enumeration above the definition for the&nbsp;<b>RccarService</b> class for the possible directions:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">enum</span> Direction<br>{<br>    Forward = 0,<br>    Backward,<br>    Left,<br>    Right,<br>    None<br>}<br><br><b>VB</b></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Enum</span> Direction<br>    Forward = 0<br>    Backward<br>    Left<br>    Right<br>    None<br><span class="kwrd">End</span> <span class="kwrd">Enum</span></pre>
<p>The value of each item in the enumeration will correspond to the relay used for that direction as described above.&nbsp; Next, we will write a method named
<b>SetOutput </b>to communicate with the Phidget Interface Kit and enable or disable the output relay as appropriate:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> SetOutput(Direction dir, <span class="kwrd">bool</span> enabled)<br>{<br>    <span class="rem">// if no direction sent, return</span><br>    <span class="kwrd">if</span>(dir == Direction.None)<br>        <span class="kwrd">return</span>;<br><br>    <span class="rem">// create a new request to send to the Phidgets service</span><br>    phidgetcommon.SetOutputRequestType req = <span class="kwrd">new</span> phidgetcommon.SetOutputRequestType();<br><br>    <span class="rem">// assign the index and state (true/false)</span><br>    req.Index = (<span class="kwrd">int</span>)dir;<br>    req.State = enabled;<br><br>    <span class="rem">// send the request to the port</span><br>    _ikPort.SetOutput(req);<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> SetOutput(<span class="kwrd">ByVal</span> dir <span class="kwrd">As</span> Direction, <span class="kwrd">ByVal</span> enabled <span class="kwrd">As</span> <span class="kwrd">Boolean</span>)<br>    <span class="rem">' if no direction sent, return</span><br>    <span class="kwrd">If</span> dir = Direction.None <span class="kwrd">Then</span> <span class="kwrd">Return</span><br><br>    <span class="rem">' create a new request to send to the Phidgets service</span><br>    <span class="kwrd">Dim</span> req <span class="kwrd">As</span> <span class="kwrd">New</span> phidgetcommon.SetOutputRequestType<br><br>    <span class="rem">' assign the index and state (true/false)</span><br>    req.Index = dir<br>    req.State = enabled<br><br>    <span class="rem">' send the request to the port</span><br>    _ikPort.SetOutput(req)<br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>SetOutput </b>method creates a new <b>SetOutputRequestType</b> request object and fills in the appropriate
<b>Index</b> and <b>State</b>. The <b>Index</b> refers to the index number of the relay to change, and the
<b>State</b> property is a&nbsp;boolean of whether the relay should be opened or closed.
</p>
<p>Next, we will need a user interface to interact with to control the robot. Right-click on the RCCar project and select
<b>Add</b> -&gt; <b>Windows Form</b> from the context menu. Name this form <b><a href="http://RemoteControlForm.cs/.vb" class="linkification-ext" title="Linkification: http://RemoteControlForm.cs/.vb">RemoteControlForm.cs/.vb</a></b>.
</p>
<p><b>&lt;NOTE FOR VB USERS&gt;</b> </p>
<p>Due to an oddity in the dssproxy application which runs during the compilation process, one addition must be made to the form created in the Visual Basic project.&nbsp; To make this change, first click on the
<b>Show all files</b> button on the Solution Explorer toolbar as shown: </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/showall4.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/showall3.png" border="0" height="56" width="240"></a>
</p>
<p>Once that is done, you should see a &quot;&#43;&quot; next to the <b>RemoteControlForm.vb</b> file.&nbsp; First, right-click on the
<b>RemoteControlForm.vb</b> file and select <b>View Code</b>.&nbsp; Add the following namespace definition around the the class definition as shown:
</p>
<pre class="csharpcode"><span class="kwrd">Namespace</span> Robotics.Rccarvb<br>    <span class="kwrd">Public</span> <span class="kwrd">Class</span> RemoteControlForm<br><br>    <span class="kwrd">End</span> <span class="kwrd">Class</span><br><span class="kwrd">End</span> <span class="kwrd">Namespace</span><br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, open the <b>RemoteControlForm.Designer.vb</b> file using the same method above and add the same namespace definition around the class implementation.&nbsp; Once this is done, verify that the project&nbsp;compile and continue on.
</p>
<p><b>&lt;/NOTE FOR VB USERS&gt;</b> </p>
<p>For the moment, we will setup the form with four buttons (up, down, left and right) and control the vehicle with those. Drag four buttons onto the form and label them appropriately. You can easily get arrow glyphs on the buttons by using the Marlett font
 and setting the <b>Text</b> property of each button to one of the following: </p>
<p>3 = Left </p>
<p>4 = Right </p>
<p>5 = Up </p>
<p>6 = Down </p>
<p>Name the&nbsp;buttons&nbsp;<b>btnForward</b>,<b> btnBackward</b>,<b> btnLeft</b>, and<b> btnRight</b>.&nbsp; In an effort to make things easy for determining which button is pressed, assign the values 0, 1, 2, and 3 to the
<b>Tag</b> property of each button to match the enumeration created above.&nbsp; So, the
<b>Tag</b> property of the forward button would be 0, backward would be 1, and so on.&nbsp; When you are done, you will have a form similar to the following:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/form4.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/form3.png" border="0" height="94" width="240"></a>
</p>
<p>This form will need to call the <b>SetOutput</b> method we created in our service above.&nbsp; Therefore, it will need an instance of the
<b>RccarService</b> available to it.&nbsp; To easily accomplish this, the constructor for the form will be written to accept the current instance of the service and store it in a member variable for later use.&nbsp; Add the following code to
<b><a href="http://RemoteControlForm.cs/.vb" class="linkification-ext" title="Linkification: http://RemoteControlForm.cs/.vb">RemoteControlForm.cs/.vb</a></b> to facilitate this:</p>
<p><b>C#</b></p>
<pre class="csharpcode">RccarService _service = <span class="kwrd">null</span>;<br><br><span class="kwrd">public</span> RemoteControlForm(RccarService service)<br>{<br>    InitializeComponent();<br><br>    _service = service;<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> _service <span class="kwrd">As</span> RccarService<br><br><span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> service <span class="kwrd">As</span> RccarService)<br><br>    <span class="rem">' This call is required by the Windows Form Designer.</span><br>    InitializeComponent()<br><br>    <span class="rem">' Add any initialization after the InitializeComponent() call.</span><br>    _service = service<br><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>To properly drive the car, we need to listen for both the button being clicked (close the circuit) and the button being released (open the circuit). This can be done by hooking the
<b>MouseDown</b> and <b>MouseUp</b> events on each button. Open <b><a href="http://RemoteControlForm.cs/.vb" class="linkification-ext" title="Linkification: http://RemoteControlForm.cs/.vb">RemoteControlForm.cs/.vb</a></b> in the designer. Then, choose the
 events list in the properties window by clicking on the “lightning bolt” icon. This will toggle the event list into view.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/events4.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1507304/events3.png" border="0" height="240" width="189"></a>
</p>
<p>Highlight all of the buttons on the form. Then, enter <b>btn_MouseDown</b> into the
<b>MouseDown</b> event and <b>btn_MouseUp</b> in the <b>MouseUp</b> event. The IDE will automatically generate method stubs for each of those events.
</p>
<p>Next, add the code for&nbsp;the <b>MouseDown</b> and <b>MouseUp</b> events.&nbsp; If you are using VB, you will need to import the System.Windows.Forms namespace into the RemoteControlForm code.&nbsp; The
<b>Tag</b> property created above will be used from each button to determine which was clicked:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> btn_MouseDown(<span class="kwrd">object</span> sender, MouseEventArgs e)<br>{<br>    _service.SetOutput((Direction)<span class="kwrd">int</span>.Parse((sender <span class="kwrd">as</span> Button).Tag.ToString()), <span class="kwrd">true</span>);<br>}<br><br><span class="kwrd">private</span> <span class="kwrd">void</span> btn_MouseUp(<span class="kwrd">object</span> sender, MouseEventArgs e)<br>{<br>    _service.SetOutput((Direction)<span class="kwrd">int</span>.Parse((sender <span class="kwrd">as</span> Button).Tag.ToString()), <span class="kwrd">false</span>);<br>}</pre>
<pre class="csharpcode"><b>VB</b></pre>
<pre class="csharpcode"><span class="kwrd">Imports</span> System.Windows.Forms<br><br>...<br><br><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btn_MouseDown(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> System.<span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.Windows.Forms.MouseEventArgs) <span class="kwrd">Handles</span> btnRight.MouseDown, btnLeft.MouseDown, btnForward.MouseDown, btnBackward.MouseDown<br>    _service.SetOutput(<span class="kwrd">CType</span>(<span class="kwrd">Integer</span>.Parse(<span class="kwrd">CType</span>(sender, Button).Tag.ToString()), Direction), <span class="kwrd">True</span>)<br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br><br><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btn_MouseUp(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> System.<span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.Windows.Forms.MouseEventArgs) <span class="kwrd">Handles</span> btnRight.MouseUp, btnLeft.MouseUp, btnForward.MouseUp, btnBackward.MouseUp<br>    _service.SetOutput(<span class="kwrd">CType</span>(<span class="kwrd">Integer</span>.Parse(<span class="kwrd">CType</span>(sender, Button).Tag.ToString()), Direction), <span class="kwrd">False</span>)<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The events simply look at the button being sent in as the <b>sender</b> parameter, convert the
<b>Tag</b> to an entry in the <b>Direction</b> enumeration, and set the associated relay using the
<b>SetOutput</b> method. </p>
<p>Now that our base user interface is setup, we need to launch the form from our&nbsp;service. To do this, we need to add reference to the
<b>Ccr.Adapters.WinForms</b> namespace. This can be done in the same way as we added the reference to the Phidget library. Once that is done, back in
<b><a href="http://Rccar.cs/.vb" class="linkification-ext" title="Linkification: http://Rccar.cs/.vb">Rccar.cs/.vb</a></b>, bring the WinForms library into the class by adding the following using statement:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.Ccr.Adapters.WinForms;<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Imports</span> Microsoft.Ccr.Adapters.WinForms<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>To actually launch the form, add the following line to the bottom of the&nbsp;<b>Start</b> method, below the previous call to
<b>SubscribeToServices</b>: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">WinFormsServicePort.Post(<span class="kwrd">new</span> RunForm(StartForm));</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode">WinFormsServicePort.Post(<span class="kwrd">New</span> RunForm(<span class="kwrd">AddressOf</span> StartForm))</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This will launch the method <b>StartForm</b> which actually creates the form. Add a member variable to the class to store the instance of the created form and add the
<b>StartMethod</b> form as follows: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">RemoteControlForm _remoteForm = <span class="kwrd">null</span>;</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<pre class="csharpcode"><span class="kwrd">public</span> System.Windows.Forms.Form StartForm()<br>{<br>    _remoteForm = <span class="kwrd">new</span> RemoteControlForm(<span class="kwrd">this</span>);<br>    <span class="kwrd">return</span> _remoteForm;<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> _remoteForm <span class="kwrd">As</span> RemoteControlForm<br><br><span class="kwrd">Private</span> <span class="kwrd">Function</span> StartForm() <span class="kwrd">As</span> System.Windows.Forms.Form<br>    _remoteForm = <span class="kwrd">New</span> RemoteControlForm(<span class="kwrd">Me</span>)<br>    <span class="kwrd">Return</span> _remoteForm<br><span class="kwrd">End</span> <span class="kwrd">Function</span><br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This will create a new instance of the form, assign it to the local member variable, and return the instance back to the calling method.
</p>
<p>At this point, everything should be in place to actually run the project. Make sure the Phidget board is connected to the PC via the USB cable and press the
<b>F5</b> key to build and execute the project. If all went to plan, you should see the UI form start up and you should be able to click the arrow buttons and hear the relays click on the 0/0/4 board, or the lights flicker on the 0/16/16 board. If the car is
 turned on and the remote is turned on, the car will drive around based on the buttons you click.
</p>
<h3><b>The Keyboard</b></h3>
<p>We can easily add support to drive the car with the keyboard's arrow keys. To use the arrows, we cannot use the native
<b>KeyDown </b>event because the arrow keys are normally used to cycle through the active controls of a form. Therefore, we need to trap the key down events earlier in the message chain. To do this, we must override the
<b>ProcessCmdKey</b> method of the <b>Form</b> class. Additionally, the form's <b>
KeyPreview</b> property must be set to false.&nbsp; Add&nbsp;the following code to the <b><a href="http://RemoteControlForm.cs/.vb" class="linkification-ext" title="Linkification: http://RemoteControlForm.cs/.vb">RemoteControlForm.cs/.vb</a></b> file:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">const</span> <span class="kwrd">int</span> WM_KEYDOWN = 0x100;<br><br><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> ProcessCmdKey(<span class="kwrd">ref</span> Message msg, Keys keyData) <br>{ <br>    <span class="kwrd">if</span>(msg.Msg == WM_KEYDOWN) <br>    {<br>        <span class="kwrd">switch</span>(keyData) <br>        { <br>            <span class="kwrd">case</span> Keys.Up: <br>                _service.SetOutput(Direction.Forward, <span class="kwrd">true</span>); <br>            <span class="kwrd">break</span>; <br><br>            <span class="kwrd">case</span> Keys.Down: <br>                _service.SetOutput(Direction.Backward, <span class="kwrd">true</span>); <br>                <span class="kwrd">break</span>; <br><br>            <span class="kwrd">case</span> Keys.Left: <br>                _service.SetOutput(Direction.Left, <span class="kwrd">true</span>); <br>                <span class="kwrd">break</span>; <br><br>            <span class="kwrd">case</span> Keys.Right: <br>                _service.SetOutput(Direction.Right, <span class="kwrd">true</span>); <br>                <span class="kwrd">break</span>; <br>        } <br>        <span class="kwrd">return</span> <span class="kwrd">true</span>; <br>    } <br>    <span class="kwrd">return</span> <span class="kwrd">false</span>; <br>} <br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Dim</span> WM_KEYDOWN <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 256<br><br><span class="kwrd">Protected</span> <span class="kwrd">Overrides</span> <span class="kwrd">Function</span> ProcessCmdKey(<span class="kwrd">ByRef</span> msg <span class="kwrd">As</span> Message, <span class="kwrd">ByVal</span> keyData <span class="kwrd">As</span> Keys) <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>    <span class="kwrd">If</span> (msg.Msg = WM_KEYDOWN) <span class="kwrd">Then</span><br>        <span class="kwrd">Select</span> <span class="kwrd">Case</span> (keyData)<br>            <span class="kwrd">Case</span> Keys.Up<br>                _service.SetOutput(Direction.Forward, <span class="kwrd">true</span>)<br>            <span class="kwrd">Case</span> Keys.Down<br>                _service.SetOutput(Direction.Backward, <span class="kwrd">true</span>)<br>            <span class="kwrd">Case</span> Keys.Left<br>                _service.SetOutput(Direction.Left, <span class="kwrd">true</span>)<br>            <span class="kwrd">Case</span> Keys.Right<br>                _service.SetOutput(Direction.Right, <span class="kwrd">true</span>)<br>        <span class="kwrd">End</span> <span class="kwrd">Select</span><br>        <span class="kwrd">Return</span> <span class="kwrd">true</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">Return</span> <span class="kwrd">false</span><br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This looks much like the button processors from above. </p>
<p>Just like the buttons, we also need a <b>KeyUp </b>event. Go back to the designer for the form and double-click on the
<b>KeyUp</b> event in the properties pane, just like we did with the mouse button events. This will generate an event stub for the
<b>KeyUp</b> event. Fill in the method with the following: </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> RemoteControlForm_KeyUp(<span class="kwrd">object</span> sender, KeyEventArgs e)<br>{<br>    <span class="kwrd">switch</span>(e.KeyCode)<br>    { <br>        <span class="kwrd">case</span> Keys.Up: <br>            _service.SetOutput(Direction.Forward, <span class="kwrd">false</span>); <br>        <span class="kwrd">break</span>; <br><br>        <span class="kwrd">case</span> Keys.Down: <br>            _service.SetOutput(Direction.Backward, <span class="kwrd">false</span>); <br>            <span class="kwrd">break</span>; <br><br>        <span class="kwrd">case</span> Keys.Left: <br>            _service.SetOutput(Direction.Left, <span class="kwrd">false</span>); <br>            <span class="kwrd">break</span>; <br><br>        <span class="kwrd">case</span> Keys.Right: <br>            _service.SetOutput(Direction.Right, <span class="kwrd">false</span>); <br>            <span class="kwrd">break</span>; <br>    } <br>} <br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> RemoteControlForm_KeyUp(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> System.<span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.Windows.Forms.KeyEventArgs) <span class="kwrd">Handles</span> <span class="kwrd">MyBase</span>.KeyUp<br>    <span class="kwrd">Select</span> <span class="kwrd">Case</span> (e.KeyCode)<br>        <span class="kwrd">Case</span> Keys.Up<br>            _service.SetOutput(Direction.Forward, <span class="kwrd">False</span>)<br>        <span class="kwrd">Case</span> Keys.Down<br>            _service.SetOutput(Direction.Backward, <span class="kwrd">False</span>)<br>        <span class="kwrd">Case</span> Keys.Left<br>            _service.SetOutput(Direction.Left, <span class="kwrd">False</span>)<br>        <span class="kwrd">Case</span> Keys.Right<br>            _service.SetOutput(Direction.Right, <span class="kwrd">False</span>)<br>    <span class="kwrd">End</span> <span class="kwrd">Select</span><br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now, if you execute the application again, you will be able to drive the car around just by pressing the arrow keys on the keyboard.
</p>
<h3><b>Gamepad Support</b></h3>
<p>If you own an Xbox 360 Controller for Windows, or a similar gamepad device, we can use it to drive our vehicle around. Ensure that the Xbox 360 Controller for Windows drivers are installed and the controller is working normally.
</p>
<p>To use the gamepad, we first need to partner with the gamepad service, much like we did with the PhidgetInterfaceKit service.
</p>
<p>First, set a reference to the <b>XInputGamepad.Y2006.M09.proxy</b> namespace. Bring the namespace into the
<b><a href="http://RCCar.cs/.vb" class="linkification-ext" title="Linkification: http://RCCar.cs/.vb">RCCar.cs/.vb</a>
</b>file by adding the following <b>using</b> statement, and then partner with the XInputGamepad service like we did with the Phidget service above:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode">[Partner(<span class="str">&quot;XInputGamepad&quot;</span>, Contract = gamepad.Contract.Identifier,<br>CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate)] <br><span class="kwrd">private</span> gamepad.XInputGamepadOperations _gamepadPort = <span class="kwrd">new</span> gamepad.XInputGamepadOperations(); <br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode">&lt;Partner(<span class="str">&quot;XInputGamepad&quot;</span>, Contract:=gamepad.Contract.Identifier, _<br>CreationPolicy:=PartnerCreationPolicy.UseExistingOrCreate)&gt; _<br><span class="kwrd">Private</span> _gamepadPort <span class="kwrd">As</span> <span class="kwrd">New</span> gamepad.XInputGamepadOperations()<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>With that in place, we now need to subscribe to the XInputGamepad service to receive notifications when the state of the controller changes.&nbsp;This code will be added to our previous
<b>SubscribeToServices</b> method:&nbsp; </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SubscribeToServices()<br>{<br>    _ikPort.SelectiveSubscribe(<span class="kwrd">null</span>, <span class="kwrd">new</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations());<br><br>    gamepad.XInputGamepadOperations _gamepadNotify = <span class="kwrd">new</span> gamepad.XInputGamepadOperations();<br><br>    Activate(Arbiter.Receive&lt;gamepad.DPadChanged&gt;(<span class="kwrd">true</span>, _gamepadNotify, GamepadDpadHandler));<br><br>    _gamepadPort.Subscribe(_gamepadNotify);<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SubscribeToServices()<br>    _ikPort.SelectiveSubscribe(<span class="kwrd">Nothing</span>, <span class="kwrd">New</span> phidgetinterfacekit.PhidgetInterfaceKitBoardsOperations())<br><br>    <span class="kwrd">Dim</span> _gamepadNotify <span class="kwrd">As</span> gamepad.XInputGamepadOperations = <span class="kwrd">New</span> gamepad.XInputGamepadOperations<br><br>    Activate(Arbiter.Receive(Of gamepad.DPadChanged)(<span class="kwrd">True</span>, _gamepadNotify, <span class="kwrd">AddressOf</span> GamepadDpadHandler))<br><br>    _gamepadPort.Subscribe(_gamepadNotify)<br><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This method creates a port named _gamepadNotify which will receive the notifications from the Gamepad service. The
<b>Activate</b> method sets up relationships between communication ports and arbiters. An arbiter is simply an object which automatically manages&nbsp;concurrency. So, the second line sets up a relationship between the _gamepadNotify port and a method we will implement,
<b>GamepadDpadHandler</b>. This is setup on the&nbsp;<b>DPadChanged</b> message. </p>
<p>The&nbsp;last line in the method sets up a subscription. A subscription is required to receive the messages on the port specified.&nbsp; You may wish to wrap the call to
<b>Subscribe</b> a call to <b>Arbiter.Choice</b>.&nbsp; This will allow you to determine if the subscription was successful or not, and display a message either way.&nbsp; The source package for this article contains the code on how this is done.&nbsp; For simplicity, it
 has been removed for the listing above. </p>
<p>Next, we must actually implement the <b>GamepadDpadHandler</b> method. It looks like the following snippet:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> GamepadDpadHandler(gamepad.DPadChanged msg)<br>{<br>    gamepad.DPad dpad = msg.Body;<br><br>    SetOutput(Direction.Forward, dpad.Up);<br>    SetOutput(Direction.Backward, dpad.Down);<br>    SetOutput(Direction.Left, dpad.Left);<br>    SetOutput(Direction.Right, dpad.Right);<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> GamepadDpadHandler(<span class="kwrd">ByVal</span> msg <span class="kwrd">As</span> gamepad.DPadChanged)<br>    <span class="kwrd">Dim</span> dpad <span class="kwrd">As</span> gamepad.DPad = msg.Body<br><br>    SetOutput(Direction.Forward, dpad.Up)<br>    SetOutput(Direction.Backward, dpad.Down)<br>    SetOutput(Direction.Left, dpad.Left)<br>    SetOutput(Direction.Right, dpad.Right)<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This code simply maps the current state of the d-pad to the outputs on the Phidget interface kit.&nbsp; We can also use the thumbsticks of the Xbox 360 controller to drive the vehicle.&nbsp; You will find the code for this in the source package linked above.
</p>
<p>With this code in place, we can once again press <b>F5</b> to build and execute the project. Ensure the Phidget board and the controller are connected. When the application runs, you will be able to drive the car with the left thumbstick.
</p>
<p><b>Note:</b> This <b>XInputGamepad</b> service specifically works with devices that are defined as gamepads. If you have a true analog joystick, like a flight stick, you will need to replace the code above with a partnership with the
<b>GameController</b> service instead of the <b>XInputGamepad</b> service and propagate accordingly.
</p>
<h3><b>The Camera</b></h3>
<p>Now that the car is up and running, we can add&nbsp;the code required to drive the wireless camera.&nbsp;
</p>
<p><b>&lt;NOTE FOR VB USERS&gt;</b> </p>
<p>Unfortunately, I have been unsuccessful in getting the following code to work in Visual Basic due to its lack of custom iterators (i.e. the lack of the
<b>yield</b> keyword).&nbsp; I am currently pursuing a workaround for this, but until one is found, the following section will consist of C# code only.&nbsp; I will update this portion of the&nbsp;article with VB code&nbsp;if/when a solution is found.
</p>
<p><b>&lt;/NOTE FOR VB USERS&gt;</b> </p>
<p>I decided to create a brand new service to operate the wireless camera so it could be later used in other projects very easily. In this section, we will learn how to create a brand new service and use it to post messages to other services that are listening.
</p>
<p>As with the RCCar service, you will use the dssnewservice.exe command to generate the template for the new service. Open the Robotics Studio Command Prompt as before and run the following:
</p>
<p><b>C#</b> </p>
<p><b>dssnewservice /service:NetCam </b></p>
<p>This will, as before, generate a directory and code for a new service named <b>
NetCam</b>. </p>
<p>Back in Microsoft C#&nbsp;Express 2005, right-click on the solution in the <b>Solution Explorer</b> and select
<b>Add -&gt; Existing Project</b> and navigate to the generated <b>NetCam.csproj</b> file. This will bring the project into our existing solution for easy editing and debugging.
</p>
<p>The first thing we need to do is add a reference to the <b>System.Drawing</b> assembly.&nbsp; This can be done as described above.
</p>
<p>Next, switch to the <b>NetCamTypes.cs</b> file. We will be using the <b>NetCamState</b> to store the most recently captured image from the camera. To do this, we will need to bring the
<b>System.Drawing</b> reference into the class and modify the <b>NetCamState</b> object to look like the following:
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> System.Drawing;<br><br>...<br><br>[DataContract()] <br><span class="kwrd">public</span> <span class="kwrd">class</span> NetCamState <br>{ <br>    <span class="kwrd">private</span> Bitmap _image; <br>    <span class="kwrd">private</span> <span class="kwrd">int</span> _size; <br>    <span class="kwrd">private</span> DateTime _timeStamp; <br><br>    <span class="kwrd">public</span> Bitmap Image <br>    { <br>        get { <span class="kwrd">return</span> _image; } <br>        set { _image = <span class="kwrd">value</span>; } <br>    } <br><br>    [DataMember] <br>    <span class="kwrd">public</span> Size Size <br>    { <br>        get <br>        { <br>            <span class="kwrd">if</span> (_image != <span class="kwrd">null</span>) <br>            { <br>                <span class="kwrd">return</span> _image.Size; <br>            } <br>            <span class="kwrd">return</span> Size.Empty; <br>        } <br>        set { <span class="kwrd">return</span>; } <br>    } <br><br>    [DataMember] <br>    <span class="kwrd">public</span> DateTime TimeStamp <br>    { <br>        get { <span class="kwrd">return</span> _timeStamp; } <br>        set { _timeStamp = <span class="kwrd">value</span>; } <br>    } <br>} </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>DataContract()</b> attribute states that the <b>NetCamState</b> object is serializable via XML. The
<b>DataMember</b> attribute must be added to every property and field that you would like to be serialized. A
<b>Bitmap </b>object cannot be directly serialized, so we will be working around that shortly.
</p>
<p>The network camera I chose for this project streams its live video feed via MotionJPEG, or MJPEG. This is a quirky little non-standard that basically sends a never-ending stream of JPG images down the pipe. When displayed fast enough, it looks like smooth
 animation. Think of an electronic flipbook and you've got the right idea. </p>
<p>The net cam expects a web request to its internal web server and then responds with a multipart response which is a stream of JPEG images, each prefaced with some boundary tags and information about the image ahead. A standard GET request to the camera's
 IP address will result in something that looks like the following: </p>
<pre>HTTP/1.0 200 OK <br>Server: Camera Web Server/1.0 <br>Auther: Steven Wu <br>MIME-version: 1.0 <br>Cache-Control: no-cache <br>Content-Type: multipart/x-mixed-replace;boundary=--video boundary-- <br>--video boundary--Content-length: 9052 <br>Date: 2006-10-01 22:21:47 IO_00000000_PT_000_114 <br>Content-type: image/jpeg <br>&lt;binary data of length 9052 bytes&gt; <br>--video boundary--Content-length: 9375 <br>Date: 2006-10-01 22:21:48 IO_00000000_PT_000_114 <br>Content-type: image/jpeg <br>&lt;binary data of length 9375 bytes&gt;</pre>
<p>Our <b>NetCam</b> service is going to connect to the network camera's MJPEG source URL and loop through the response data, pulling out each frame as it is downloaded. When a partnered service wishes to request the current frame, it will do so by sending
 the <b>QueryFrame</b> message that we are about to define. </p>
<p>Open the <b>NetCamType.cs</b> file and you will see class definitions for <b>NetCamOperations</b>,<b> Get</b>,<b>
</b>and <b>Replace</b>. Here we will add our new message. </p>
<p>Add a class named <b>QueryFrame</b> to the file with the rest of the request types.&nbsp; This will inherit from the base
<b>Query</b> object and define its request object, <b>QueryFrameRequest</b>, and it's response, one of two types: a
<b>QueryFrameResponse</b> object, or a <b>Fault</b> in case of an error.&nbsp; Next, we need to add this
<b>QueryFrame</b> message to the list of valid messages that <b>NetCamOperations</b> will handle. This is done by changing the class definition as shown.&nbsp; Finally, we need to create the definitions for the
<b>QueryFrameRequest</b> and <b>QueryFrameResponse</b> objects. </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> NetCamOperations : PortSet&lt;DsspDefaultLookup, DsspDefaultDrop, Get, QueryFrame&gt;<br>{<br>}<br><br><span class="kwrd">public</span> <span class="kwrd">class</span> QueryFrame : Query&lt;QueryFrameRequest, PortSet&lt;QueryFrameResponse, Fault&gt;&gt; <br>{<br>}<br><br>[DataContract] <br><span class="kwrd">public</span> <span class="kwrd">class</span> QueryFrameRequest <br>{ <br>} <br><br>[DataContract] <br><span class="kwrd">public</span> <span class="kwrd">class</span> QueryFrameResponse <br>{ <br>    [DataMember] <br>    <span class="kwrd">public</span> Size Size; <br><br>    [DataMember] <br>    <span class="kwrd">public</span> <span class="kwrd">byte</span>[] FrameBuffer; <br><br>    [DataMember] <br>    <span class="kwrd">public</span> DateTime TimeStamp; <br>} </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>As you can see, for right now, the <b>QueryFrameRequest</b> object remains empty, while the
<b>QueryFrameResponse</b> contains a handful of properties which define the size of the image, a byte buffer for the image data itself, and a timestamp for the time the image was grabbed.
</p>
<p>Now we need to handle the camera data itself and provide the current frame data to a service requesting it.&nbsp; This will be accomplished by creating a processing thread which will parse each image from the webcam into a JPEG image, store it in memory to pass
 as a response to a request for it, and repeat.&nbsp; Internally, we will parse&nbsp;our JPEG, post a message to an internal port stating that the current frame is ready,&nbsp;store the frame, and start over.&nbsp; Since many requests can be received concurrently, we will be using
 the built-in <b>Arbiter</b> class to manage incoming requests while at the same time, parsing the data from the webcam to ensure the service does not get into a situation where frame data is being manipulated while a request is simultaneously being processed.
</p>
<p>First, the internal message port will be created to handle notifications that a complete frame is available.&nbsp; The port will be named
<b>FramePort</b> and designed to handle messages of type <b>Frame</b>.&nbsp; The implementation these types can be added directly to the
<b>NetCam.cs</b> file either above or below the implementation of the <b>NetCamService</b> class.&nbsp; The
<b>Frame</b> class will be using types from the <b>System.Drawing</b> library, so ensure that the library is both referenced and imported.
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> System.Drawing;<br><span class="kwrd">using</span> System.Drawing.Imaging;<br><br>...<br><br><span class="kwrd">internal</span> <span class="kwrd">class</span> Frame<br>{<br>    <span class="kwrd">private</span> Bitmap _image;<br>    <span class="kwrd">private</span> Size _size;<br>    <span class="kwrd">private</span> DateTime _timeStamp;<br><br>    <span class="kwrd">public</span> Bitmap Image<br>    {<br>        get { <span class="kwrd">return</span> _image; }<br>        set { _image = <span class="kwrd">value</span>; }<br>    }<br><br>    <span class="kwrd">public</span> Size Size<br>    {<br>        get<br>        {<br>            <span class="kwrd">if</span> (_image != <span class="kwrd">null</span>)<br>            {<br>                <span class="kwrd">return</span> _image.Size;<br>            }<br>            <span class="kwrd">return</span> Size.Empty;<br>        }<br>        set { <span class="kwrd">return</span>; }<br>    }<br>    <br>    <span class="kwrd">public</span> DateTime TimeStamp<br>    {<br>        get { <span class="kwrd">return</span> _timeStamp; }<br>        set { _timeStamp = <span class="kwrd">value</span>; }<br>    }<br>}<br><br><span class="kwrd">internal</span> <span class="kwrd">class</span> FramePort : Port&lt;Frame&gt; { }</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now we need to hook up the <b>QueryFrameRequest</b> message so that it can be responded to from incoming requests, and we need to grab the data from the camera. To do this, first, add the following member variable definition to the top of the
<b>NetCamService</b> class along with a declaration of a boolean variable to maintain the status of the connection to the camera, and then modify the
<b>Start</b> method of the <b>NetCam</b> service to look like the snippet below: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">FramePort _framePort = <span class="kwrd">new</span> FramePort();<br><span class="kwrd">private</span> <span class="kwrd">bool</span> _connected = <span class="kwrd">false</span>;<br><br><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Start()<br>{<br>    <span class="kwrd">base</span>.Start();<br><br>    Activate( <br>        Arbiter.Interleave( <br>            <span class="kwrd">new</span> TeardownReceiverGroup(), <br>            <span class="kwrd">new</span> ExclusiveReceiverGroup( <br>                Arbiter.Receive(<span class="kwrd">true</span>, _framePort, FrameHandler) <br>            ), <br>            <span class="kwrd">new</span> ConcurrentReceiverGroup <br>            ( <br>                Arbiter.Receive&lt;QueryFrame&gt;(<span class="kwrd">true</span>, _mainPort, QueryFrameHandler) <br>            )<br>        ) <br>    ); <br><br>    DirectoryInsert();<br><br>    Thread t = <span class="kwrd">new</span> Thread(<span class="kwrd">new</span> ThreadStart(NetCamProcessor)); <br>    t.IsBackground = <span class="kwrd">true</span>; <br>    t.Start();<br><br>    LogInfo(LogGroups.Console, <span class="str">&quot;Service uri: &quot;</span>); <br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>You will notice a new <b>Arbiter</b> method. The <b>Interleave</b> allows you to setup several handlers at once, defining the concurrency of each. Handlers that require Exclusive access are registered in the
<b>ExclusiveReceiverGroup</b> constructor, and those that can be called simultaneously are registered in the
<b>ConcurrentReceiverGroup</b> constructor. </p>
<p>In the code above, we setup a handler on the internal <b>_framePort</b> port, calling the method
<b>FrameHandler</b>. Additionally, a handler is created on the main service port,
<b>_mainPort</b> for the <b>QueryFrame</b> message, which will be handled by the <b>
QueryFrameHandler</b> method. </p>
<p>Finally, a thread is created which will be responsible for connecting to the network camera and grabbing each JPEG image as it is sent. I am not going to list every single line here, but I will highlight the important points.&nbsp; The full code, of course, can
 be found in the source package.&nbsp; First, let's implement the <b>FrameHandler </b>
method.&nbsp; As described above, a message will be posted from the processing thread when a new frame is ready to be requested.&nbsp; The
<b>FrameHandler</b> method is the method that will respond to that notification.&nbsp; Simply, it will expect a
<b>Frame</b> object and store it away inside of the <b>NetCamState</b> object we created earlier.
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">private void</span> FrameHandler(Frame frame)<br>{<br>    _state.Image = frame.Image;<br>    _state.TimeStamp = frame.TimeStamp;<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, we need to implement the <b>NetCamProcessor</b> thread handler.&nbsp; The code here is a bit complex, and I have taken a number of shortcuts to make it as simple as possible.&nbsp; I am the first to admit that the parsing code is not very robust, however it
 will properly parse the output of the Airlink AIC-250W.&nbsp; The thread processor will use the
<b>HttpWebRequest</b> and <b>HttpWebResponse</b> methods of the <b>System.Net</b> class, several IO methods from
<b>System.IO</b> and the methods from the <b>System.Text</b> class.&nbsp; As always, ensure this is referenced and imported into the class.
</p>
<p>The processor will sit in an infinite loop which connects to the IP address of the camera, requests a specific page, and parses the MJPEG data as described earlier.&nbsp; When a full frame has been parsed, it posts that
<b>Frame</b> object to our internal <b>_framePort</b> to store away until a <b>QueryFrameRequest</b> comes in.
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> System.Net;<br><span class="kwrd">using</span> System.IO;<br><span class="kwrd">using</span> System.Text;<br><br>...<br><br><span class="kwrd">private</span> <span class="kwrd">void</span> CameraProcessor()<br>{<br>    <span class="kwrd">byte</span>[] buff = <span class="kwrd">new</span> <span class="kwrd">byte</span>[1024*1024];<br>    <span class="kwrd">byte</span>[] lenBuff = <span class="kwrd">new</span> <span class="kwrd">byte</span>[10];<br>    HttpWebRequest req = <span class="kwrd">null</span>;<br>    HttpWebResponse resp = <span class="kwrd">null</span>;<br>    Stream s = <span class="kwrd">null</span>;<br>    <span class="kwrd">int</span> len = 0;<br><br>    <span class="kwrd">while</span>(<span class="kwrd">true</span>)<br>    {<br>        <span class="kwrd">try</span><br>        {<br>            <span class="rem">// NOTE: change the IP address for the camera on your network</span><br>            req = (HttpWebRequest)HttpWebRequest.Create(<span class="str">&quot;<a href="http://192.168.1.100/mjpeg.cgi" class="linkification-ext" title="Linkification: http://192.168.1.100/mjpeg.cgi">http://192.168.1.100/mjpeg.cgi</a>&quot;</span>);<br>            resp = (HttpWebResponse)req.GetResponse();<br><br>            _connected = <span class="kwrd">true</span>;<br><br>            s = resp.GetResponseStream();<br>            BinaryReader br = <span class="kwrd">new</span> BinaryReader(s);<br><br>            <span class="kwrd">while</span>(<span class="kwrd">true</span>)<br>            {<br>                Array.Clear(buff, 0, buff.Length);<br>                Array.Clear(lenBuff, 0, lenBuff.Length);<br><br>                <span class="rem">// --video boundary--</span><br>                <span class="rem">// Content-length: </span><br>                buff = br.ReadBytes(34);<br><br>                <span class="rem">// content length</span><br>                <span class="kwrd">byte</span> by;<br>                <span class="kwrd">int</span> i = 0;<br>                <span class="kwrd">while</span>((by = br.ReadByte()) != 0x0d)<br>                    lenBuff[i&#43;&#43;] = by;<br>                len = <span class="kwrd">int</span>.Parse(Encoding.ASCII.GetString(lenBuff));<br><br>                <span class="rem">// Date: 2000-01-01 01:23:45 IO_00000000_PT_000_114</span><br>                <span class="rem">// Content-type: image/jpeg</span><br>                buff = br.ReadBytes(79);<br><br>                <span class="rem">// image data</span><br>                buff = br.ReadBytes(len);<br><br>                <span class="rem">// create a new Frame object and post it to our internal port</span><br>                Frame frame = <span class="kwrd">new</span> Frame();<br>                frame.Image = (Bitmap)Bitmap.FromStream(<span class="kwrd">new</span> MemoryStream(buff, 0, len));<br>                frame.TimeStamp = DateTime.Now;<br><br>                _framePort.Post(frame);<br><br>                <span class="rem">// new lines before the next --video boundary-- segment</span><br>                buff = br.ReadBytes(6);<br>            }<br>        }<br>        <span class="kwrd">catch</span>(Exception ex)<br>        {<br>            System.Diagnostics.Debug.WriteLine(ex.Message);<br>            _connected = <span class="kwrd">false</span>;<br>        }<br>        <span class="kwrd">finally</span><br>        {<br>            <span class="kwrd">if</span>(req != <span class="kwrd">null</span>)<br>                req.Abort();<br><br>            <span class="kwrd">if</span>(s != <span class="kwrd">null</span>)<br>                s.Close();<br><br>            <span class="kwrd">if</span>(resp != <span class="kwrd">null</span>)<br>                resp.Close();<br>        }<br>    }<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>NetCamProcessor</b> method connects to the mjpeg.cgi file on the network camera's IP address. Once connected, it loops forever reading data from the response stream, parsing out the
<b>Content-length</b> information and reading precisely that much information into a byte buffer. With this in hand, it fills in an instance of the
<b>Frame</b> object and posts that to the internal _framePort communications port. As we set it up earlier, the _framePort handles messages sent to it with the
<b>FrameHandler</b> method. This was setup in the exclusive group for a reason. Because images are streaming in as quickly as possible, before all processing can be completed and the next image arrives, by posting the message to the
<b>_framePort</b> port, the thread will block until the <b>FrameHandler</b> method returns, as this method was registered in the
<b>ExclusiveReceiverGroup</b> above.&nbsp; This will allow us to copy the current <b>Image</b> and
<b>TimeStamp</b> into the internal state object before moving on to the next image. Therefore, when a partnered service requests the current frame, it will return the current frame in the state object without worry of being overwritten mid-process.
</p>
<p>The final thing to setup in our <b>NetCamService</b> is the method to respond to the
<b>QueryFrame </b>message. Recall that this handler was setup in the constructor above.&nbsp; This code uses the
<b>Fault</b> object in the <b>W3C.Soap</b> namespace, so import accordingly. </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> W3C.Soap;<br><br>...<br><br><span class="kwrd">private</span> <span class="kwrd">void</span> QueryFrameHandler(QueryFrame query)<br>{<br>    QueryFrameResponse response = <span class="kwrd">new</span> QueryFrameResponse();<br><br>    <span class="kwrd">if</span>(!_connected)<br>    {<br>        response.Size = Size.Empty;<br>        response.FrameBuffer = <span class="kwrd">null</span>;<br>        response.TimeStamp = DateTime.MinValue;<br>        query.ResponsePort.Post(<span class="kwrd">new</span> Fault());<br>    }<br>    <span class="kwrd">else</span><br>    {<br>        <span class="kwrd">if</span>(_state.Image != <span class="kwrd">null</span>)<br>        {<br>            ImageFormat format = ImageFormat.Bmp;<br><br>            <span class="kwrd">using</span> (MemoryStream stream = <span class="kwrd">new</span> MemoryStream())<br>            {<br>                Size size = _state.Image.Size;<br>                _state.Image.Save(stream, format);<br><br>                response.TimeStamp = _state.TimeStamp;<br>                response.FrameBuffer = <span class="kwrd">new</span> <span class="kwrd">byte</span>[(<span class="kwrd">int</span>)stream.Length];<br>                response.Size = size;<br><br>                stream.Position = 0;<br>                stream.Read(response.FrameBuffer, 0, response.FrameBuffer.Length);<br>            }<br>            query.ResponsePort.Post(response);<br>        }<br>    }<br>}</pre>
<p>This method takes the current image stored in the internal state object and converts it into a byte stream to be returned in our previously defined
<b>QueryFrameResponse</b> object. The response object is then sent back to the caller via the
<b>ResponsePort</b> object contained within the passed in <b>QueryFrame</b> object.
</p>
<p>Now that we have the camera setup to grab images and allow requests for the currently available frame, we can partner with the service in our
<b>RCCar</b> service and display the live stream from the camera. </p>
<p>As with the other services, you will need to add a reference to the <b>NetCam</b> service. You can do this by adding a reference to the
<b>NetCam.Y200X.MYY</b> where X is the current year, and Y is the current month. Do not add add a reference to the project-level
<b>NetCam</b> assembly. </p>
<p>Now, switch back to the <b>RCCar.cs</b> file. At the top with the other partner definitions, add the following two lines to partner with the
<b>NetCam </b>service: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">[Partner(<span class="str">&quot;NetCam&quot;</span>, Contract = netcam.Contract.Identifier,<br>CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate)] <br><span class="kwrd">private</span> netcam.NetCamOperations _netcamPort = <span class="kwrd">new</span> netcam.NetCamOperations(); </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, we need to add a method which will continually send the <b>QueryFrame </b>
message to the <b>NetCam</b> service and handle the resulting image data. This can be accomplished by adding the following call to the
<b>Start</b> method: </p>
<p><b>C#</b> </p>
<pre class="csharpcode">SpawnIterator(NetCamHandler);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>SpawnIterator</b> method will allow you to call a method of type <b>IEnumerator&lt;ITask&gt;
</b>asynchronously.&nbsp;&nbsp;Let's take a look at the <b>NetCamHandler</b> method that is spawned.&nbsp; This will use code from the
<b>System.Threading</b> library, so import as usual. </p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> System.Threading;<br><br>...<br><br><span class="kwrd">private</span> IEnumerator&lt;ITask&gt; NetCamHandler()<br>{<br>    <span class="kwrd">bool</span> pollCamera = <span class="kwrd">true</span>;<br><br>    <span class="kwrd">while</span>(<span class="kwrd">true</span>)<br>    {<br>        <span class="rem">// wait a few ticks for the cam to get connected</span><br>        Thread.Sleep(4000);<br>        pollCamera = <span class="kwrd">true</span>;<br><br>        <span class="kwrd">while</span>(pollCamera)<br>        {<br>            <span class="rem">// send the QueryFrame message and send the result to our form to be displayed</span><br>            <span class="kwrd">yield</span> <span class="kwrd">return</span> Arbiter.Choice(<br>                _netcamPort.QueryFrame(<span class="kwrd">new</span> netcam.QueryFrameRequest()),<br>                <span class="kwrd">delegate</span>(netcam.QueryFrameResponse response)<br>                {<br>                    WinFormsServicePort.FormInvoke(<br>                        <span class="kwrd">delegate</span>()<br>                        {<br>                            _remoteForm.ImageUpdate(response);<br>                        }<br>                    );<br>                },<br>                <span class="kwrd">delegate</span>(Fault fault)<br>                {<br>                    LogError(<span class="str">&quot;Error querying frame from camera&quot;</span>);<br>                    pollCamera = <span class="kwrd">false</span>;<br>                }<br>            );<br>        }<br>    }<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This will wait for 4 seconds for the camera to become available and then continually poll the
<b>NetCam</b> service for the latest available frame. The <b>Choice</b> method from the
<b>Arbiter</b> object will allow you to send a message to a specified port and handle the result in both a success and a failure. In this case, we are creating a
<b>QueryFrameRequest</b> object, posting it to the <b>_netCam</b> port, and handing the response with two delegates, the first being the successful return, and the second being a fault from the
<b>NetCam</b> service. </p>
<p>When a valid <b>QueryFrameResponse</b> object is returned, the delegate we've defined calls the
<b>ImageUpdate</b> method on our user interface via <b>WinFormsServicePort.FormInvoke</b>&nbsp;to ensure that we do not attempt to update&nbsp;the UI thread from a thread other than it was created on.&nbsp;
<b>ImageUpdate</b> passes the <b>QueryFrameResponse</b> response object which contains the image data to be displayed.
</p>
<p>The <b>yield</b> keyword seen above is new to C# and .NET 2.0 .&nbsp; Also note that the
<b>NetCamHandler</b> method is defined as type <b>IEnumerator&lt;ITask&gt;</b>.&nbsp; When&nbsp;<b>yield return</b> is used with an enumerator, this tells the CCR that more data will be available.&nbsp; When
<b>yield break</b> is used, this signals the end of the enumeration.&nbsp; In this case, since we will constantly be polling images, this signals to the CCR that more data is forthcoming.
</p>
<p>On the <b>RemoteControlForm</b>, a&nbsp;<b>PictureBox</b> control must be added to display the images from the camera.&nbsp; Do this in the designer and set the box dimensions to 320x240, the default size returned by the network camera. Name the control
<b>pbImage</b>. </p>
<p>And finally,&nbsp;following code is added to the <b>RemoteControlForm.cs </b>class.&nbsp; Note that the following method,
<b>ImageUpdate</b>, uses methods from the <b>System.IO</b> and our <b>NetCam</b> namespaces, so import them at the top.
</p>
<p><b>C#</b> </p>
<pre class="csharpcode"><span class="kwrd">using</span> System.IO;<br><span class="kwrd">using</span> netcam = Robotics.NetCam.Proxy;<br><br>...<br><br><span class="kwrd">public</span> <span class="kwrd">void</span> ImageUpdate(netcam.QueryFrameResponse response)<br>{<br>    pbImage.Image = Bitmap.FromStream(<span class="kwrd">new</span> MemoryStream(response.FrameBuffer));<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This simply takes the response from our above <b>QueryFrame</b> request, turns it back into a
<b>Bitmap</b> object, and then assigns it to the PictureBox. </p>
<h3><b>We're Done!</b></h3>
<p>Pressing F5 to build and run the solution should now allow<b> </b>you to: </p>
<ul>
<li>Drive the car with the keyboard </li><li>Drive the car with the onscreen buttons </li><li>Drive the car with a gamepad controller </li><li>View the output from the network camera attached to the roof of the vehicle.</li></ul>
<p>So where do we go from here?&nbsp; Well, there are a variety of features that can be added to the project, such as:</p>
<ul>
<li>Implement the remote control form using the MSRS-included <b>DirectionDialog</b> form.&nbsp; Note that you will likely have to split out the camera display to a separate form.
</li><li>Implement the above with the VPL language. </li><li>Try building a new service for another platform (Lego NXT, BoeBot, etc.) and use the
<b>NetCam</b> service and IP camera with that. </li><li>Add configuration and state persistence to allow the IP address for the camera to be specified in an XML store instead of hard-coding it into the application.
</li><li>Add logic to replay a series of commands to drive the vehicle in a set path. </li><li>With the above, add motion detection code to have the car surprise an unsuspecting victim.
</li><li>If you are using a Phidget 0/16/16 or Phidget 8/8/8 board, find a remote control car with additional features,&nbsp;like&nbsp;the
<a href="http://www.tycorc.com/us/product.asp?category_type_id=19&amp;id=11840&amp;category_id=7819" target="_blank">
Tyco N.S.E.C.T</a>, assuming it has a digital vs. analog control unit.</li></ul>
<h3><b>Conclusion</b></h3>
<p>As you can see, Microsoft Robotics Studio is a very functional, very sophisticated and very complex library which tackles many of the issues involved with creating software for use in robotics.&nbsp; With the issues of concurrency and decentralization handled
 by the CCR and DSS runtimes, you are free to focus your efforts at building robust software for controlling the machine at hand.</p>
<h3>More Information</h3>
<p>Here are a few links regarding MSRS, the CCR and various other useful tidbits to help you along:</p>
<ul>
<li><a href="http://channel9.msdn.com/wiki/default.aspx/Channel9.ConcurrencyRuntime" title="http://channel9.msdn.com/wiki/default.aspx/Channel9.ConcurrencyRuntime" target="_blank">http://channel9.msdn.com/wiki/default.aspx/Channel9.ConcurrencyRuntime</a>
</li><li><a href="http://msdn.microsoft.com/msdnmag/issues/06/09/concurrentaffairs/default.aspx" title="http://msdn.microsoft.com/msdnmag/issues/06/09/concurrentaffairs/default.aspx" target="_blank">http://msdn.microsoft.com/msdnmag/issues/06/09/concurrentaffairs/default.aspx</a></li></ul>
<h3>Bio</h3>
<p>Though Brian is a recognized .NET expert with over 6 years experience developing .NET solutions, and over 9 years of professional experience architecting and developing solutions using Microsoft technologies and platforms, he has been &quot;coding for fun&quot; for
 as long as he can remember.&nbsp; Outside the world of .NET and&nbsp;business applications, Brian enjoys developing&nbsp;both hardware and software projects in the areas of gaming, robotics, and&nbsp;whatever else strikes his fancy for the next ten minutes.&nbsp;He rarely passes up
 an opportunity to dive into a C/C&#43;&#43;&nbsp;or assembly language project.&nbsp; You can reach Brian via his blog at
<a href="http://www.brianpeek.com/">http://www.brianpeek.com/</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:4b8ba91fbc7340858c8b9e7600d66856">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Computer-Controlled-RC-Car-with-Camera</comments>
      <itunes:summary>
&amp;nbsp; 






Control a remote controlled car with your computer using Microsoft Robotics Studio. Then, add a wireless IP camera for stealthy remote operation.



Brian Peek
ASPSOFT, Inc.

Difficulty: Advanced
Time Required: 
3-6 hours
Cost: $50-$100
Software: Visual Basic or Visual C# Express Editions,
Microsoft Robotics Studio,

Phidgets .NET and MSRS libraries 
Hardware: A remote-controlled car,

PhidgetInterfaceKit 0/0/4 OR 
PhidgetInterfaceKit 0/16/16, 
Airlink101 AIC-250W wireless camera (optional), 
Xbox 360 Controller for Windows (optional), batteries, wire, and solder
Download: Download
&amp;nbsp;
In 2005, we at ASPSOFT built the world&#39;s first .NET-powered battlebot known as
The Finalizer. Since then, many robotics enthusiasts and hobbyists have become intrigued with the idea of a .NET-controlled robot, but don&#39;t have the cash or hardware required to build something as elaborate
 as The Finalizer. With that in mind, I set out to create a very simple and very cheap computer controlled vehicle that anyone with a couple bucks and a computer could build.
&amp;nbsp;





What You Will Need

A remote-controlled vehicle with a digital controller. That is, a controller that uses switches for forward/backward/left/right, not potentiometers. The car used in this article is a vehicle from the “Dub
 City” collection by Jada Toys.
PhidgetInterfaceKit 0/0/4 – a USB-controlled board with 4 relays,
OR 
PhidgetInterfaceKit 0/16/16, -&amp;nbsp;USB-controlled digital IO boards (if you need to control more than 4 controls on your remote controlled car)
A soldering iron and some solder Some spare wire Microsoft Visual C# or Visual Basic 2005 Express Edition
Microsoft Robotics Studio
Optional: WiFi-enabled webcam. This article uses the 
Airlink101 AIC-250W wireless camera. Optional: 4 AA battery holder (6V total) to power the webcam. I used a battery holder from Radio Shack with part number

270-391A. Optional: DC Power Plug to connect to AA battery holder above. The size required is 5.5mm</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Computer-Controlled-RC-Car-with-Camera</link>
      <pubDate>Mon, 22 Jan 2007 07:51:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Computer-Controlled-RC-Car-with-Camera</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1507304_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1507304_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>20</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Computer-Controlled-RC-Car-with-Camera/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Robotics</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Introduction to the Make Controller Kit in C#</title>
      <description><![CDATA[
<p></p>
<p><b>Difficulty: </b>Easy </p>
<p><b>Time Required:</b> 1-3 hours </p>
<p><b>Cost: </b>$150 </p>
<p><b>Software: </b><a href="http://msdn.com/express/">Visual Studio Express Editions</a>
</p>
<p><b>Hardware: </b><a href="http://makezine.com/controller/">Make Controller Kit</a>
</p>
<p>The Make Controller Kit was developed by MakingThings in collaboration with Make Magazine to provide an open hardware platform that encourages experimentation, learning, and - most importantly - the creation of fun, interesting, and practical projects. We
 aim to provide the easiest possible way for creative people from all backgrounds to get involved making interactive devices in the physical world. The firmware and software tools used with the Make Controller Kit are open source, and the schematics and hardware
 information are freely available as well. </p>
<p><img height="353" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/mck_glamor4.jpg" width="450">
<br>
The Make Controller Kit </p>
<h4><strong>Project Possibilities</strong></h4>
<p>The flexibility of the Make Controller Kit enables a wide range of possible projects:
</p>
<ul>
<li>
<p>Control up to 4 DC motors to create a robotic platform.</p>
</li><li>
<p>Connect to your LAN or other web service to enable networked and distributed projects. Control your garage door opener, or jointly monitor carbon dioxide levels with other users across town or across the state.
</p>
</li><li>
<p>Use up to 8 analog inputs to log data on your PC, or provide custom control mechanisms for your programs.
</p>
<ul>
<li>
<p>Track the temperature in your house over several weeks.</p>
</li><li>
<p>Monitor the amount of electricity your appliances use.</p>
</li><li>
<p>Use a motion detector to alert your desktop applications to the presence of a person.
</p>
</li></ul>
</li><li>Control animations or other feedback devices with 4 standard servo controllers.
</li></ul>
<h4><strong>Structure/Architecture of the Make Controller Kit</strong></h4>
<p>The Make Controller Kit consists of two parts – the Controller Board and the Application Board. The Controller Board includes the microcontroller itself – the SAM7X256 from Atmel – and brings the majority of its signal lines out to standard 0.1” spaced headers.
 The Controller Board physically plugs into the Application Board, which includes the hardware necessary to connect to real devices – motors, sensors, and lights, among others. Alternatively, the Controller Board can be plugged into a circuit of your own design.
 Because the Controller Board is common to both, everybody benefits from and contributes to the same software tools.
</p>
<p><img height="287" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/Controller4.jpg" width="250">
<br>
The Make Controller Board </p>
<p>By default, the Make Controller Kit can connect as an interface to a PC either via Ethernet or USB – then you create desktop applications that talk to the Controller to read sensor data, or to control motors or lights. The board itself can also be reprogrammed
 to run standalone from the PC – firmware is written in C, and can be easily uploaded via USB.
</p>
<h4><strong>.NET and the Make Controller Kit</strong></h4>
<p>The <strong>.NET C#</strong> library for the Make Controller Kit is designed to make it as simple as possible for developers to integrate the Make Controller Kit into their desktop applications, offering the transparency that makes open source software so
 rewarding to work with. You can communicate with the Make Controller Kit from your applications over either an Ethernet or USB connection, or both. The library is supplied both in source form and built, as
<strong>MakeControllerOsc.dll</strong> </p>
<h4><strong>Communication</strong></h4>
<p>Messages to and from the board conform to the <strong>OSC</strong> (Open Sound Control) protocol. OSC is an open, transport-independent standard supported by an increasing number of environments and devices.
</p>
<p>OSC messages are represented by the class <strong>OscMessage</strong>, and consist of two elements:
</p>
<ol>
<li>
<p>An <strong>address</strong> string for the device on the board you're dealing with.</p>
</li><li>
<p>A list of<strong> value</strong>(s) being sent to or from that device. The list of values is optional.</p>
</li></ol>
<p>From the perspective of OSC addresses, the Make Controller Kit is organized into a hierarchy of two or three layers:
</p>
<ul>
<li>
<p><strong>subsystems</strong> – classes of device, such as analog inputs, servo controllers, and digital outputs.</p>
</li><li>
<p><strong>devices</strong> – the index of a specific device within a subsystem. If there is only one device in a subsystem, the device is not included in the OSC address.</p>
</li><li>
<p><strong>properties</strong> – different devices have different properties, such as the value of an analog input, the position of a servo motor, or the state of an LED.
</p>
</li></ul>
<p>OSC messages always begin with a slash, and use a slash to delimit each element in the address, so an example OSC address string would look like:</p>
<pre><strong>/subsystem/device/property</strong>
 </pre>
<p>The second part of an OscMessage is a list of values to be sent to the specified address. The OSC types that are used by the Make Controller Kit for these values are integers, floats, and strings. The values in this list are simply separated by spaces, and
 the list can be arbitrarily long. Most devices on the Make Controller Kit expect only one value. For example, to set the position of servo 1, you might send a message which in string form might look like:</p>
<pre> <strong>/servo/1/position  512</strong>
 </pre>
<p>This addressing scheme allows interactions with the board's various subsystems and properties, and most importantly, accommodates the possibility of future or custom devices on the board that have not yet been implemented or imagined. If somebody creates,
 for example, a GPS extension to the board, communicating with that device from this library is the same as for any other. More details about OSC can be found at www.opensoundcontrol.org.
</p>
<h4><strong>Sending Data</strong></h4>
<p>As previously mentioned, the Make Controller Kit can communicate over both Ethernet and USB. Messages are sent as packets, both over USB and UDP, and corresponding structures are used –
<strong>UsbPacket</strong> and <strong>UdpPacket</strong>. Once you've created a packet, you can simply call its Send() method, with the OscMessage you'd like to send. There are helper methods to create an OscMessage from a string, or you can pass in the OscMessage
 itself. </p>
<p>For example, you might set up your <strong>UsbSend()</strong> routine to look something like:</p>
<pre>public  void usbSend(string text)
{
  OscMessage  oscM = Osc.StringToOscMessage(text);
  // oscUsb is  an Osc object, connected to a UsbPacket object
  oscUsb.Send(oscM);
}</pre>
<p>If your data is already in the form of an OscMessage, you can call <strong>oscUsb.Send()</strong> directly.
</p>
<h4><strong>Reading Data</strong></h4>
<p>The Make Controller Kit must be polled in order to read data from it. To do this, send an OscMessage with the address of the device you'd like to read, but omit the list of values. When the board receives an OscMessage with no value, it interprets that as
 a read request, and sends back an OscMessage with the current value at the appropriate address.
</p>
<p>The .NET Make Controller Kit library conveniently provides handlers that will call back a given function when an OscMessage with a given address string is received. Your implementation could look something like:</p>
<pre>// Set the handler in the constructor for a particular address
MyConstructor()
{
  udpPacket  = new  UdpPacket();
  oscUdp  = new  Osc(udpPacket);
  // A thread  is started when the Osc object is created to read 
  // incoming  messages.
  oscUdp.SetAddressHandler(&quot;/analogin/0/value&quot;,  Ain0Message);
}</pre>
<pre>//  The method you specified as the handler will be called back when a 
//  message with a matching address string comes back from the board.</pre>
<pre>public  void AIn0Message(OscMessage oscMessage)
{
  // write the  message to a console, for example
  mct.WriteLine(&quot;AIn0  &gt; &quot; &#43; Osc.OscMessageToString(oscMessage));<br>}</pre>
<p>You could alternatively set a handler for all incoming messages by calling the SetAllMessageHandler() method in your setup, instead of SetAddressHandler().
</p>
<h4><strong>System Commands</strong></h4>
<p>In addition to reading and writing to the IO devices on the board, you can also programmatically read/write parameters of your Make Controller Kit's configuration. For instance, you can check its serial number (good for uniquely identifying it), read and/or
 change its IP address, or tell it to shut down. </p>
<h4><strong>Quick Code Examples</strong></h4>
<p>We've put together a few simple code examples to demonstrate a few of the board's capabilities, and to give developers a place to start in creating their own applications.
</p>
<ol>
<li><strong>CPU Monitor</strong> – a servo motor moves an indicator to show how busy your machine is. The application uses the System.Diagnostics PerformanceCounter class to monitor CPU usage.
</li></ol>
<p><img height="86" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/CpuMonitor_screen4.png" width="283">
<br>
The onscreen UI </p>
<p><img height="350" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/DeskTimer_overview_4004.png" width="400">
<br>
The complete physical system </p>
<blockquote>
<p>Every 250ms the counter is examined and if the CPU usage is different from last time a new value is sent to the servo. The servo is set to move relatively slowly so the signal is smoothed out a little.
</p>
</blockquote>
<p><img height="300" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/CpuMonitor_close_servo_2504.png" width="250">
<br>
The servo motor </p>
<p><img height="300" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/CpuMonitor_close_panel_2504.png" width="250">
<br>
The dial being turned by the servo motor </p>
<blockquote>
<p><strong>Desktop Timer – </strong>a distance measuring sensor points out from the monitor on your computer and, if it finds you in front of it begins counting how long you're at your desk. If you go away, the work timer stops and the away counter begins.
</p>
<p><img height="350" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/DeskTimer_overview_4009.png" width="400">
</p>
</blockquote>
<blockquote>
<p>The Distance Measuring Sensor provides a varying voltage depending on how close a target is in front of it. This voltage is converted into a number by the Make Controller Kit whenever the desktop polls the board for it. When the value exceeds a certain amount,
 the computer decides someone's at the desk and the Working counter is incremented. If the signal is above that amount for longer than 5 seconds, the Away counter is incremented instead.
</p>
<p><img height="150" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/DeskTimer_screen5.png" width="302">
</p>
<p><strong>MCTest </strong>- a .NET application similar to <strong>mchelper</strong> that allows users to send OSC messages to the Make Controller Kit over USB and Ethernet from a command line. Great for testing and debugging the board, and familiarizing yourself
 with the OSC protocol that it runs. </p>
</blockquote>
<p><img height="425" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1378305/MCTest4.png" width="500">
</p>
<h4><strong>Application Deployment</strong></h4>
<p>To run your application, you'll need to do a few things: </p>
<ul>
<li>
<p>Confirm that your Make Controller Kit is running appropriate firmware – the default firmware, called Heavy, is fine.</p>
</li><li>
<p>Make sure the application has access to the MakeControllerOsc.dll assembly, by placing it either in the same directory as the application, or in a shared location.</p>
</li></ul>
<h4><strong>Summary</strong></h4>
<p>The Make Controller Kit is provides a friendly, open, and extensible environment for creating interactive devices, exhibits, and installations. Users are continually creating new applications and examples that can be easily shared with others. Because the
 Make Controller Kit is accessible and rewarding for users all the way from elementary school students to professional engineers, there is a vibrant community working with and advancing this platform. We look forward to seeing what you create with it.
</p>
<h4><strong>Links</strong></h4>
<p>MakingThings home - <a href="http://www.makingthings.com/makecontrollerkit">www.makingthings.com/makecontrollerkit</a>
</p>
<p>Make forums - <a href="http://forums.makezine.com/?CategoryID=5">http://forums.makezine.com/?CategoryID=5</a>
</p>
<p>Getting Started With the Make Controller Kit and .NET C# - <a href="http://www.makingthings.com/makecontrollerkit/guides/dotnet.html">
http://www.makingthings.com/makecontrollerkit/guides/dotnet.html</a> </p>
<p>Make Controller Kit .NET C# Reference - <a href="http://www.makingthings.com/makecontrollerkit/software/doc/dotnet/html/">
http://www.makingthings.com/makecontrollerkit/software/doc/dotnet/html/</a></p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:9fb010aded1b433ebcb69e7600d6ccd9">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Introduction-to-the-Make-Controller-Kit-in-C</comments>
      <itunes:summary>
 
Difficulty: Easy  
Time Required: 1-3 hours  
Cost: $150  
Software: Visual Studio Express Editions
 
Hardware: Make Controller Kit
 
The Make Controller Kit was developed by MakingThings in collaboration with Make Magazine to provide an open hardware platform that encourages experimentation, learning, and - most importantly - the creation of fun, interesting, and practical projects. We
 aim to provide the easiest possible way for creative people from all backgrounds to get involved making interactive devices in the physical world. The firmware and software tools used with the Make Controller Kit are open source, and the schematics and hardware
 information are freely available as well.  


The Make Controller Kit  
Project Possibilities
The flexibility of the Make Controller Kit enables a wide range of possible projects:
 


Control up to 4 DC motors to create a robotic platform. 

Connect to your LAN or other web service to enable networked and distributed projects. Control your garage door opener, or jointly monitor carbon dioxide levels with other users across town or across the state.
 

Use up to 8 analog inputs to log data on your PC, or provide custom control mechanisms for your programs.
 


Track the temperature in your house over several weeks. 

Monitor the amount of electricity your appliances use. 

Use a motion detector to alert your desktop applications to the presence of a person.
 

Control animations or other feedback devices with 4 standard servo controllers.

Structure/Architecture of the Make Controller Kit
The Make Controller Kit consists of two parts – the Controller Board and the Application Board. The Controller Board includes the microcontroller itself – the SAM7X256 from Atmel – and brings the majority of its signal lines out to standard 0.1” spaced headers.
 The Controller Board physically plugs into the Application Board, which includes the hardware necessary to connect to real devices – motors, sensors, and lights, among others. Alt</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Introduction-to-the-Make-Controller-Kit-in-C</link>
      <pubDate>Fri, 29 Dec 2006 00:11:49 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Introduction-to-the-Make-Controller-Kit-in-C</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1378305_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1378305_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Introduction-to-the-Make-Controller-Kit-in-C/RSS</wfw:commentRss>
      <category>Robotics</category>
      <category>hardwarehacks</category>
    </item>
  <item>
      <title>Controlling a Microbric Viper Robot with a custom IR Serial Port using .NET</title>
      <description><![CDATA[
<p><b>Summary:</b> In this installment of &quot;Some Assembly Required&quot;, Scott Hanselman&nbsp;teams up with the makers of the
<a href="http://www.microbric.com/">Microbric</a>&nbsp;Viper Robot and the guys at <a href="http://iguanaworks.net/ir/">
Iguanaworks</a>&nbsp;to create a custom IR serial port board to control the Viper Robot using .NET!
</p>
<h2><b>Introduction</b> </h2>
<p>The Microbric Viper is a robot construction kit based on a new solderless construction technique. The Viper uses a
<a href="http://www.microbric.com/page.php?sId=26">Basic Atom</a> microcontroller that you program, shockingly,&nbsp;using BASIC. Modules like an
<a href="http://www.microbric.com/page.php?sId=31">Infrared Receiver</a>, motors and switches can be fairly easily controlled as you just screw them directly into the mainboard and address them by number. Once I got my hands on a Microbric, I started trying
 to talk to the robot using my laptop's Infrared Port. It turns out after a number of failed attempts that Windows doesn't expose standard laptop IR ports as Serial Ports or in any way other than via the
<a href="http://en.wikipedia.org/wiki/IrDA">IRDA</a>&nbsp;protocol. IRDA was not only overkill for this kind of communication but also a hassle to program to. What I really needed was an IR transmitter that I could talk to using an interface that was clear and clean
 like the Serial Port&nbsp;interface exposed by System.IO.Ports. </p>
<p>I approached the guys at <a href="http://iguanaworks.net/ir/">Iguanaworks</a>&nbsp;as they make an infrared transceiver that is addressable via a standard Serial Port. The Viper comes with a Sony Remote Control so I set off to figure out how to get the Iguanaworks
 IR transmitter to speak to the Viper using .NET. </p>
<h2><b>Programming the Microbric Viper Robot</b> </h2>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0018.jpg"><img title="" height="212" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image001_thumb3.jpg" width="240" align="right" border="0"></a>The IR receiver module is
 screwed into the Microbric Viper, in my case, into the addressable P14 port on the side of the main body. The Viper includes a main chip called the Basic Atom that is flashed using BASIC programs written in an included BASIC IDE. In my BASIC file a constant
 is used to address the IR &quot;Data Pin,&quot; in this case, P14. </p>
<p>The Basic Atom includes a number of BASIC helper methods that the microprocessor uses to talk to the&nbsp;external world. The &quot;<strong>pulsin</strong>&quot; method&nbsp;is used to talk to the IR Data&nbsp;Pin&nbsp;and detect a pulse.&nbsp;Infrared receivers use high-speed pulses at a
 certain frequency (how fast it flashes) and duty cycle (a percentage of how long the LED is on versus off). These pulses of light continue for a set amount of time to indicate ones, zeros or the header.
</p>
<h2><b>How the Sony Infrared Protocol works</b> </h2>
<p>I'm trying to pulse the IR LED to emulate&nbsp;the Sony Remote Control, and started by looking for some information on how the Sony Infrared Protocol (SIRC) works. I found two excellent writeups.
</p>
<ul>
<li><a href="http://www.hifi-remote.com/infrared/IR-PWM.shtml">Excellent explanation about how IR works.
</a></li><li>Details of the <a href="http://www.sbprojects.com/knowledge/ir/sirc.htm">SIRC (Sony Infrared Control) Protocol.</a></li></ul>
<p>IR Protocols are fairly sensitive to timing. The pulses need to happen at specific intervals with the correct frequency.&nbsp; Because the timing is so fine-grained, I'm using the new System.Diagnostic.Stopwatch class in .NET (a wrapper for the Win32 QueryPerformanceCounter
 API)&nbsp;that uses Ticks for its unit of measurement. The Frequency is 2992540000 ticks per second, so I figure that'd be enough resolution.
</p>
<p>The Sony remote I'm trying to emulate uses a 40kHz frequency, so it wants to flash the LED one cycle, once, every 1/40000 of&nbsp;a second. That means every 74814 ticks or every 25µs (microseconds are 1/1000000 of a second.)
</p>
<p>I'm trying to send a header pulse of 2.4ms in length and I need to cycle the LED once every 25µs. I turn it on for 8µs and turn if off for 17µs. That means it will cycle 96 (2400µs) times for the header, 24 (1200µs) times for a space or zero, and 48 (600µs)times
 for a one. An image from <a href="http://www.sbprojects.com/knowledge/ir/sirc.htm">
San Bergmans</a> illustrates: </p>
<p><img height="125" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0029.gif" width="450" border="0">
</p>
<p>The <a href="http://iguanaworks.net/ir/">Iguanaworks IR</a>&nbsp;serial port board uses DTR (Data Terminal Ready) to turn on the IR LED. When DTR is high, the LED lights up, when it's off, the LED turns off. Using the Stopwatch and some really tight loops I figure
 I can flash (pulse) the LED fast enough. </p>
<blockquote>
<p><i>Now at this point, you may, dear reader, have already had the thought that perhaps trying to flash the LED via software, rather than hardware,&nbsp;is an astonishingly bad idea. Well, I could have used your insight earlier, my friend. But, on with my tale,
 as it is the telling that is so enjoyable, right?.</i> </p>
</blockquote>
<p>We'll take a look at more details of the internal implementation of the Sony Protocol in a moment.
</p>
<p><b><i>INTERESTING REMINDER:</i></b><b> </b>Remember, you can't see IR (it's infrared, therefore not in our visible spectrum) but you can see it if you point it at a Webcam or digital camera, which is what I've been doing to sanity check the hardware. The
 picture at left is an image of the LED pointed at my Logitech Webcam. </p>
<h2><b>Infrared Serial Port&nbsp;via Software</b> </h2>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/irimage_5b3_5d.png"></a><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0046.gif"><img title="" height="246" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image004_thumb1.gif" width="330" align="right" border="0"></a><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/irimage_5b3_5d.png"></a>Of
 course, I've started with managed code, because I'm a managed kind of a guy. I started using System.IO.Ports to address the Iguanaworks IR transmitter that is connected to a serial point on my PC. They make both a Serial Port and a USB version, but there are
 not yet drivers for the USB version so I got a three-foot long serial extension cord and went to work.
</p>
<h3><b><i>ASIDE: Where does the Power come from?</i></b><i> </i></h3>
<p>The Iguanaworks IR is a uniquely high-power transmitter that charges up a&nbsp; capacitor in order to provide a range of up to 10-meters. Your mileage may vary. However, it requires a few minutes to charge up the capacitor. Once it is charged up, however, even
 if you are using it constantly, it'll find a comfortable middle place where the output matches the input. If you use it intermittently, which is more typical, you'll likely get very good range and bright output. In my initial testing, though, while I had no
 trouble getting output from it using <a href="http://winlirc.sourceforge.net/">Winlirc</a>&nbsp;(the only
<b>officially</b> supported Open Source software package for this transmitter) but when I used my application, the transmitter would peter out and eventually go dim.&nbsp; What the heck was going on?
</p>
<p>I fought with it for a while, then decided to RTFS (where &quot;S&quot; is &quot;Schematic). The
<a href="http://iguanaworks.net/ir/ir_schematic.pdf">board layout is here</a>.&nbsp;Notice that the RTS (Serial Port Ready-To-Send) Pin 7 goes straight to VoltageIn. Duh! &lt;slaps forehead&gt;. They are
<a href="http://www.tkk.fi/misc/electronics/circuits/rspower.html">sipping power off the Ready To Send</a> pin and I'm not setting that pin hot via RtsEnable.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>port = <span class="kwrd">new</span> SerialPort(portString); </pre>
<pre><span class="lnum">   2:  </span>port.RtsEnable = <span class="kwrd">true</span>; <span class="rem">//needed for power! </span></pre>
<pre class="alt"><span class="lnum">   3:  </span>port.BaudRate = 115200; </pre>
<pre><span class="lnum">   4:  </span>port.StopBits = StopBits.One; </pre>
<pre class="alt"><span class="lnum">   5:  </span>port.Parity = Parity.None; </pre>
<pre><span class="lnum">   6:  </span>port.DataBits = 7; </pre>
<pre class="alt"><span class="lnum">   7:  </span>port.Handshake = Handshake.None; </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>So, if you ever find yourself using the High-Power LIRC Transmitter/Receiver in an unsupported way writing your own program, remember to set RTS high or you won't get any power. Heh!
</p>
<p>Back to the narrative. I suspected I might be writing more than one serial port class, or possibly using different pieces of hardware, so I defined an IIRSerialPort interface with some basics like On, Open, Off, etc. Since the Iguanaworks IR uses DTR to
 turn on the LED, it was as easy as setting the port's DtrEnable property to true to get a solid LED output.
</p>
<p>Here's part of the first Managed IR Serial Port class. </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> ManagedIRSerialPort : IIRSerialPort </pre>
<pre><span class="lnum">   2:  </span>{ </pre>
<pre class="alt"><span class="lnum">   3:  </span>  SerialPort port = <span class="kwrd">null</span>; </pre>
<pre><span class="lnum">   4:  </span> </pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">public</span> ManagedIRSerialPort(<span class="kwrd">string</span> portString) </pre>
<pre><span class="lnum">   6:  </span>  { </pre>
<pre class="alt"><span class="lnum">   7:  </span>   port = <span class="kwrd">new</span> SerialPort(portString); </pre>
<pre><span class="lnum">   8:  </span>   port.RtsEnable = <span class="kwrd">true</span>; <span class="rem">//needed for power! </span></pre>
<pre class="alt"><span class="lnum">   9:  </span>   port.BaudRate = 115200; </pre>
<pre><span class="lnum">  10:  </span>   port.StopBits = StopBits.One; </pre>
<pre class="alt"><span class="lnum">  11:  </span>   port.Parity = Parity.None; </pre>
<pre><span class="lnum">  12:  </span>   port.DataBits = 7; </pre>
<pre class="alt"><span class="lnum">  13:  </span>   port.Handshake = Handshake.None; </pre>
<pre><span class="lnum">  14:  </span>  } </pre>
<pre class="alt"><span class="lnum">  15:  </span> </pre>
<pre><span class="lnum">  16:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Open() </pre>
<pre class="alt"><span class="lnum">  17:  </span> { </pre>
<pre><span class="lnum">  18:  </span>   port.Open(); </pre>
<pre class="alt"><span class="lnum">  19:  </span> } </pre>
<pre><span class="lnum">  20:  </span> </pre>
<pre class="alt"><span class="lnum">  21:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> On() </pre>
<pre><span class="lnum">  22:  </span> { </pre>
<pre class="alt"><span class="lnum">  23:  </span>   port.DtrEnable = <span class="kwrd">true</span>; </pre>
<pre><span class="lnum">  24:  </span> } </pre>
<pre class="alt"><span class="lnum">  25:  </span> </pre>
<pre><span class="lnum">  26:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Off() </pre>
<pre class="alt"><span class="lnum">  27:  </span> { </pre>
<pre><span class="lnum">  28:  </span>   port.DtrEnable = <span class="kwrd">false</span>; </pre>
<pre class="alt"><span class="lnum">  29:  </span> } </pre>
<pre><span class="lnum">  30:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  31:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Close() </pre>
<pre><span class="lnum">  32:  </span> { </pre>
<pre class="alt"><span class="lnum">  33:  </span>  port.Close(); </pre>
<pre><span class="lnum">  34:  </span> } </pre>
<pre class="alt"><span class="lnum">  35:  </span>} </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This class is just the beginning, as it only turns the LED on and off. Remember I need to &quot;pulse&quot; the LED, turning it on and off 96 times all in the space of 2400µs. I wrote a SendPulse that spun very tightly and used the StopWatch class to manage timing.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">unsafe</span> <span class="kwrd">void</span> SendPulse(<span class="kwrd">long</span> microSecs) </pre>
<pre><span class="lnum">   2:  </span>{ </pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">long</span> end = LastTimeInTicks &#43; (microSecs * (STOPWATCHFREQ / MILLION)); </pre>
<pre><span class="lnum">   4:  </span>  <span class="kwrd">int</span> i = 0; </pre>
<pre class="alt"><span class="lnum">   5:  </span>  timer.Reset(); </pre>
<pre><span class="lnum">   6:  </span>  timer.Start(); </pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">do</span> </pre>
<pre><span class="lnum">   8:  </span>  { </pre>
<pre class="alt"><span class="lnum">   9:  </span>    i&#43;&#43;; </pre>
<pre><span class="lnum">  10:  </span>    port.On(); </pre>
<pre class="alt"><span class="lnum">  11:  </span>    MicroWait(pulseWidth); </pre>
<pre><span class="lnum">  12:  </span>    port.Off(); </pre>
<pre class="alt"><span class="lnum">  13:  </span>    MicroWait(spaceWidth); </pre>
<pre><span class="lnum">  14:  </span>  } </pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">while</span> (LastTimeInTicks &lt; end); </pre>
<pre><span class="lnum">  16:  </span>  timer.Stop(); </pre>
<pre class="alt"><span class="lnum">  17:  </span>  System.Diagnostics.Debug.WriteLine(i.ToString() &#43; <span class="str">&quot; pulses in &quot;</span> &#43; timer.ElapsedTicks/(<span class="kwrd">double</span>)  req*MILLION&#43;<span class="str">&quot;us&quot;</span>); </pre>
<pre><span class="lnum">  18:  </span>} </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Even with lots of optimization, I just couldn't get it to cycle fast enough. Remember, I need the header to take 2400µs total. In this screenshot, you can see it's taking an average of 30000µs! That sucks - it's 10 times slower than I need it to be.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0065.gif"><img height="340" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image006_thumb.gif" width="500" border="0"></a>
</p>
<p>So I futzed with this for a while, and then Reflector'd around. I noticed the implementation of set_dtrEnable inside of System.IO.Ports.SerialStream was WAY more complicated than it needed to be for my purposes.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="rem">//Reflector'd Microsoft code from inside System.IO.Ports.Port </span></pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">internal</span> <span class="kwrd">bool</span> DtrEnable </pre>
<pre class="alt"><span class="lnum">   3:  </span>{ </pre>
<pre><span class="lnum">   4:  </span> get </pre>
<pre class="alt"><span class="lnum">   5:  </span> { </pre>
<pre><span class="lnum">   6:  </span>   <span class="kwrd">int</span> num1 = <span class="kwrd">this</span>.GetDcbFlag(4); </pre>
<pre class="alt"><span class="lnum">   7:  </span>   <span class="kwrd">return</span> (num1 == 1); </pre>
<pre><span class="lnum">   8:  </span> } </pre>
<pre class="alt"><span class="lnum">   9:  </span> set </pre>
<pre><span class="lnum">  10:  </span> { </pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">int</span> num1 = <span class="kwrd">this</span>.GetDcbFlag(4); </pre>
<pre><span class="lnum">  12:  </span>  <span class="kwrd">this</span>.SetDcbFlag(4, <span class="kwrd">value</span> ? 1 : 0); </pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">if</span> (!UnsafeNativeMethods.SetCommState(<span class="kwrd">this</span>._handle, <span class="kwrd">ref</span> <span class="kwrd">this</span>.dcb)) </pre>
<pre><span class="lnum">  14:  </span>  { </pre>
<pre class="alt"><span class="lnum">  15:  </span>    <span class="kwrd">this</span>.SetDcbFlag(4, num1); </pre>
<pre><span class="lnum">  16:  </span>    InternalResources.WinIOError(); </pre>
<pre class="alt"><span class="lnum">  17:  </span>  } </pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">if</span> (!UnsafeNativeMethods.EscapeCommFunction(<span class="kwrd">this</span>._handle, <span class="kwrd">value</span> ? 5 : 6)) </pre>
<pre class="alt"><span class="lnum">  19:  </span>  { </pre>
<pre><span class="lnum">  20:  </span>    InternalResources.WinIOError(); </pre>
<pre class="alt"><span class="lnum">  21:  </span>  } </pre>
<pre><span class="lnum">  22:  </span> }</pre>
<pre class="alt"><span class="lnum">  23:  </span>} </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>All&nbsp;I figured I needed to do was call the Win32 API EscapeCommFunction to set the DTR pin high. One thing I learned quickly was that calling EscapeCommFunction was 4 times faster than calling SetCommState for the purposes of raising DTR, so in this code
 sample those lines are commented out. </p>
<p>I then wrote another implementation of IIRSerialPort, still in managed code, but this one talking to the COM Port using the underlying Win32 APIs.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> UnmanagedIRSerialPort : IIRSerialPort </pre>
<pre><span class="lnum">   2:  </span>{ </pre>
<pre class="alt"><span class="lnum">   3:  </span> IntPtr portHandle; </pre>
<pre><span class="lnum">   4:  </span> DCB dcb = <span class="kwrd">new</span> DCB(); </pre>
<pre class="alt"><span class="lnum">   5:  </span> <span class="kwrd">string</span> port = String.Empty; </pre>
<pre><span class="lnum">   6:  </span> <span class="kwrd">public</span> UnmanagedIRSerialPort(<span class="kwrd">string</span> portString) </pre>
<pre class="alt"><span class="lnum">   7:  </span> { </pre>
<pre><span class="lnum">   8:  </span> port = portString; </pre>
<pre class="alt"><span class="lnum">   9:  </span> } </pre>
<pre><span class="lnum">  10:  </span> </pre>
<pre class="alt"><span class="lnum">  11:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Open() </pre>
<pre><span class="lnum">  12:  </span> { </pre>
<pre class="alt"><span class="lnum">  13:  </span>  portHandle = CreateFile(<span class="str">&quot;COM1&quot;</span>, </pre>
<pre><span class="lnum">  14:   </span> EFileAccess.GenericRead | EFileAccess.GenericWrite, </pre>
<pre class="alt"><span class="lnum">  15:  </span>&nbsp; EFileShare.None, </pre>
<pre><span class="lnum">  16:  </span>  IntPtr.Zero, </pre>
<pre class="alt"><span class="lnum">  17:   </span> ECreationDisposition.OpenExisting, </pre>
<pre><span class="lnum">  18:   </span> EFileAttributes.Overlapped, IntPtr.Zero); </pre>
<pre class="alt"><span class="lnum">  19:   </span> GetCommState(portHandle, <span class="kwrd">ref</span> dcb); </pre>
<pre><span class="lnum">  20:   </span> dcb.RtsControl = RtsControl.Enable; </pre>
<pre class="alt"><span class="lnum">  21:   </span> dcb.DtrControl = DtrControl.Disable; </pre>
<pre><span class="lnum">  22:   </span> dcb.BaudRate = 115200; </pre>
<pre class="alt"><span class="lnum">  23:   </span> SetCommState(portHandle, <span class="kwrd">ref</span> dcb); </pre>
<pre><span class="lnum">  24:  </span> } </pre>
<pre class="alt"><span class="lnum">  25:  </span> </pre>
<pre><span class="lnum">  26:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> On() </pre>
<pre class="alt"><span class="lnum">  27:  </span> { </pre>
<pre><span class="lnum">  28:  </span> EscapeCommFunction(portHandle, SETDTR); </pre>
<pre class="alt"><span class="lnum">  29:  </span> <span class="rem">//dcb.DtrControl = DtrControl.Enable; </span></pre>
<pre><span class="lnum">  30:  </span> <span class="rem">//SetCommState(portHandle, ref dcb); </span></pre>
<pre class="alt"><span class="lnum">  31:  </span> } </pre>
<pre><span class="lnum">  32:  </span> </pre>
<pre class="alt"><span class="lnum">  33:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Off() </pre>
<pre><span class="lnum">  34:  </span> { </pre>
<pre class="alt"><span class="lnum">  35:  </span> EscapeCommFunction(portHandle, CLRDTR); </pre>
<pre><span class="lnum">  36:  </span> <span class="rem">//dcb.DtrControl = DtrControl.Disable; </span></pre>
<pre class="alt"><span class="lnum">  37:  </span> <span class="rem">//SetCommState(portHandle, ref dcb); </span></pre>
<pre><span class="lnum">  38:  </span> } </pre>
<pre class="alt"><span class="lnum">  39:  </span> </pre>
<pre><span class="lnum">  40:  </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Close() </pre>
<pre class="alt"><span class="lnum">  41:  </span> { </pre>
<pre><span class="lnum">  42:  </span> CloseHandle(portHandle); </pre>
<pre class="alt"><span class="lnum">  43:  </span> } </pre>
<pre><span class="lnum">  44:  </span> </pre>
<pre class="alt"><span class="lnum">  45:  </span> <span class="preproc">#region</span> Interop Serial Port Stuff </pre>
<pre><span class="lnum">  46:  </span> [DllImport(<span class="str">&quot;kernel32.dll&quot;</span>)] </pre>
<pre class="alt"><span class="lnum">  47:  </span> <span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">bool</span> GetCommState(IntPtr hFile, <span class="kwrd">ref</span> DCB lpDCB); </pre>
<pre><span class="lnum">  48:  </span> </pre>
<pre class="alt"><span class="lnum">  49:  </span> [DllImport(<span class="str">&quot;kernel32.dll&quot;</span>)] </pre>
<pre><span class="lnum">  50:  </span> <span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">bool</span> SetCommState(IntPtr hFile, [In] <span class="kwrd">ref</span> DCB lpDCB); </pre>
<pre class="alt"><span class="lnum">  51:  </span> </pre>
<pre><span class="lnum">  52:  </span> [DllImport(<span class="str">&quot;kernel32.dll&quot;</span>, SetLastError = <span class="kwrd">true</span>)] </pre>
<pre class="alt"><span class="lnum">  53:  </span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">bool</span> CloseHandle(IntPtr handle); </pre>
<pre><span class="lnum">  54:  </span> </pre>
<pre class="alt"><span class="lnum">  55:  </span> [DllImport(<span class="str">&quot;kernel32.dll&quot;</span>, SetLastError = <span class="kwrd">true</span>)] </pre>
<pre><span class="lnum">  56:  </span> <span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">bool</span> EscapeCommFunction(IntPtr hFile, <span class="kwrd">int</span> dwFunc); </pre>
<pre class="alt"><span class="lnum">  57:  </span><span class="rem">//Snipped so you don't go blind... </span></pre>
<pre><span class="lnum">  58:  </span><span class="preproc">#endregion</span> </pre>
<pre class="alt"><span class="lnum">  59:  </span>} </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Here's the NOT COMPLETE (Remember, it just does DTR) Unmanaged Serial Port class. Thanks
<a href="http://www.pinvoke.net/">PInvoke.NET</a>&nbsp;for the structures to kick start this)!:<br>
<a href="http://www.hanselman.com/blog/content/binary/UnmanagedIRSerialPort.txt">File Attachment: UnmanagedIRSerialPort.cs (10 KB)</a>
</p>
<p>As you can see I've got it abstracted away with a common interface so I can switch between managed serial and unmanaged serial quickly. I ran the same tests again, this time with MY serial port stuff:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0085.gif"><img height="338" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image008_thumb.gif" width="500" border="0"></a>
</p>
<p>Sweet, almost 10x faster and darn <b>near </b>where I need it to be. However, it's not consistent enough.&nbsp;I need numbers like 2400, 600, 1200. I'm having to boost the process and thread priority just to get here...
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>previousThreadPriority = System.Threading.Thread.CurrentThread.Priority; </pre>
<pre><span class="lnum">   2:  </span>System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest; </pre>
<pre class="alt"><span class="lnum">   3:  </span>System.Diagnostics.Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime; </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>...and undo it with... </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>System.Threading.Thread.CurrentThread.Priority = previousThreadPriority; </pre>
<pre><span class="lnum">   2:  </span>System.Diagnostics.Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Normal; </pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>...and that's just naughty and not getting the job done. </p>
<p>At this point, it's close, but I'm wondering if it's even possible to flash this thing fast enough. I'm at the limit of my understanding of serial ports (Is DTR affected by Baud Rate? Is 115200 the fastest? Would this be faster in C&#43;&#43; (probably not), or
 is there a faster way to PInvoke?) </p>
<h2><b>More Details of the SIRC Protocol</b> </h2>
<p>The Sony IR Protocol uses a header that consists of a pulse 2400µs long, followed by 12 ones or zeros (twelve bits) where a &quot;1&quot; is a pulse 1.2ms long followed by an off state for 600µs long and a &quot;0&quot; is a pulse 600µs long followed by an off state for 600µs
 long. The whole packet is finalized with an off state 600µs long. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image00215.gif"><img height="125" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0021_thumb.gif" width="450" border="0"></a>
</p>
<p>According to the SIRC spec, these are the &quot;1s and 0s&quot;&nbsp;we will be using to control the robot. They are the buttons used for the cursor on Sony remotes. This next code snippet is from the BASIC program that controls the robot, so this is what the
<em>receiver on the&nbsp;robot</em>&nbsp;needs to see to take action. </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>TestIRData:</pre>
<pre><span class="lnum">   2:  </span>High LED_Pin ;<span class="kwrd">Set</span> LED_Pin high    </pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">if</span> irdata = %0000100100000000 <span class="kwrd">then</span> forward        </pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">if</span> irdata = %1000100100000000 <span class="kwrd">then</span> backward</pre>
<pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">if</span> irdata = %0100100100000000 <span class="kwrd">then</span> twistright</pre>
<pre><span class="lnum">   6:  </span><span class="kwrd">if</span> irdata = %1100100100000000 <span class="kwrd">then</span> twistleft</pre>
<pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">if</span> irdata = %0010100100000000 <span class="kwrd">then</span> still</pre>
<pre><span class="lnum">   8:  </span>return</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The protocol indicates that it wants the Most Significant Bit on the RIGHT, which is the opposite of how it's done on Intel chips. Note that this doesn't refer to &quot;Endianness,&quot; which is byte-by-byte. We're talking about reversing or flipping&nbsp;the entire bit
 stream. </p>
<p>Here's the constants in C# that correspond (in reverse) to the values the BASIC file.&nbsp;These values are&nbsp;straight from&nbsp;the spec.&nbsp;
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> FORWARD = 144;</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> BACKWARD = 2192;</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> RIGHT = 1168;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> LEFT = 3216;</pre>
<pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> STILL = 656;</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>I could have stored them already reversed, but in the interest of making the code more reusable for other IR-related projects, I added a reverse function with help from Nicolas Allen and Wesner Moise that takes a long and the number of bits to reverse.
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">long</span> Reverse(<span class="kwrd">long</span> i, <span class="kwrd">int</span> bits)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>     i = ((i &gt;&gt; 1) &amp; 0x5555555555555555) | ((i &amp; 0x5555555555555555) &lt;&lt; 1);</pre>
<pre><span class="lnum">   4:  </span>     i = ((i &gt;&gt; 2) &amp; 0x3333333333333333) | ((i &amp; 0x3333333333333333) &lt;&lt; 2);</pre>
<pre class="alt"><span class="lnum">   5:  </span>     i = ((i &gt;&gt; 4) &amp; 0x0F0F0F0F0F0F0F0F) | ((i &amp; 0x0F0F0F0F0F0F0F0F) &lt;&lt; 4);</pre>
<pre><span class="lnum">   6:  </span>     i = ((i &gt;&gt; 8) &amp; 0x00FF00FF00FF00FF) | ((i &amp; 0x00FF00FF00FF00FF) &lt;&lt; 8);</pre>
<pre class="alt"><span class="lnum">   7:  </span>     i = ((i &gt;&gt; 16) &amp; 0x0000FFFF0000FFFF) | ((i &amp; 0x0000FFFF0000FFFF) &lt;&lt; 16);</pre>
<pre><span class="lnum">   8:  </span>     i = (i &gt;&gt; 32) | (i &lt;&lt; 32);</pre>
<pre class="alt"><span class="lnum">   9:  </span>     <span class="kwrd">return</span> i &gt;&gt; (64 - bits);</pre>
<pre><span class="lnum">  10:  </span>}</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This makes the SendData() method nice and clean and allows me to send codes straight from the SIRC spec:
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">unsafe</span> <span class="kwrd">void</span> SendData(<span class="kwrd">long</span> data, <span class="kwrd">int</span> bits)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">int</span> i;</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>    data = Reverse(data,bits);</pre>
<pre><span class="lnum">   6:  </span>    <span class="kwrd">for</span>(i=0;i&lt;bits;i&#43;&#43;)</pre>
<pre class="alt"><span class="lnum">   7:  </span>    {</pre>
<pre><span class="lnum">   8:  </span>        <span class="kwrd">if</span>((data &amp; 1) == 1)</pre>
<pre class="alt"><span class="lnum">   9:  </span>        {</pre>
<pre><span class="lnum">  10:  </span>            SendPulse(ONEPULSE);</pre>
<pre class="alt"><span class="lnum">  11:  </span>            SendSpace(ZEROPULSE);</pre>
<pre><span class="lnum">  12:  </span>        }</pre>
<pre class="alt"><span class="lnum">  13:  </span>        <span class="kwrd">else</span></pre>
<pre><span class="lnum">  14:  </span>        {</pre>
<pre class="alt"><span class="lnum">  15:  </span>            SendPulse(ZEROPULSE);</pre>
<pre><span class="lnum">  16:  </span>            SendSpace(ZEROPULSE);</pre>
<pre class="alt"><span class="lnum">  17:  </span>        }</pre>
<pre><span class="lnum">  18:  </span>        data=data&gt;&gt;1;</pre>
<pre class="alt"><span class="lnum">  19:  </span>    }</pre>
<pre><span class="lnum">  20:  </span>}</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This method takes each bit at a time and flashes the IR port. But, we've still got the problem of speed. It's just not happening fast enough. The basic design is there, but at this point I'm starting to suspect I need different hardware.
</p>
<h2><b>Infrared Serial Port via Custom Hardware</b> </h2>
<p>At this point, I went back to the <a href="http://iguanaworks.net/ir/">folks at Iguanaworks</a>&nbsp;and explained the problem. They agreed it was time to put the &quot;carrier&quot; onto the hardware. We'd change the original serial port board that turned the LED on and
 off using the Serial DTR signal so that now it would&nbsp;<em>oscillate </em>when DTR was set hot.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image0097.jpg"><img height="300" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/clip_image009_thumb2.jpg" width="400" border="0"></a></p>
<p>The graphic above shows the original serial port adapter on the right, the prototype in the middle with the &quot;daughter board&quot; attached. We tried a number of resistor values before we got it right. And the completed first-run prototype on the far left. There's
 ways to make it smaller, but this way gives the user more choices. The frequency can be swapped to emulate different remote controls by changing resistors yourself in the final design, or turning the carrier off completely.</p>
<p>My IR controlling code wouldn't change significantly, it would actually shrink, as it was silly for me to try and do the work that was better handled by hardware. Here's the updated SendPulse() method along with SendSpace().</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">unsafe</span> <span class="kwrd">void</span> SendPulse(<span class="kwrd">long</span> microSecs)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>    port.On();</pre>
<pre><span class="lnum">   4:  </span>    MicroWait(microSecs);</pre>
<pre class="alt"><span class="lnum">   5:  </span>}</pre>
<pre><span class="lnum">   6:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">public</span> <span class="kwrd">unsafe</span> <span class="kwrd">void</span> SendSpace(<span class="kwrd">long</span> length)</pre>
<pre><span class="lnum">   8:  </span>{</pre>
<pre class="alt"><span class="lnum">   9:  </span>    port.Off();</pre>
<pre><span class="lnum">  10:  </span>    MicroWait(length);</pre>
<pre class="alt"><span class="lnum">  11:  </span>}</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/infraredserial4.jpg"><img height="190" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1192168/infraredserial_thumb2.jpg" width="240" align="right" border="0"></a>
</p>
<p>It's worth noting also that the guys from Iguanaworks and the guys from Microbric worked very hard, collaborating between Colorado and Australia, along with me chiming in occasionally, to get this to work. To the right you can see an image of the IR pulse
 on an oscilloscope. You can see the header on the far right, of 2400 microseconds, followed by 0,0,0,0,1,0,0,1,0,0,0,0.
</p>
<h2><strong>Controlling the Robot from the Console</strong></h2>
<p>The next step is hooking it all up to a console app to try moving the robot around with the keyboard. At this point, the hard work is done and we can setup a simple key-checking loop that runs until you press Ctrl-C
</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">class</span> Program</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> FORWARD = 144;</pre>
<pre><span class="lnum">   4:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> BACKWARD = 2192;</pre>
<pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> RIGHT = 1168;</pre>
<pre><span class="lnum">   6:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> LEFT = 3216;</pre>
<pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> STILL = 656;</pre>
<pre><span class="lnum">   8:  </span>    <span class="kwrd">const</span> <span class="kwrd">int</span> REPEAT = 4;</pre>
<pre class="alt"><span class="lnum">   9:  </span>    </pre>
<pre><span class="lnum">  10:  </span>    <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)</pre>
<pre class="alt"><span class="lnum">  11:  </span>    {</pre>
<pre><span class="lnum">  12:  </span>        <span class="kwrd">using</span> (IR ir = <span class="kwrd">new</span> IR(<span class="str">&quot;COM1&quot;</span>))</pre>
<pre class="alt"><span class="lnum">  13:  </span>        {</pre>
<pre><span class="lnum">  14:  </span>            <span class="kwrd">while</span> (<span class="kwrd">true</span>)</pre>
<pre class="alt"><span class="lnum">  15:  </span>            {</pre>
<pre><span class="lnum">  16:  </span>                ConsoleKeyInfo key = Console.ReadKey(<span class="kwrd">true</span>);</pre>
<pre class="alt"><span class="lnum">  17:  </span>                <span class="kwrd">switch</span> (key.Key)</pre>
<pre><span class="lnum">  18:  </span>                {</pre>
<pre class="alt"><span class="lnum">  19:  </span>                    <span class="kwrd">case</span> ConsoleKey.UpArrow:</pre>
<pre><span class="lnum">  20:  </span>                        ir.Send(FORWARD, REPEAT);</pre>
<pre class="alt"><span class="lnum">  21:  </span>                        <span class="kwrd">break</span>;</pre>
<pre><span class="lnum">  22:  </span>                    <span class="kwrd">case</span> ConsoleKey.DownArrow:</pre>
<pre class="alt"><span class="lnum">  23:  </span>                        ir.Send(BACKWARD, REPEAT);</pre>
<pre><span class="lnum">  24:  </span>                        <span class="kwrd">break</span>;</pre>
<pre class="alt"><span class="lnum">  25:  </span>                    <span class="kwrd">case</span> ConsoleKey.RightArrow:</pre>
<pre><span class="lnum">  26:  </span>                        ir.Send(RIGHT, REPEAT);</pre>
<pre class="alt"><span class="lnum">  27:  </span>                        <span class="kwrd">break</span>;</pre>
<pre><span class="lnum">  28:  </span>                    <span class="kwrd">case</span> ConsoleKey.LeftArrow:</pre>
<pre class="alt"><span class="lnum">  29:  </span>                        ir.Send(LEFT, REPEAT);</pre>
<pre><span class="lnum">  30:  </span>                        <span class="kwrd">break</span>;</pre>
<pre class="alt"><span class="lnum">  31:  </span>                }</pre>
<pre><span class="lnum">  32:  </span>            }</pre>
<pre class="alt"><span class="lnum">  33:  </span>        }</pre>
<pre><span class="lnum">  34:  </span>    }</pre>
<pre class="alt"><span class="lnum">  35:  </span>}</pre>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In the next article, we'll attach the Viper and IR classes to PowerShell and script enable them like the LOGO Turtle of years past.
</p>
<p>The Microbric Viper can be ordered online in North America, check out <a href="http://www.microbric.com/">
www.microbric.com</a> for North American distributors. It's only <a href="http://www.saelig.com/miva/merchant.mvc?Screen=PROD&amp;Product_Code=RO001&amp;Category_Code=">
US$89 at Saelig</a>&nbsp;and <a href="http://www.robotshop.ca/home/suppliers/microbric-en/microbric-viper-robot-kit.html">
CAD$99 at RobotShop</a>. They have a number of educational robots that can be assembled by kids of all ages and skill levels. They're great for the classroom, and include projects like Sumo Robots, and a line-following bot, as well as a Spiderbot that climbs
 rope - all from the same kit. </p>
<p>You can order the <a href="http://iguanaworks.net/ir/">IR Transmitter/Receiver from IguanaWorks</a>. The
<a href="http://iguanaworks.net/ir/serial/">serial version</a> works on Windows or Linux, and there's a
<a href="http://iguanaworks.net/ir/usb/">Linux USB version</a>. It's not just a Transmitter, but also a learning receiver that works with WinLIRC&nbsp;and turns your computer into a learning remote control.
</p>
<h2><b>Conclusion</b> </h2>
<p>As with all my projects, there's things that could be&nbsp;extended, added,&nbsp;and improved on with this project.&nbsp;Here are&nbsp;some ideas to get you started.
</p>
<ul>
<li>Extend the IR program running&nbsp;inside the Viper to support other commands.&nbsp; </li><li>Integrate the Viper with the Microsoft Robotics Toolkit. </li><li>Use the IR class to control your home theater and television.&nbsp; </li><li>Write a paint program that controls the Viper and draws with a pen what you draw in paint!
</li></ul>
<p>Have fun and have no fear when faced with the words - Some Assembly Required! </p>
<hr align="center" width="100%" size="2">
<p>Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C&#43;&#43;, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture
 MVP. He is co-author of Professional ASP.NET 2.0&nbsp;with Bill Evjen, available on BookPool.com and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at
<a href="http://www.computerzen.com/">http://www.computerzen.com</a>.&nbsp;He thanks his wife and&nbsp;Zenzo for indulging him in these hobbies!</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/hardwarehacks/RSS&WT.dl=0&WT.entryid=Entry:RSSView:00bd796e3c8145daac789e7600d77bfb">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Controlling-a-Microbric-Viper-Robot-with-a-custom-IR-Serial-Port-using-NET</comments>
      <itunes:summary>
Summary: In this installment of &amp;quot;Some Assembly Required&amp;quot;, Scott Hanselman&amp;nbsp;teams up with the makers of the
Microbric&amp;nbsp;Viper Robot and the guys at 
Iguanaworks&amp;nbsp;to create a custom IR serial port board to control the Viper Robot using .NET!
 
Introduction 
The Microbric Viper is a robot construction kit based on a new solderless construction technique. The Viper uses a
Basic Atom microcontroller that you program, shockingly,&amp;nbsp;using BASIC. Modules like an
Infrared Receiver, motors and switches can be fairly easily controlled as you just screw them directly into the mainboard and address them by number. Once I got my hands on a Microbric, I started trying
 to talk to the robot using my laptop&#39;s Infrared Port. It turns out after a number of failed attempts that Windows doesn&#39;t expose standard laptop IR ports as Serial Ports or in any way other than via the
IRDA&amp;nbsp;protocol. IRDA was not only overkill for this kind of communication but also a hassle to program to. What I really needed was an IR transmitter that I could talk to using an interface that was clear and clean
 like the Serial Port&amp;nbsp;interface exposed by System.IO.Ports.  
I approached the guys at Iguanaworks&amp;nbsp;as they make an infrared transceiver that is addressable via a standard Serial Port. The Viper comes with a Sony Remote Control so I set off to figure out how to get the Iguanaworks
 IR transmitter to speak to the Viper using .NET.  
Programming the Microbric Viper Robot 
The IR receiver module is
 screwed into the Microbric Viper, in my case, into the addressable P14 port on the side of the main body. The Viper includes a main chip called the Basic Atom that is flashed using BASIC programs written in an included BASIC IDE. In my BASIC file a constant
 is used to address the IR &amp;quot;Data Pin,&amp;quot; in this case, P14.  
The Basic Atom includes a number of BASIC helper methods that the microprocessor uses to talk to the&amp;nbsp;external world. The &amp;quot;pulsin&amp;quot; method&amp;n</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Controlling-a-Microbric-Viper-Robot-with-a-custom-IR-Serial-Port-using-NET</link>
      <pubDate>Sat, 02 Dec 2006 04:10:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Controlling-a-Microbric-Viper-Robot-with-a-custom-IR-Serial-Port-using-NET</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1192168_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1192168_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Scott Hanselman</dc:creator>
      <itunes:author>Scott Hanselman</itunes:author>
      <slash:comments>6</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Controlling-a-Microbric-Viper-Robot-with-a-custom-IR-Serial-Port-using-NET/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Robotics</category>
      <category>hardwarehacks</category>
      <category>hardware miscellaneous</category>
    </item>    
</channel>
</rss>