<?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</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Harald-Rxeisen/Posts/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</title>
      <link>http://channel9.msdn.com/Niners/c4f.Harald-Rxeisen/Posts</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/Niners/c4f.Harald-Rxeisen/Posts</link>
    <language>en</language>
    <pubDate>Tue, 21 May 2013 19:24:51 GMT</pubDate>
    <lastBuildDate>Tue, 21 May 2013 19:24:51 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>1</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Using Optimus Mini Three 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">Even though the device is connected to an usb port the communication is done through a (virtual) serial port. The protocol specification is available in
<a href="http://www.artlebedev.com/everything/optimus-mini/developers/">the developer section on Art.Lebedev Studio's website</a>. There's also some c sample code available which proved to be very useful to build this class. The document lists the following
 commands to send data to the device:
<ul>
<li>Switch the device on and off </li><li>Send image data for a specific key </li><li>Show sent image for a specific key </li><li>Change the brightness </li></ul>
There're two additional commands available, to read and write the internal id of the device. We're not going to use them for this article. They could be used if you've multiple devices connected to differentiate them.
<br>
<br>
All the commands we're sending have a length of 197 bytes, the last byte being the checksum. The response to a command consists of two bytes: a 0 to tell us this is a command confirmation and as second byte the checksum. Ideally that checksum matches the one
 of the sent command - if not the data was somehow corrupted and we've to send it again.
<br>
<br>
And the device is not just waiting until we send it something, it will also send something to us: the keys which are currently pressed - of course, wouldn't qualify as keyboard otherwise. These messages are also 2 bytes long, first byte being a 1 and the second
 byte is the 1-based index of the pressed key. We can get them anytime and very often - as long as one or more keys are pressed they're repeatedly send. When commands are send at the same time we get a mix of key messages and command confirmations.
<br>
<br>
</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Harald Röxeisen </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">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input">Optimus mini three software</span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">Optimus mini three keyboard</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=324244#324244">Download</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<h4>Getting started: the serial port</h4>
<p>First we need to know the serial port to connect to. Usb devices are stored in the windows registry in
<em>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB</em>, and the device id we're looking for is
<em>Vid_067b&amp;Pid_2303</em>. Below that key can be multiple nodes, depending on how often and which usb ports you've plugged in the device.
</p>
<p>Below each node is a sub node called <em>Device Parameters</em> and there we find what we're looking for: the key
<em>PortName</em> with the serial port name as value. We're additionally verifying that the serial port actually exists. It can happen that the
<em>PortName</em> key is set, but the port doesn't exist because it's an old/inactive registry entry from a previous connection.
</p>
<p><strong>C#</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetPort()</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">string</span> result = <span class="kwrd">null</span>;</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="rem">// Get all active ports</span></pre>
<pre><span class="lnum">   6:  </span>  List&lt;<span class="kwrd">string</span>&gt; ports = <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;();</pre>
<pre class="alt"><span class="lnum">   7:  </span>  ports.AddRange(SerialPort.GetPortNames());</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">if</span> (ports.Count == 0) { <span class="kwrd">return</span> <span class="kwrd">null</span>; }</pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span>  <span class="rem">// Get root</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">string</span> rootName = <span class="str">&quot;SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_067b&amp;Pid_2303&quot;</span>;</pre>
<pre><span class="lnum">  12:  </span>  RegistryKey root = Registry.LocalMachine.OpenSubKey(rootName);</pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">if</span> (root == <span class="kwrd">null</span>) { <span class="kwrd">return</span> <span class="kwrd">null</span>; }</pre>
<pre><span class="lnum">  14:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="rem">// Get all keys below root - there can be several of them if the</span></pre>
<pre><span class="lnum">  16:  </span>  <span class="rem">// device was connected to different usb ports</span></pre>
<pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">string</span>[] devices = root.GetSubKeyNames();</pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">if</span> (devices == <span class="kwrd">null</span>) { <span class="kwrd">return</span> <span class="kwrd">null</span>; }</pre>
<pre class="alt"><span class="lnum">  19:  </span>&nbsp;</pre>
<pre><span class="lnum">  20:  </span>  <span class="rem">// Loop through all devices and get first active</span></pre>
<pre class="alt"><span class="lnum">  21:  </span>  <span class="kwrd">foreach</span> (<span class="kwrd">string</span> deviceKey <span class="kwrd">in</span> devices)</pre>
<pre><span class="lnum">  22:  </span>  {</pre>
<pre class="alt"><span class="lnum">  23:  </span>    RegistryKey device = root.OpenSubKey(deviceKey &#43; <span class="str">&quot;\\Device Parameters&quot;</span>);</pre>
<pre><span class="lnum">  24:  </span>    <span class="kwrd">if</span> (device == <span class="kwrd">null</span>) { <span class="kwrd">continue</span>; }</pre>
<pre class="alt"><span class="lnum">  25:  </span>&nbsp;</pre>
<pre><span class="lnum">  26:  </span>    <span class="kwrd">object</span> portValue = device.GetValue(<span class="str">&quot;PortName&quot;</span>);</pre>
<pre class="alt"><span class="lnum">  27:  </span>    <span class="kwrd">if</span> (portValue == <span class="kwrd">null</span>) { <span class="kwrd">continue</span>; }</pre>
<pre><span class="lnum">  28:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  29:  </span>    <span class="rem">// Check if that port is active</span></pre>
<pre><span class="lnum">  30:  </span>    <span class="kwrd">string</span> port = (<span class="kwrd">string</span>)portValue;</pre>
<pre class="alt"><span class="lnum">  31:  </span>    <span class="kwrd">if</span> (ports.Contains(port))</pre>
<pre><span class="lnum">  32:  </span>    {</pre>
<pre class="alt"><span class="lnum">  33:  </span>      result = port;</pre>
<pre><span class="lnum">  34:  </span>      <span class="kwrd">break</span>;</pre>
<pre class="alt"><span class="lnum">  35:  </span>    }</pre>
<pre><span class="lnum">  36:  </span>  }</pre>
<pre class="alt"><span class="lnum">  37:  </span>  <span class="rem">// Result</span></pre>
<pre><span class="lnum">  38:  </span>  <span class="kwrd">return</span> result;</pre>
<pre class="alt"><span class="lnum">  39:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> GetPort() <span class="kwrd">As</span> <span class="kwrd">String</span></pre>
<pre><span class="lnum">   2:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">Dim</span> result <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Nothing</span></pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="rem">'Get all active ports</span></pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">Dim</span> ports <span class="kwrd">As</span> List(Of <span class="kwrd">String</span>) = <span class="kwrd">New</span> List(Of <span class="kwrd">String</span>)</pre>
<pre class="alt"><span class="lnum">   7:  </span>  ports.AddRange(SerialPort.GetPortNames())</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">If</span> (ports.Count = 0) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">Return</span> <span class="kwrd">Nothing</span></pre>
<pre><span class="lnum">  10:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>&nbsp;</pre>
<pre><span class="lnum">  12:  </span>  <span class="rem">'Get root</span></pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">Dim</span> rootName <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="str">&quot;SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_067b&amp;Pid_2303&quot;</span></pre>
<pre><span class="lnum">  14:  </span>  <span class="kwrd">Dim</span> root <span class="kwrd">As</span> RegistryKey = Registry.LocalMachine.OpenSubKey(rootName)</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">If</span> (root <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  16:  </span>    <span class="kwrd">Return</span> <span class="kwrd">Nothing</span></pre>
<pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  18:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  19:  </span>  <span class="rem">'Get all keys below root - there can be several of them if the</span></pre>
<pre><span class="lnum">  20:  </span>  <span class="rem">'device was connected to different usb ports</span></pre>
<pre class="alt"><span class="lnum">  21:  </span>  <span class="kwrd">Dim</span> devices() <span class="kwrd">As</span> <span class="kwrd">String</span> = root.GetSubKeyNames()</pre>
<pre><span class="lnum">  22:  </span>  <span class="kwrd">If</span> (devices <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  23:  </span>    <span class="kwrd">Return</span> <span class="kwrd">Nothing</span></pre>
<pre><span class="lnum">  24:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>&nbsp;</pre>
<pre><span class="lnum">  26:  </span>  <span class="rem">'Loop through all devices and get first active</span></pre>
<pre class="alt"><span class="lnum">  27:  </span>  <span class="kwrd">Dim</span> deviceKey <span class="kwrd">As</span> <span class="kwrd">String</span></pre>
<pre><span class="lnum">  28:  </span>  <span class="kwrd">For</span> <span class="kwrd">Each</span> deviceKey <span class="kwrd">In</span> devices</pre>
<pre class="alt"><span class="lnum">  29:  </span>    <span class="kwrd">Dim</span> device <span class="kwrd">As</span> RegistryKey = root.OpenSubKey(deviceKey &#43; <span class="str">&quot;\\Device Parameters&quot;</span>)</pre>
<pre><span class="lnum">  30:  </span>    <span class="kwrd">If</span> (device <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  31:  </span>      Continue <span class="kwrd">For</span></pre>
<pre><span class="lnum">  32:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  33:  </span>&nbsp;</pre>
<pre><span class="lnum">  34:  </span>    <span class="kwrd">Dim</span> portValue <span class="kwrd">As</span> <span class="kwrd">Object</span> = device.GetValue(<span class="str">&quot;PortName&quot;</span>)</pre>
<pre class="alt"><span class="lnum">  35:  </span>    <span class="kwrd">If</span> (portValue <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  36:  </span>      Continue <span class="kwrd">For</span></pre>
<pre class="alt"><span class="lnum">  37:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  38:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  39:  </span>    <span class="rem">'Check if that port is active</span></pre>
<pre><span class="lnum">  40:  </span>    <span class="kwrd">Dim</span> port <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">CType</span>(portValue, <span class="kwrd">String</span>)</pre>
<pre class="alt"><span class="lnum">  41:  </span>    <span class="kwrd">If</span> (ports.Contains(port)) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  42:  </span>      result = port</pre>
<pre class="alt"><span class="lnum">  43:  </span>      <span class="kwrd">Exit</span> <span class="kwrd">For</span></pre>
<pre><span class="lnum">  44:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  45:  </span>  <span class="kwrd">Next</span></pre>
<pre><span class="lnum">  46:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  47:  </span>  <span class="rem">'Result</span></pre>
<pre><span class="lnum">  48:  </span>  <span class="kwrd">Return</span> result</pre>
<pre class="alt"><span class="lnum">  49:  </span>&nbsp;</pre>
<pre><span class="lnum">  50:  </span><span class="kwrd">End</span> Function</pre>
</div>
<h4>Connecting to the device</h4>
<p>Now that we know the port name we can open it. After that we add an handler for the
<em>DataReceived</em> event and tell the background thread to start working. </p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">bool</span> _Connected;</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">private</span> SerialPort _Port;</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">private</span> Thread _ProcessCommandsThread;</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">public</span> <span class="kwrd">bool</span> Init()</pre>
<pre><span class="lnum">   6:  </span>{</pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="rem">// If already connected exit</span></pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">if</span> (_Connected) { <span class="kwrd">return</span> <span class="kwrd">true</span>; }</pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span>  <span class="rem">// Get port name where the device is connected</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">string</span> port = GetPort();</pre>
<pre><span class="lnum">  12:  </span>  <span class="kwrd">if</span> (<span class="kwrd">string</span>.IsNullOrEmpty(port)) { <span class="kwrd">return</span> <span class="kwrd">false</span>; }</pre>
<pre class="alt"><span class="lnum">  13:  </span>&nbsp;</pre>
<pre><span class="lnum">  14:  </span>  <span class="rem">// Open port</span></pre>
<pre class="alt"><span class="lnum">  15:  </span>  _Port = <span class="kwrd">new</span> SerialPort(port);</pre>
<pre><span class="lnum">  16:  </span>  _Port.BaudRate = 1000000;</pre>
<pre class="alt"><span class="lnum">  17:  </span>  _Port.DataBits = 8;</pre>
<pre><span class="lnum">  18:  </span>  _Port.Open();</pre>
<pre class="alt"><span class="lnum">  19:  </span>  _Connected = <span class="kwrd">true</span>;</pre>
<pre><span class="lnum">  20:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  21:  </span>  <span class="rem">// Add event handler for DataReceived</span></pre>
<pre><span class="lnum">  22:  </span>  _Port.DataReceived &#43;= <span class="kwrd">new</span> SerialDataReceivedEventHandler(PortDataReceived);</pre>
<pre class="alt"><span class="lnum">  23:  </span>&nbsp;</pre>
<pre><span class="lnum">  24:  </span>  <span class="rem">// Start command thread</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>  _ProcessCommandsThread = <span class="kwrd">new</span> Thread(ProcessCommands);</pre>
<pre><span class="lnum">  26:  </span>  _ProcessCommandsThread.Start();</pre>
<pre class="alt"><span class="lnum">  27:  </span>&nbsp;</pre>
<pre><span class="lnum">  28:  </span>  <span class="rem">// Successfully connected</span></pre>
<pre class="alt"><span class="lnum">  29:  </span>  <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre>
<pre><span class="lnum">  30:  </span>}</pre>
<pre class="alt"><span class="lnum">  31:  </span>&nbsp;</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> _Connected <span class="kwrd">As</span> <span class="kwrd">Boolean</span></pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">Private</span> _Port <span class="kwrd">As</span> SerialPort</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">Private</span> _ProcessCommandsThread <span class="kwrd">As</span> Thread</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">Public</span> <span class="kwrd">Function</span> Init() <span class="kwrd">As</span> <span class="kwrd">Boolean</span></pre>
<pre><span class="lnum">   6:  </span>  <span class="rem">'If already connected exit</span></pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">If</span> (_Connected) <span class="kwrd">Then</span> <span class="kwrd">Return</span> <span class="kwrd">True</span></pre>
<pre><span class="lnum">   8:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   9:  </span>  <span class="rem">' Get port name where the device is connected</span></pre>
<pre><span class="lnum">  10:  </span>  <span class="kwrd">Dim</span> port <span class="kwrd">As</span> <span class="kwrd">String</span> = GetPort()</pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">If</span> (<span class="kwrd">String</span>.IsNullOrEmpty(port)) <span class="kwrd">Then</span> <span class="kwrd">Return</span> <span class="kwrd">False</span></pre>
<pre><span class="lnum">  12:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="rem">'Open port</span></pre>
<pre><span class="lnum">  14:  </span>  _Port = <span class="kwrd">New</span> SerialPort(port)</pre>
<pre class="alt"><span class="lnum">  15:  </span>  _Port.BaudRate = 1000000</pre>
<pre><span class="lnum">  16:  </span>  _Port.DataBits = 8</pre>
<pre class="alt"><span class="lnum">  17:  </span>  _Port.Open()</pre>
<pre><span class="lnum">  18:  </span>  _Connected = <span class="kwrd">True</span></pre>
<pre class="alt"><span class="lnum">  19:  </span>&nbsp;</pre>
<pre><span class="lnum">  20:  </span>  <span class="rem">'Add event handler for DataReceived</span></pre>
<pre class="alt"><span class="lnum">  21:  </span>  <span class="kwrd">AddHandler</span> _Port.DataReceived, <span class="kwrd">AddressOf</span> PortDataReceived</pre>
<pre><span class="lnum">  22:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  23:  </span>  <span class="rem">'Start command thread</span></pre>
<pre><span class="lnum">  24:  </span>  _ProcessCommandsThread = <span class="kwrd">New</span> Thread(<span class="kwrd">AddressOf</span> ProcessCommands)</pre>
<pre class="alt"><span class="lnum">  25:  </span>  _ProcessCommandsThread.Start()</pre>
<pre><span class="lnum">  26:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  27:  </span>  <span class="rem">'Successfully connected</span></pre>
<pre><span class="lnum">  28:  </span>  <span class="kwrd">Return</span> <span class="kwrd">True</span></pre>
<pre class="alt"><span class="lnum">  29:  </span><span class="kwrd">End</span> <span class="kwrd">Function</span></pre>
</div>
<p></p>
<h4>Handle incoming data</h4>
<p>This handler added in <em>Init</em> will be called asynchronously as soon as there's data in the input buffer. We'll only get byte pairs from the device which makes parsing very easy - a pair is either a command confirmation (0 followed by checksum) or a
 key message (1 followed by the 1-based key index). A wait handle is used to signal our background thread that a command confirmation was received. If we received a key message we'll call our
<em>RaiseKeyDown</em> method. </p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">byte</span> _LastCommandChecksum;</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">private</span> EventWaitHandle _CommandWaitHandle;</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> PortDataReceived(<span class="kwrd">object</span> sender, System.IO.Ports.SerialDataReceivedEventArgs e)</pre>
<pre class="alt"><span class="lnum">   5:  </span>{</pre>
<pre><span class="lnum">   6:  </span>  <span class="rem">// If we've not at least 2 bytes no need to read</span></pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">int</span> length = _Port.BytesToRead;</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">if</span> (length &lt; 2) { <span class="kwrd">return</span>; }</pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span>  <span class="rem">// We need byte pairs, single byte at the end is not read</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">int</span> pairs = length / 2;</pre>
<pre><span class="lnum">  12:  </span>  <span class="kwrd">byte</span>[] data = <span class="kwrd">new</span> <span class="kwrd">byte</span>[pairs * 2];</pre>
<pre class="alt"><span class="lnum">  13:  </span>  _Port.Read(data, 0, pairs * 2);</pre>
<pre><span class="lnum">  14:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="rem">// Parse data</span></pre>
<pre><span class="lnum">  16:  </span>  <span class="kwrd">bool</span> commandReceived = <span class="kwrd">false</span>;</pre>
<pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">bool</span>[] keyReceived = <span class="kwrd">new</span> <span class="kwrd">bool</span>[3];</pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; pairs; i&#43;&#43;)</pre>
<pre class="alt"><span class="lnum">  19:  </span>  {</pre>
<pre><span class="lnum">  20:  </span>    <span class="kwrd">byte</span> dataType = data[i * 2];</pre>
<pre class="alt"><span class="lnum">  21:  </span>    <span class="kwrd">byte</span> dataValue = data[i * 2 &#43; 1];</pre>
<pre><span class="lnum">  22:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  23:  </span>    <span class="kwrd">if</span> (dataType == 0)</pre>
<pre><span class="lnum">  24:  </span>    {</pre>
<pre class="alt"><span class="lnum">  25:  </span>      <span class="rem">// Command confirmation</span></pre>
<pre><span class="lnum">  26:  </span>      _LastCommandChecksum = dataValue;</pre>
<pre class="alt"><span class="lnum">  27:  </span>      commandReceived = <span class="kwrd">true</span>;</pre>
<pre><span class="lnum">  28:  </span>    }</pre>
<pre class="alt"><span class="lnum">  29:  </span>    <span class="kwrd">else</span></pre>
<pre><span class="lnum">  30:  </span>    {</pre>
<pre class="alt"><span class="lnum">  31:  </span>      <span class="rem">// Key message</span></pre>
<pre><span class="lnum">  32:  </span>      <span class="kwrd">if</span> (dataValue &gt;= 1 &amp;&amp; dataValue &lt;= 3)</pre>
<pre class="alt"><span class="lnum">  33:  </span>      {</pre>
<pre><span class="lnum">  34:  </span>        keyReceived[dataValue - 1] = <span class="kwrd">true</span>;</pre>
<pre class="alt"><span class="lnum">  35:  </span>      }</pre>
<pre><span class="lnum">  36:  </span>    }</pre>
<pre class="alt"><span class="lnum">  37:  </span>  }</pre>
<pre><span class="lnum">  38:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  39:  </span>  <span class="rem">// If a command confirmation was received notify wait handle</span></pre>
<pre><span class="lnum">  40:  </span>  <span class="kwrd">if</span> (commandReceived &amp;&amp; _CommandWaitHandle != <span class="kwrd">null</span>) { _CommandWaitHandle.Set(); }</pre>
<pre class="alt"><span class="lnum">  41:  </span>&nbsp;</pre>
<pre><span class="lnum">  42:  </span>  <span class="rem">// If key messages were received raise event</span></pre>
<pre class="alt"><span class="lnum">  43:  </span>  <span class="kwrd">for</span> (<span class="kwrd">byte</span> i = 0; i &lt;= 2; i&#43;&#43;)</pre>
<pre><span class="lnum">  44:  </span>  {</pre>
<pre class="alt"><span class="lnum">  45:  </span>    <span class="kwrd">if</span> (keyReceived[i]) { RaiseKeyDown(i); }</pre>
<pre><span class="lnum">  46:  </span>  }</pre>
<pre class="alt"><span class="lnum">  47:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> _LastCommandChecksum <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">Private</span> _CommandWaitHandle <span class="kwrd">As</span> EventWaitHandle</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">Private</span> <span class="kwrd">Sub</span> PortDataReceived(<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> SerialDataReceivedEventArgs)</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="rem">'If we've not at least 2 bytes no need to read</span></pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">Dim</span> length <span class="kwrd">As</span> <span class="kwrd">Integer</span> = _Port.BytesToRead</pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">If</span> (length &lt; 2) <span class="kwrd">Then</span> <span class="kwrd">Exit</span> <span class="kwrd">Sub</span></pre>
<pre><span class="lnum">   8:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   9:  </span>  <span class="rem">'We need byte pairs, single byte at the end is not read</span></pre>
<pre><span class="lnum">  10:  </span>  <span class="kwrd">Dim</span> pairs <span class="kwrd">As</span> <span class="kwrd">Integer</span> = length \ 2</pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">Dim</span> data() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(pairs * 2) {}</pre>
<pre><span class="lnum">  12:  </span>  _Port.Read(data, 0, pairs * 2)</pre>
<pre class="alt"><span class="lnum">  13:  </span>&nbsp;</pre>
<pre><span class="lnum">  14:  </span>  <span class="rem">'Parse data</span></pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">Dim</span> commandReceived <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">False</span></pre>
<pre><span class="lnum">  16:  </span>  <span class="kwrd">Dim</span> keyReceived() <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">New</span> <span class="kwrd">Boolean</span>(3) {}</pre>
<pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span></pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">For</span> i = 0 <span class="kwrd">To</span> pairs - 1 <span class="kwrd">Step</span> i &#43; 1</pre>
<pre class="alt"><span class="lnum">  19:  </span>    <span class="kwrd">Dim</span> dataType <span class="kwrd">As</span> <span class="kwrd">Byte</span> = data(i * 2)</pre>
<pre><span class="lnum">  20:  </span>    <span class="kwrd">Dim</span> dataValue <span class="kwrd">As</span> <span class="kwrd">Byte</span> = data(i * 2 &#43; 1)</pre>
<pre class="alt"><span class="lnum">  21:  </span>&nbsp;</pre>
<pre><span class="lnum">  22:  </span>    <span class="kwrd">If</span> (dataType = 0) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  23:  </span>      <span class="rem">'Command confirmation</span></pre>
<pre><span class="lnum">  24:  </span>      _LastCommandChecksum = dataValue</pre>
<pre class="alt"><span class="lnum">  25:  </span>      commandReceived = <span class="kwrd">True</span></pre>
<pre><span class="lnum">  26:  </span>    <span class="kwrd">Else</span></pre>
<pre class="alt"><span class="lnum">  27:  </span>      <span class="rem">'Key message</span></pre>
<pre><span class="lnum">  28:  </span>      <span class="kwrd">If</span> (dataValue &gt;= 1 <span class="kwrd">And</span> dataValue &lt;= 3) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  29:  </span>        keyReceived(dataValue - 1) = <span class="kwrd">True</span></pre>
<pre><span class="lnum">  30:  </span>      <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  31:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  32:  </span>  <span class="kwrd">Next</span></pre>
<pre class="alt"><span class="lnum">  33:  </span>&nbsp;</pre>
<pre><span class="lnum">  34:  </span>  <span class="rem">'If a command confirmation was received notify wait handle</span></pre>
<pre class="alt"><span class="lnum">  35:  </span>  <span class="kwrd">If</span> (commandReceived <span class="kwrd">And</span> <span class="kwrd">Not</span> _CommandWaitHandle <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  36:  </span>    _CommandWaitHandle.<span class="kwrd">Set</span>()</pre>
<pre class="alt"><span class="lnum">  37:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  38:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  39:  </span>  <span class="rem">'If key messages were received raise event</span></pre>
<pre><span class="lnum">  40:  </span>  <span class="kwrd">Dim</span> j <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre class="alt"><span class="lnum">  41:  </span>  <span class="kwrd">For</span> j = 0 <span class="kwrd">To</span> 2</pre>
<pre><span class="lnum">  42:  </span>    <span class="kwrd">If</span> (keyReceived(j)) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  43:  </span>      RaiseKeyDown(j)</pre>
<pre><span class="lnum">  44:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  45:  </span>  <span class="kwrd">Next</span></pre>
<pre><span class="lnum">  46:  </span><span class="kwrd">End</span> Sub</pre>
</div>
<h4>Key down event</h4>
<p>This method is called from the <em>DataReceived</em> handler and raises <em>OnKeyDown</em> events when we received key messages. Now we know that we can get them at a very fast rate and we shouldn't raise an event for every single message. We'll restrict
 it to only raise the event once if the key was not pressed in the last 100 ms. I came up with the 100ms after some testing - sometimes there're just a few ms between the key messages, but from time to time the gap is up to 70.
</p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">int</span>[] _LastKeyMessageOn = <span class="kwrd">new</span> <span class="kwrd">int</span>[3];</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">public</span> <span class="kwrd">delegate</span> <span class="kwrd">void</span> KeyDownEventHandler(<span class="kwrd">byte</span> keyIndex);</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">public</span> <span class="kwrd">event</span> KeyDownEventHandler OnKeyDown;</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> RaiseKeyDown(<span class="kwrd">byte</span> keyIndex)</pre>
<pre><span class="lnum">   6:  </span>{</pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">int</span> current = Environment.TickCount;</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">if</span> (current - _LastKeyMessageOn[keyIndex] &gt;= 100)</pre>
<pre class="alt"><span class="lnum">   9:  </span>  {</pre>
<pre><span class="lnum">  10:  </span>    <span class="rem">// Time to raise event</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">if</span> (OnKeyDown != <span class="kwrd">null</span>) { OnKeyDown(keyIndex); }</pre>
<pre><span class="lnum">  12:  </span>  }</pre>
<pre class="alt"><span class="lnum">  13:  </span>  _LastKeyMessageOn[keyIndex] = current;</pre>
<pre><span class="lnum">  14:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> _LastKeyMessageOn() <span class="kwrd">As</span> <span class="kwrd">Integer</span> = <span class="kwrd">New</span> <span class="kwrd">Integer</span>(3) {}</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">Public</span> <span class="kwrd">Event</span> OnKeyDown(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">Private</span> <span class="kwrd">Sub</span> RaiseKeyDown(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">Dim</span> current <span class="kwrd">As</span> <span class="kwrd">Integer</span> = Environment.TickCount</pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">If</span> (current - _LastKeyMessageOn(keyIndex) &gt;= 100) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">   7:  </span>    <span class="rem">'Time to raise event</span></pre>
<pre><span class="lnum">   8:  </span>    <span class="kwrd">RaiseEvent</span> OnKeyDown(keyIndex)</pre>
<pre class="alt"><span class="lnum">   9:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  10:  </span>  _LastKeyMessageOn(keyIndex) = current</pre>
<pre class="alt"><span class="lnum">  11:  </span><span class="kwrd">End</span> Sub</pre>
</div>
<h4>Sending commands</h4>
<p>This method takes a byte array as parameter and writes it to the output buffer of the serial port. Once sent it will wait up to a second at the handle we defined above for a command confirmation. If the confirmation arrives within time it'll compare the
 checksum. If they don't match or if there was a time out the command is send again, up to 3 times.
</p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">const</span> <span class="kwrd">int</span> COMMAND_LENGTH = 197;</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">private</span> <span class="kwrd">const</span> <span class="kwrd">int</span> COMMAND_LAST = 196;</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">private</span> <span class="kwrd">bool</span> SendCommand(<span class="kwrd">byte</span>[] command)</pre>
<pre class="alt"><span class="lnum">   5:  </span>{</pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">bool</span> success = <span class="kwrd">false</span>;</pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">int</span> triesLeft = 3;</pre>
<pre><span class="lnum">   8:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   9:  </span>  <span class="kwrd">while</span> (!success &amp;&amp; triesLeft &gt; 0)</pre>
<pre><span class="lnum">  10:  </span>  {</pre>
<pre class="alt"><span class="lnum">  11:  </span>    _Port.Write(command, 0, COMMAND_LENGTH);</pre>
<pre><span class="lnum">  12:  </span>    _CommandWaitHandle = <span class="kwrd">new</span> System.Threading.AutoResetEvent(<span class="kwrd">false</span>);</pre>
<pre class="alt"><span class="lnum">  13:  </span>    <span class="kwrd">if</span> (_CommandWaitHandle.WaitOne(1000, <span class="kwrd">false</span>))</pre>
<pre><span class="lnum">  14:  </span>    {</pre>
<pre class="alt"><span class="lnum">  15:  </span>      _CommandWaitHandle = <span class="kwrd">null</span>;</pre>
<pre><span class="lnum">  16:  </span>      <span class="kwrd">if</span> (_LastCommandChecksum == command[COMMAND_LAST])</pre>
<pre class="alt"><span class="lnum">  17:  </span>      {</pre>
<pre><span class="lnum">  18:  </span>        <span class="rem">// Success</span></pre>
<pre class="alt"><span class="lnum">  19:  </span>        success = <span class="kwrd">true</span>;</pre>
<pre><span class="lnum">  20:  </span>        <span class="kwrd">break</span>;</pre>
<pre class="alt"><span class="lnum">  21:  </span>      }</pre>
<pre><span class="lnum">  22:  </span>      <span class="kwrd">else</span></pre>
<pre class="alt"><span class="lnum">  23:  </span>      {</pre>
<pre><span class="lnum">  24:  </span>        <span class="rem">// Failed</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>        triesLeft -= 1;</pre>
<pre><span class="lnum">  26:  </span>      }</pre>
<pre class="alt"><span class="lnum">  27:  </span>    }</pre>
<pre><span class="lnum">  28:  </span>    <span class="kwrd">else</span></pre>
<pre class="alt"><span class="lnum">  29:  </span>    {</pre>
<pre><span class="lnum">  30:  </span>      <span class="rem">// Failed</span></pre>
<pre class="alt"><span class="lnum">  31:  </span>      triesLeft -= 1;</pre>
<pre><span class="lnum">  32:  </span>    }</pre>
<pre class="alt"><span class="lnum">  33:  </span>  }</pre>
<pre><span class="lnum">  34:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  35:  </span>  <span class="kwrd">return</span> success;</pre>
<pre><span class="lnum">  36:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> <span class="kwrd">Const</span> COMMAND_LENGTH <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 197</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">Private</span> <span class="kwrd">Const</span> COMMAND_LAST <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 196</pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">Private</span> <span class="kwrd">Function</span> SendCommand(<span class="kwrd">ByVal</span> command <span class="kwrd">As</span> <span class="kwrd">Byte</span>()) <span class="kwrd">As</span> <span class="kwrd">Boolean</span></pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">Dim</span> success <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">False</span></pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">Dim</span> triesLeft <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 3</pre>
<pre class="alt"><span class="lnum">   7:  </span>&nbsp;</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">While</span> <span class="kwrd">Not</span> success <span class="kwrd">And</span> triesLeft &gt; 0</pre>
<pre class="alt"><span class="lnum">   9:  </span>    _Port.Write(command, 0, COMMAND_LENGTH)</pre>
<pre><span class="lnum">  10:  </span>    _CommandWaitHandle = <span class="kwrd">New</span> System.Threading.AutoResetEvent(<span class="kwrd">False</span>)</pre>
<pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">If</span> (_CommandWaitHandle.WaitOne(1000, <span class="kwrd">False</span>)) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  12:  </span>      _CommandWaitHandle = <span class="kwrd">Nothing</span></pre>
<pre class="alt"><span class="lnum">  13:  </span>      <span class="kwrd">If</span> (_LastCommandChecksum = command(COMMAND_LAST)) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  14:  </span>        <span class="rem">'Success</span></pre>
<pre class="alt"><span class="lnum">  15:  </span>        success = <span class="kwrd">True</span></pre>
<pre><span class="lnum">  16:  </span>        <span class="kwrd">Exit</span> <span class="kwrd">While</span></pre>
<pre class="alt"><span class="lnum">  17:  </span>      <span class="kwrd">Else</span></pre>
<pre><span class="lnum">  18:  </span>        <span class="rem">'Failed</span></pre>
<pre class="alt"><span class="lnum">  19:  </span>        triesLeft -= 1</pre>
<pre><span class="lnum">  20:  </span>      <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  21:  </span>    <span class="kwrd">Else</span></pre>
<pre><span class="lnum">  22:  </span>      <span class="rem">'Failed</span></pre>
<pre class="alt"><span class="lnum">  23:  </span>      triesLeft -= 1</pre>
<pre><span class="lnum">  24:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>  <span class="kwrd">End</span> <span class="kwrd">While</span></pre>
<pre><span class="lnum">  26:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  27:  </span>  <span class="kwrd">Return</span> success</pre>
<pre><span class="lnum">  28:  </span><span class="kwrd">End</span> Function</pre>
</div>
<h4>The commands</h4>
<p>All commands we want to execute are added to a queue. That queue is a FIFO type - first in, first out. It's filled by the methods described below and emptied by the background thread. Because two different threads can modify the queue at the same time we
 need to synchronize it. The easiest way to do that is by using the <em>lock</em> statement to just let one thread in at a time.
</p>
<p>Let's start with the simple commands. For better readability the possible brightness values of low, normal and high (20, 40 and 60) are added as enumeration. The
<em>keyIndex</em> parameter is 0-based - 0 is the key on the side with the usb cable.
</p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> Queue&lt;<span class="kwrd">byte</span>[]&gt; _CommandQueue = <span class="kwrd">new</span> Queue&lt;<span class="kwrd">byte</span>[]&gt;();</pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">public</span> <span class="kwrd">const</span> <span class="kwrd">int</span> SCREEN_SIZE = 96;</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">public</span> <span class="kwrd">enum</span> Brightness</pre>
<pre><span class="lnum">   4:  </span>{</pre>
<pre class="alt"><span class="lnum">   5:  </span>  Low = 20,</pre>
<pre><span class="lnum">   6:  </span>  Normal = 40,</pre>
<pre class="alt"><span class="lnum">   7:  </span>  High = 60</pre>
<pre><span class="lnum">   8:  </span>}</pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> SwitchOn()</pre>
<pre class="alt"><span class="lnum">  11:  </span>{</pre>
<pre><span class="lnum">  12:  </span>  <span class="kwrd">byte</span>[] command = <span class="kwrd">new</span> <span class="kwrd">byte</span>[COMMAND_LENGTH];</pre>
<pre class="alt"><span class="lnum">  13:  </span>  command[0] = 2;</pre>
<pre><span class="lnum">  14:  </span>  command[COMMAND_LAST] = 2;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre><span class="lnum">  16:  </span>  {</pre>
<pre class="alt"><span class="lnum">  17:  </span>    _CommandQueue.Enqueue(command);</pre>
<pre><span class="lnum">  18:  </span>  }</pre>
<pre class="alt"><span class="lnum">  19:  </span>}</pre>
<pre><span class="lnum">  20:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> SwitchOff()</pre>
<pre class="alt"><span class="lnum">  21:  </span>{</pre>
<pre><span class="lnum">  22:  </span>  <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre class="alt"><span class="lnum">  23:  </span>  {</pre>
<pre><span class="lnum">  24:  </span>    _CommandQueue.Enqueue(CreateSwitchOffCommand());</pre>
<pre class="alt"><span class="lnum">  25:  </span>  }</pre>
<pre><span class="lnum">  26:  </span>}</pre>
<pre class="alt"><span class="lnum">  27:  </span><span class="kwrd">private</span> <span class="kwrd">byte</span>[] CreateSwitchOffCommand()</pre>
<pre><span class="lnum">  28:  </span>{</pre>
<pre class="alt"><span class="lnum">  29:  </span>  <span class="kwrd">byte</span>[] command = <span class="kwrd">new</span> <span class="kwrd">byte</span>[COMMAND_LENGTH];</pre>
<pre><span class="lnum">  30:  </span>  command[0] = 3;</pre>
<pre class="alt"><span class="lnum">  31:  </span>  command[COMMAND_LAST] = 3;</pre>
<pre><span class="lnum">  32:  </span>  <span class="kwrd">return</span> command;</pre>
<pre class="alt"><span class="lnum">  33:  </span>}</pre>
<pre><span class="lnum">  34:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> SetBrightness(Brightness brightness)</pre>
<pre class="alt"><span class="lnum">  35:  </span>{</pre>
<pre><span class="lnum">  36:  </span>  <span class="kwrd">byte</span>[] command = <span class="kwrd">new</span> <span class="kwrd">byte</span>[COMMAND_LENGTH];</pre>
<pre class="alt"><span class="lnum">  37:  </span>  command[0] = 9;</pre>
<pre><span class="lnum">  38:  </span>  command[1] = (<span class="kwrd">byte</span>)brightness;</pre>
<pre class="alt"><span class="lnum">  39:  </span>  command[COMMAND_LAST] = (<span class="kwrd">byte</span>)(command[0] &#43; command[1]);</pre>
<pre><span class="lnum">  40:  </span>  <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre class="alt"><span class="lnum">  41:  </span>  {</pre>
<pre><span class="lnum">  42:  </span>    _CommandQueue.Enqueue(command);</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="kwrd">public</span> <span class="kwrd">void</span> ShowImage(<span class="kwrd">byte</span> keyIndex)</pre>
<pre><span class="lnum">  46:  </span>{</pre>
<pre class="alt"><span class="lnum">  47:  </span>  <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre><span class="lnum">  48:  </span>  {</pre>
<pre class="alt"><span class="lnum">  49:  </span>    _CommandQueue.Enqueue(CreateShowImageCommand(keyIndex));</pre>
<pre><span class="lnum">  50:  </span>  }</pre>
<pre class="alt"><span class="lnum">  51:  </span>}</pre>
<pre><span class="lnum">  52:  </span><span class="kwrd">private</span> <span class="kwrd">byte</span>[] CreateShowImageCommand(<span class="kwrd">byte</span> keyIndex)</pre>
<pre class="alt"><span class="lnum">  53:  </span>{</pre>
<pre><span class="lnum">  54:  </span>  <span class="kwrd">byte</span>[] command = <span class="kwrd">new</span> <span class="kwrd">byte</span>[COMMAND_LENGTH];</pre>
<pre class="alt"><span class="lnum">  55:  </span>  command[0] = 4;</pre>
<pre><span class="lnum">  56:  </span>  command[1] = (<span class="kwrd">byte</span>)(keyIndex &#43; 1);</pre>
<pre class="alt"><span class="lnum">  57:  </span>  command[COMMAND_LAST] = (<span class="kwrd">byte</span>)(command[0] &#43; command[1]);</pre>
<pre><span class="lnum">  58:  </span>  <span class="kwrd">return</span> command;</pre>
<pre class="alt"><span class="lnum">  59:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> _CommandQueue <span class="kwrd">As</span> Queue(Of <span class="kwrd">Byte</span>()) = <span class="kwrd">New</span> Queue(Of <span class="kwrd">Byte</span>())</pre>
<pre><span class="lnum">   2:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">Public</span> <span class="kwrd">Const</span> SCREEN_SIZE <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 96</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">Public</span> <span class="kwrd">Enum</span> Brightness</pre>
<pre class="alt"><span class="lnum">   5:  </span>  Low = 20</pre>
<pre><span class="lnum">   6:  </span>  Normal = 40</pre>
<pre class="alt"><span class="lnum">   7:  </span>  High = 60</pre>
<pre><span class="lnum">   8:  </span><span class="kwrd">End</span> <span class="kwrd">Enum</span></pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> SwitchOn()</pre>
<pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(COMMAND_LENGTH) {}</pre>
<pre><span class="lnum">  12:  </span>  command(0) = 2</pre>
<pre class="alt"><span class="lnum">  13:  </span>  command(COMMAND_LAST) = 2</pre>
<pre><span class="lnum">  14:  </span>  <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre class="alt"><span class="lnum">  15:  </span>    _CommandQueue.Enqueue(command)</pre>
<pre><span class="lnum">  16:  </span>  <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre class="alt"><span class="lnum">  17:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<pre><span class="lnum">  18:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> SwitchOff()</pre>
<pre class="alt"><span class="lnum">  19:  </span>  <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre><span class="lnum">  20:  </span>    _CommandQueue.Enqueue(CreateSwitchOffCommand())</pre>
<pre class="alt"><span class="lnum">  21:  </span>  <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre><span class="lnum">  22:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<pre class="alt"><span class="lnum">  23:  </span><span class="kwrd">Private</span> <span class="kwrd">Function</span> CreateSwitchOffCommand() <span class="kwrd">As</span> <span class="kwrd">Byte</span>()</pre>
<pre><span class="lnum">  24:  </span>  <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(COMMAND_LENGTH) {}</pre>
<pre class="alt"><span class="lnum">  25:  </span>  command(0) = 3</pre>
<pre><span class="lnum">  26:  </span>  command(COMMAND_LAST) = 3</pre>
<pre class="alt"><span class="lnum">  27:  </span>  <span class="kwrd">Return</span> command</pre>
<pre><span class="lnum">  28:  </span><span class="kwrd">End</span> <span class="kwrd">Function</span></pre>
<pre class="alt"><span class="lnum">  29:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> SetBrightness(<span class="kwrd">ByVal</span> brightness <span class="kwrd">As</span> Brightness)</pre>
<pre><span class="lnum">  30:  </span>  <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(COMMAND_LENGTH) {}</pre>
<pre class="alt"><span class="lnum">  31:  </span>  command(0) = 9</pre>
<pre><span class="lnum">  32:  </span>  command(1) = <span class="kwrd">CType</span>(brightness, <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">  33:  </span>  command(COMMAND_LAST) = <span class="kwrd">CType</span>((command(0) &#43; command(1)), <span class="kwrd">Byte</span>)</pre>
<pre><span class="lnum">  34:  </span>  <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre class="alt"><span class="lnum">  35:  </span>    _CommandQueue.Enqueue(command)</pre>
<pre><span class="lnum">  36:  </span>  <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre class="alt"><span class="lnum">  37:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<pre><span class="lnum">  38:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> ShowImage(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">  39:  </span>  <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre><span class="lnum">  40:  </span>    _CommandQueue.Enqueue(CreateShowImageCommand(keyIndex))</pre>
<pre class="alt"><span class="lnum">  41:  </span>  <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre><span class="lnum">  42:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<pre class="alt"><span class="lnum">  43:  </span><span class="kwrd">Private</span> <span class="kwrd">Function</span> CreateShowImageCommand(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>) <span class="kwrd">As</span> <span class="kwrd">Byte</span>()</pre>
<pre><span class="lnum">  44:  </span>  <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(COMMAND_LENGTH) {}</pre>
<pre class="alt"><span class="lnum">  45:  </span>  command(0) = 4</pre>
<pre><span class="lnum">  46:  </span>  command(1) = <span class="kwrd">CType</span>((keyIndex &#43; 1), <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">  47:  </span>  command(COMMAND_LAST) = <span class="kwrd">CType</span>((command(0) &#43; command(1)), <span class="kwrd">Byte</span>)</pre>
<pre><span class="lnum">  48:  </span>  <span class="kwrd">Return</span> command</pre>
<pre class="alt"><span class="lnum">  49:  </span><span class="kwrd">End</span> <span class="kwrd">Function</span></pre>
</div>
<p>A more complex command is required to send the image data. Actually we need to send 96 such commands because the data is send line by line. We need to access the passed bitmap pixel by pixel to put together the commands, so we'll first copy the bitmap into
 a byte array for faster access. </p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> SetImage(<span class="kwrd">byte</span> keyIndex, System.Drawing.Bitmap image)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="rem">// Copy image into array for faster processing</span></pre>
<pre><span class="lnum">   4:  </span>  BitmapData imageData = image.LockBits(</pre>
<pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">new</span> Rectangle(0, 0, SCREEN_SIZE, SCREEN_SIZE),</pre>
<pre><span class="lnum">   6:  </span>    ImageLockMode.ReadOnly,</pre>
<pre class="alt"><span class="lnum">   7:  </span>    PixelFormat.Format24bppRgb);</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">int</span> imageRgbLength = SCREEN_SIZE * SCREEN_SIZE * 3;</pre>
<pre class="alt"><span class="lnum">   9:  </span>  <span class="kwrd">byte</span>[] imageRgb = <span class="kwrd">new</span> <span class="kwrd">byte</span>[imageRgbLength];</pre>
<pre><span class="lnum">  10:  </span>  System.Runtime.InteropServices.Marshal.Copy(imageData.Scan0, imageRgb, 0, imageRgbLength);</pre>
<pre class="alt"><span class="lnum">  11:  </span>  image.UnlockBits(imageData);</pre>
<pre><span class="lnum">  12:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="rem">// Convert image to commands</span></pre>
<pre><span class="lnum">  14:  </span>  <span class="kwrd">byte</span> colorR, colorG, colorB;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">int</span> imageRgbIndex;</pre>
<pre><span class="lnum">  16:  </span>  <span class="kwrd">byte</span>[] command;</pre>
<pre class="alt"><span class="lnum">  17:  </span>&nbsp;</pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">for</span> (<span class="kwrd">int</span> y = 0; y &lt; SCREEN_SIZE; y &#43;= 1)</pre>
<pre class="alt"><span class="lnum">  19:  </span>  {</pre>
<pre><span class="lnum">  20:  </span>    command = <span class="kwrd">new</span> <span class="kwrd">byte</span>[COMMAND_LENGTH];</pre>
<pre class="alt"><span class="lnum">  21:  </span>    command[0] = 1;</pre>
<pre><span class="lnum">  22:  </span>    command[1] = (<span class="kwrd">byte</span>)(keyIndex &#43; 1);</pre>
<pre class="alt"><span class="lnum">  23:  </span>    command[2] = (<span class="kwrd">byte</span>)((192 * y) &gt;&gt; 8);</pre>
<pre><span class="lnum">  24:  </span>    command[3] = (<span class="kwrd">byte</span>)((192 * y) - (command[2] &lt;&lt; 8));</pre>
<pre class="alt"><span class="lnum">  25:  </span>    command[COMMAND_LAST] &#43;= (<span class="kwrd">byte</span>)(command[0] &#43; command[1] &#43; command[2] &#43; command[3]);</pre>
<pre><span class="lnum">  26:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  27:  </span>    <span class="kwrd">for</span> (<span class="kwrd">int</span> x = 0; x &lt; SCREEN_SIZE; x &#43;= 1)</pre>
<pre><span class="lnum">  28:  </span>    {</pre>
<pre class="alt"><span class="lnum">  29:  </span>      imageRgbIndex = y * SCREEN_SIZE * 3 &#43; x * 3;</pre>
<pre><span class="lnum">  30:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  31:  </span>      colorR = imageRgb[imageRgbIndex &#43; 2];</pre>
<pre><span class="lnum">  32:  </span>      colorG = imageRgb[imageRgbIndex &#43; 1];</pre>
<pre class="alt"><span class="lnum">  33:  </span>      colorB = imageRgb[imageRgbIndex];</pre>
<pre><span class="lnum">  34:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  35:  </span>      command[4 &#43; x * 2] = (<span class="kwrd">byte</span>)((colorR &amp; 0xF8) &#43; (colorG &gt;&gt; 5));</pre>
<pre><span class="lnum">  36:  </span>      command[5 &#43; x * 2] = (<span class="kwrd">byte</span>)((colorB &gt;&gt; 3) &#43; ((colorG &amp; 0x1C) &lt;&lt; 3));</pre>
<pre class="alt"><span class="lnum">  37:  </span>&nbsp;</pre>
<pre><span class="lnum">  38:  </span>      command[COMMAND_LAST] &#43;= command[4 &#43; x * 2];</pre>
<pre class="alt"><span class="lnum">  39:  </span>      command[COMMAND_LAST] &#43;= command[5 &#43; x * 2];</pre>
<pre><span class="lnum">  40:  </span>    }</pre>
<pre class="alt"><span class="lnum">  41:  </span>&nbsp;</pre>
<pre><span class="lnum">  42:  </span>    <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre class="alt"><span class="lnum">  43:  </span>    {</pre>
<pre><span class="lnum">  44:  </span>      _CommandQueue.Enqueue(command);</pre>
<pre class="alt"><span class="lnum">  45:  </span>    }</pre>
<pre><span class="lnum">  46:  </span>  }</pre>
<pre class="alt"><span class="lnum">  47:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> SetImage(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>, <span class="kwrd">ByVal</span> image <span class="kwrd">As</span> Bitmap)</pre>
<pre><span class="lnum">   2:  </span>  <span class="rem">'Copy image into array for faster processing</span></pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">Dim</span> imageData <span class="kwrd">As</span> BitmapData = image.LockBits( _</pre>
<pre><span class="lnum">   4:  </span>    <span class="kwrd">New</span> Rectangle(0, 0, SCREEN_SIZE, SCREEN_SIZE), _</pre>
<pre class="alt"><span class="lnum">   5:  </span>    ImageLockMode.<span class="kwrd">ReadOnly</span>, _</pre>
<pre><span class="lnum">   6:  </span>    PixelFormat.Format24bppRgb)</pre>
<pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">Dim</span> imageRgbLength <span class="kwrd">As</span> <span class="kwrd">Integer</span> = SCREEN_SIZE * SCREEN_SIZE * 3</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">Dim</span> imageRgb() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(imageRgbLength) {}</pre>
<pre class="alt"><span class="lnum">   9:  </span>  System.Runtime.InteropServices.Marshal.Copy(imageData.Scan0, imageRgb, 0, imageRgbLength)</pre>
<pre><span class="lnum">  10:  </span>  image.UnlockBits(imageData)</pre>
<pre class="alt"><span class="lnum">  11:  </span>&nbsp;</pre>
<pre><span class="lnum">  12:  </span>  <span class="rem">'Convert image to commands</span></pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">Dim</span> colorR <span class="kwrd">As</span> <span class="kwrd">Byte</span>, colorG <span class="kwrd">As</span> <span class="kwrd">Byte</span>, colorB <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre><span class="lnum">  14:  </span>  <span class="kwrd">Dim</span> imageRgbIndex <span class="kwrd">As</span> <span class="kwrd">Integer</span></pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre><span class="lnum">  16:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">Dim</span> y <span class="kwrd">As</span> <span class="kwrd">Integer</span></pre>
<pre><span class="lnum">  18:  </span>  <span class="kwrd">For</span> y = 0 <span class="kwrd">To</span> SCREEN_SIZE - 1</pre>
<pre class="alt"><span class="lnum">  19:  </span>    command = <span class="kwrd">New</span> <span class="kwrd">Byte</span>(COMMAND_LENGTH) {}</pre>
<pre><span class="lnum">  20:  </span>    command(0) = 1</pre>
<pre class="alt"><span class="lnum">  21:  </span>    command(1) = <span class="kwrd">CByte</span>(keyIndex &#43; 1)</pre>
<pre><span class="lnum">  22:  </span>    command(2) = <span class="kwrd">CByte</span>((192 * y) &gt;&gt; 8)</pre>
<pre class="alt"><span class="lnum">  23:  </span>    command(3) = <span class="kwrd">CByte</span>((192 * y) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre><span class="lnum">  24:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  25:  </span>    command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(0)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre><span class="lnum">  26:  </span>    command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(1)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre class="alt"><span class="lnum">  27:  </span>    command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(2)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre><span class="lnum">  28:  </span>    command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(3)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre class="alt"><span class="lnum">  29:  </span>&nbsp;</pre>
<pre><span class="lnum">  30:  </span>    <span class="kwrd">Dim</span> x <span class="kwrd">As</span> <span class="kwrd">Integer</span></pre>
<pre class="alt"><span class="lnum">  31:  </span>    <span class="kwrd">For</span> x = 0 <span class="kwrd">To</span> SCREEN_SIZE - 1</pre>
<pre><span class="lnum">  32:  </span>      imageRgbIndex = y * SCREEN_SIZE * 3 &#43; x * 3</pre>
<pre class="alt"><span class="lnum">  33:  </span>&nbsp;</pre>
<pre><span class="lnum">  34:  </span>      colorR = imageRgb(imageRgbIndex &#43; 2)</pre>
<pre class="alt"><span class="lnum">  35:  </span>      colorG = imageRgb(imageRgbIndex &#43; 1)</pre>
<pre><span class="lnum">  36:  </span>      colorB = imageRgb(imageRgbIndex)</pre>
<pre class="alt"><span class="lnum">  37:  </span>&nbsp;</pre>
<pre><span class="lnum">  38:  </span>      command(4 &#43; x * 2) = <span class="kwrd">CByte</span>(((colorR <span class="kwrd">And</span> &amp;HF8) &#43; (colorG &gt;&gt; 5)))</pre>
<pre class="alt"><span class="lnum">  39:  </span>      command(5 &#43; x * 2) = <span class="kwrd">CByte</span>(((colorB &gt;&gt; 3) &#43; ((colorG <span class="kwrd">And</span> &amp;H1C) &lt;&lt; 3)))</pre>
<pre><span class="lnum">  40:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  41:  </span>      command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(4 &#43; x * 2)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre><span class="lnum">  42:  </span>      command(COMMAND_LAST) = <span class="kwrd">CByte</span>((<span class="kwrd">CShort</span>(command(COMMAND_LAST)) &#43; command(5 &#43; x * 2)) <span class="kwrd">And</span> &amp;HFF)</pre>
<pre class="alt"><span class="lnum">  43:  </span>    <span class="kwrd">Next</span></pre>
<pre><span class="lnum">  44:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  45:  </span>    <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre><span class="lnum">  46:  </span>      _CommandQueue.Enqueue(command)</pre>
<pre class="alt"><span class="lnum">  47:  </span>    <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre><span class="lnum">  48:  </span>  <span class="kwrd">Next</span></pre>
<pre class="alt"><span class="lnum">  49:  </span>&nbsp;</pre>
<pre><span class="lnum">  50:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
</div>
<p>There's some shifting taking place because the device requires 16 bit colors - 5 bits red, 6 bits green and another 5 bits for blue. The VB version has some additional code to be not dependent on the
<em>Remove integer overflow checks</em> project setting. </p>
<h4>The background thread</h4>
<p>Everything is in place to fill up the queue with commands, time to add the background thread code to empty it. The task of the thread is quite simple: check if there're any queued commands and send them until we tell him to stop. Additionally it sends show
 commands every 5 seconds. That's done because the device would switch off automatically after about 10 seconds if there were no commands.
</p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> ProcessCommands()</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">bool</span> exit = <span class="kwrd">false</span>;</pre>
<pre><span class="lnum">   4:  </span>  <span class="kwrd">int</span> lastShowOn = Environment.TickCount;</pre>
<pre class="alt"><span class="lnum">   5:  </span>&nbsp;</pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">while</span> (_Connected &amp;&amp; !exit)</pre>
<pre class="alt"><span class="lnum">   7:  </span>  {</pre>
<pre><span class="lnum">   8:  </span>    <span class="rem">// Time for regular refresh?</span></pre>
<pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">if</span> (Environment.TickCount - lastShowOn &gt; 5000)</pre>
<pre><span class="lnum">  10:  </span>    {</pre>
<pre class="alt"><span class="lnum">  11:  </span>      <span class="kwrd">for</span> (<span class="kwrd">byte</span> i = 0; i &lt;= 2; i&#43;&#43;)</pre>
<pre><span class="lnum">  12:  </span>      {</pre>
<pre class="alt"><span class="lnum">  13:  </span>        <span class="kwrd">if</span> (!SendCommand(CreateShowImageCommand(i))) { <span class="kwrd">break</span>; }</pre>
<pre><span class="lnum">  14:  </span>      }</pre>
<pre class="alt"><span class="lnum">  15:  </span>      lastShowOn = Environment.TickCount;</pre>
<pre><span class="lnum">  16:  </span>    }</pre>
<pre class="alt"><span class="lnum">  17:  </span>&nbsp;</pre>
<pre><span class="lnum">  18:  </span>    <span class="rem">// If we've commands ...</span></pre>
<pre class="alt"><span class="lnum">  19:  </span>    <span class="kwrd">if</span> (_CommandQueue.Count &gt; 0)</pre>
<pre><span class="lnum">  20:  </span>    {</pre>
<pre class="alt"><span class="lnum">  21:  </span>      <span class="kwrd">while</span> (_CommandQueue.Count &gt; 0)</pre>
<pre><span class="lnum">  22:  </span>      {</pre>
<pre class="alt"><span class="lnum">  23:  </span>        <span class="rem">// ... process them</span></pre>
<pre><span class="lnum">  24:  </span>        <span class="kwrd">byte</span>[] command;</pre>
<pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">lock</span> (_CommandQueue)</pre>
<pre><span class="lnum">  26:  </span>        {</pre>
<pre class="alt"><span class="lnum">  27:  </span>          command = _CommandQueue.Dequeue();</pre>
<pre><span class="lnum">  28:  </span>        }</pre>
<pre class="alt"><span class="lnum">  29:  </span>        <span class="kwrd">if</span> (!SendCommand(command))</pre>
<pre><span class="lnum">  30:  </span>        {</pre>
<pre class="alt"><span class="lnum">  31:  </span>          exit = <span class="kwrd">true</span>;</pre>
<pre><span class="lnum">  32:  </span>          <span class="kwrd">break</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>
<pre><span class="lnum">  36:  </span>    <span class="kwrd">else</span></pre>
<pre class="alt"><span class="lnum">  37:  </span>    {</pre>
<pre><span class="lnum">  38:  </span>      <span class="rem">// No commands, time to relax</span></pre>
<pre class="alt"><span class="lnum">  39:  </span>     Thread.Sleep(10);</pre>
<pre><span class="lnum">  40:  </span>    }</pre>
<pre class="alt"><span class="lnum">  41:  </span>  }</pre>
<pre><span class="lnum">  42:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Private</span> <span class="kwrd">Sub</span> ProcessCommands()</pre>
<pre><span class="lnum">   2:  </span>  <span class="kwrd">Dim</span> exitThread <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">False</span></pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">Dim</span> lastShowOn <span class="kwrd">As</span> <span class="kwrd">Integer</span> = Environment.TickCount</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">While</span> _Connected <span class="kwrd">And</span> <span class="kwrd">Not</span> exitThread</pre>
<pre><span class="lnum">   6:  </span>    <span class="rem">'Time for regular refresh?</span></pre>
<pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">If</span> (Environment.TickCount - lastShowOn &gt; 5000) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">   8:  </span>      <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre class="alt"><span class="lnum">   9:  </span>      <span class="kwrd">For</span> i = 0 <span class="kwrd">To</span> 2</pre>
<pre><span class="lnum">  10:  </span>        <span class="kwrd">If</span> (<span class="kwrd">Not</span> SendCommand(CreateShowImageCommand(i))) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>          <span class="kwrd">Exit</span> <span class="kwrd">While</span></pre>
<pre><span class="lnum">  12:  </span>        <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  13:  </span>      <span class="kwrd">Next</span></pre>
<pre><span class="lnum">  14:  </span>      lastShowOn = Environment.TickCount</pre>
<pre class="alt"><span class="lnum">  15:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  16:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  17:  </span>    <span class="rem">'If we've commands ...</span></pre>
<pre><span class="lnum">  18:  </span>    <span class="kwrd">If</span> (_CommandQueue.Count &gt; 0) <span class="kwrd">Then</span></pre>
<pre class="alt"><span class="lnum">  19:  </span>      <span class="kwrd">While</span> _CommandQueue.Count &gt; 0</pre>
<pre><span class="lnum">  20:  </span>        <span class="rem">'... process them</span></pre>
<pre class="alt"><span class="lnum">  21:  </span>        <span class="kwrd">Dim</span> command() <span class="kwrd">As</span> <span class="kwrd">Byte</span></pre>
<pre><span class="lnum">  22:  </span>        <span class="kwrd">SyncLock</span> _CommandQueue</pre>
<pre class="alt"><span class="lnum">  23:  </span>          command = _CommandQueue.Dequeue()</pre>
<pre><span class="lnum">  24:  </span>        <span class="kwrd">End</span> <span class="kwrd">SyncLock</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">If</span> (<span class="kwrd">Not</span> SendCommand(command)) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">  26:  </span>          exitThread = <span class="kwrd">True</span></pre>
<pre class="alt"><span class="lnum">  27:  </span>          <span class="kwrd">Exit</span> <span class="kwrd">While</span></pre>
<pre><span class="lnum">  28:  </span>        <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">  29:  </span>      <span class="kwrd">End</span> <span class="kwrd">While</span></pre>
<pre><span class="lnum">  30:  </span>    <span class="kwrd">Else</span></pre>
<pre class="alt"><span class="lnum">  31:  </span>      <span class="rem">'No commands, time to relax</span></pre>
<pre><span class="lnum">  32:  </span>      Thread.Sleep(10)</pre>
<pre class="alt"><span class="lnum">  33:  </span>    <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre><span class="lnum">  34:  </span>  <span class="kwrd">End</span> <span class="kwrd">While</span></pre>
<pre class="alt"><span class="lnum">  35:  </span>&nbsp;</pre>
<pre><span class="lnum">  36:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
</div>
<h4>Turn off</h4>
<p>The last method is used to turn the device off. We stop the background thread and before closing the port a switch off command is send.
</p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> Terminate()</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">if</span> (!_Connected) { <span class="kwrd">return</span>; }</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="rem">// Stop processing commands</span></pre>
<pre><span class="lnum">   6:  </span>  <span class="kwrd">if</span> (_ProcessCommandsThread.IsAlive)</pre>
<pre class="alt"><span class="lnum">   7:  </span>  {</pre>
<pre><span class="lnum">   8:  </span>    _ProcessCommandsThread.Abort();</pre>
<pre class="alt"><span class="lnum">   9:  </span>    _ProcessCommandsThread.Join(1000);</pre>
<pre><span class="lnum">  10:  </span>  }</pre>
<pre class="alt"><span class="lnum">  11:  </span>&nbsp;</pre>
<pre><span class="lnum">  12:  </span>  <span class="rem">// Switch off</span></pre>
<pre class="alt"><span class="lnum">  13:  </span>  SendCommand(CreateSwitchOffCommand());</pre>
<pre><span class="lnum">  14:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  <span class="rem">// Close port</span></pre>
<pre><span class="lnum">  16:  </span>  _Port.Close();</pre>
<pre class="alt"><span class="lnum">  17:  </span>  _Connected = <span class="kwrd">false</span>;</pre>
<pre><span class="lnum">  18:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Public</span> <span class="kwrd">Sub</span> Terminate()</pre>
<pre><span class="lnum">   2:  </span>  <span class="kwrd">If</span> (<span class="kwrd">Not</span> _Connected) <span class="kwrd">Then</span> <span class="kwrd">Exit</span> <span class="kwrd">Sub</span></pre>
<pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre>
<pre><span class="lnum">   4:  </span>  <span class="rem">'Stop processing commands</span></pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">If</span> (_ProcessCommandsThread.IsAlive) <span class="kwrd">Then</span></pre>
<pre><span class="lnum">   6:  </span>    _ProcessCommandsThread.Abort()</pre>
<pre class="alt"><span class="lnum">   7:  </span>    _ProcessCommandsThread.Join(1000)</pre>
<pre><span class="lnum">   8:  </span>  <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre>
<pre><span class="lnum">  10:  </span>  <span class="rem">'Switch off</span></pre>
<pre class="alt"><span class="lnum">  11:  </span>  SendCommand(CreateSwitchOffCommand())</pre>
<pre><span class="lnum">  12:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  13:  </span>  <span class="rem">'Close port</span></pre>
<pre><span class="lnum">  14:  </span>  _Port.Close()</pre>
<pre class="alt"><span class="lnum">  15:  </span>  _Connected = <span class="kwrd">False</span></pre>
<pre><span class="lnum">  16:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  17:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
</div>
<h4>Using this class</h4>
<p>Now comes the most interesting part of this exercise: seeing the code in action. For this we'll add some code to the main method of the console application to display the RGB colors on the key and to print the key down events. Ok, not that cool yet, but
 should give you an idea how to use it. </p>
<p><strong>C#</strong> </p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre class="alt"><span class="lnum">   3:  </span>  OptimusMiniDevice device = <span class="kwrd">new</span> OptimusMiniDevice();</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  device.OnKeyDown &#43;= <span class="kwrd">new</span> OptimusMiniDevice.KeyDownEventHandler(device_OnKeyDown);</pre>
<pre><span class="lnum">   6:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   7:  </span>  device.Init();</pre>
<pre><span class="lnum">   8:  </span>  device.SwitchOn();</pre>
<pre class="alt"><span class="lnum">   9:  </span>  device.SetBrightness(OptimusMiniDevice.Brightness.Low);</pre>
<pre><span class="lnum">  10:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  11:  </span>  device.SetImage(0, GetColor(System.Drawing.Brushes.Red));</pre>
<pre><span class="lnum">  12:  </span>  device.SetImage(1, GetColor(System.Drawing.Brushes.Green));</pre>
<pre class="alt"><span class="lnum">  13:  </span>  device.SetImage(2, GetColor(System.Drawing.Brushes.Blue));</pre>
<pre><span class="lnum">  14:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  device.ShowImage(0);</pre>
<pre><span class="lnum">  16:  </span>  device.ShowImage(1);</pre>
<pre class="alt"><span class="lnum">  17:  </span>  device.ShowImage(2);</pre>
<pre><span class="lnum">  18:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  19:  </span>  Console.ReadKey();</pre>
<pre><span class="lnum">  20:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  21:  </span>  device.SwitchOff();</pre>
<pre><span class="lnum">  22:  </span>  device.Terminate();</pre>
<pre class="alt"><span class="lnum">  23:  </span>}</pre>
<pre><span class="lnum">  24:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  25:  </span><span class="kwrd">static</span> System.Drawing.Bitmap GetColor(System.Drawing.Brush brush)</pre>
<pre><span class="lnum">  26:  </span>{</pre>
<pre class="alt"><span class="lnum">  27:  </span>  System.Drawing.Bitmap bitmap = <span class="kwrd">new</span> Bitmap(OptimusMiniDevice.SCREEN_SIZE, OptimusMiniDevice.SCREEN_SIZE);</pre>
<pre><span class="lnum">  28:  </span>  System.Drawing.Graphics graphic = Graphics.FromImage(bitmap);</pre>
<pre class="alt"><span class="lnum">  29:  </span>  graphic.FillRectangle(brush, <span class="kwrd">new</span> Rectangle(0, 0, OptimusMiniDevice.SCREEN_SIZE, OptimusMiniDevice.SCREEN_SIZE));</pre>
<pre><span class="lnum">  30:  </span>  graphic.Flush();</pre>
<pre class="alt"><span class="lnum">  31:  </span>  <span class="kwrd">return</span> bitmap;</pre>
<pre><span class="lnum">  32:  </span>}</pre>
<pre class="alt"><span class="lnum">  33:  </span>&nbsp;</pre>
<pre><span class="lnum">  34:  </span><span class="kwrd">static</span> <span class="kwrd">void</span> device_OnKeyDown(<span class="kwrd">byte</span> keyIndex)</pre>
<pre class="alt"><span class="lnum">  35:  </span>{</pre>
<pre><span class="lnum">  36:  </span>  Console.WriteLine(<span class="kwrd">string</span>.Format(<span class="str">&quot;key down {0}&quot;</span>, keyIndex));</pre>
<pre class="alt"><span class="lnum">  37:  </span>}</pre>
</div>
<p><strong>VB</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">Sub</span> Main()</pre>
<pre><span class="lnum">   2:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">Dim</span> device <span class="kwrd">As</span> OptimusMiniDevice = <span class="kwrd">New</span> OptimusMiniDevice()</pre>
<pre><span class="lnum">   4:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">AddHandler</span> device.OnKeyDown, <span class="kwrd">AddressOf</span> device_OnKeyDown</pre>
<pre><span class="lnum">   6:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">   7:  </span>  device.Init()</pre>
<pre><span class="lnum">   8:  </span>  device.SwitchOn()</pre>
<pre class="alt"><span class="lnum">   9:  </span>  device.SetBrightness(OptimusMiniDevice.Brightness.Low)</pre>
<pre><span class="lnum">  10:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  11:  </span>  device.SetImage(0, GetColor(Brushes.Red))</pre>
<pre><span class="lnum">  12:  </span>  device.SetImage(1, GetColor(Brushes.Green))</pre>
<pre class="alt"><span class="lnum">  13:  </span>  device.SetImage(2, GetColor(Brushes.Blue))</pre>
<pre><span class="lnum">  14:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  15:  </span>  device.ShowImage(0)</pre>
<pre><span class="lnum">  16:  </span>  device.ShowImage(1)</pre>
<pre class="alt"><span class="lnum">  17:  </span>  device.ShowImage(2)</pre>
<pre><span class="lnum">  18:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  19:  </span>  Console.ReadKey()</pre>
<pre><span class="lnum">  20:  </span>&nbsp;</pre>
<pre class="alt"><span class="lnum">  21:  </span>  device.SwitchOff()</pre>
<pre><span class="lnum">  22:  </span>  device.Terminate()</pre>
<pre class="alt"><span class="lnum">  23:  </span>&nbsp;</pre>
<pre><span class="lnum">  24:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<pre class="alt"><span class="lnum">  25:  </span>&nbsp;</pre>
<pre><span class="lnum">  26:  </span><span class="kwrd">Function</span> GetColor(<span class="kwrd">ByVal</span> brush <span class="kwrd">As</span> Brush)</pre>
<pre class="alt"><span class="lnum">  27:  </span>  <span class="kwrd">Dim</span> bitmap <span class="kwrd">As</span> Bitmap = <span class="kwrd">New</span> Bitmap(OptimusMiniDevice.SCREEN_SIZE, OptimusMiniDevice.SCREEN_SIZE)</pre>
<pre><span class="lnum">  28:  </span>  <span class="kwrd">Dim</span> graphic <span class="kwrd">As</span> Graphics = Graphics.FromImage(bitmap)</pre>
<pre class="alt"><span class="lnum">  29:  </span>  graphic.FillRectangle(brush, <span class="kwrd">New</span> Rectangle(0, 0, OptimusMiniDevice.SCREEN_SIZE, OptimusMiniDevice.SCREEN_SIZE))</pre>
<pre><span class="lnum">  30:  </span>  graphic.Flush()</pre>
<pre class="alt"><span class="lnum">  31:  </span>  <span class="kwrd">Return</span> bitmap</pre>
<pre><span class="lnum">  32:  </span><span class="kwrd">End</span> <span class="kwrd">Function</span></pre>
<pre class="alt"><span class="lnum">  33:  </span>&nbsp;</pre>
<pre><span class="lnum">  34:  </span><span class="kwrd">Sub</span> device_OnKeyDown(<span class="kwrd">ByVal</span> keyIndex <span class="kwrd">As</span> <span class="kwrd">Byte</span>)</pre>
<pre class="alt"><span class="lnum">  35:  </span>  Console.WriteLine(<span class="kwrd">String</span>.Format(<span class="str">&quot;key down {0}&quot;</span>, keyIndex))</pre>
<pre><span class="lnum">  36:  </span><span class="kwrd">End</span> <span class="kwrd">Sub</span></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></p>
<h4>Conclusion</h4>
<p>That's it, a pretty straightforward class and easy to use - and for sure extendable. This is the prototype i've built to play around with the device and i'm working on an improved version, but it's not quite ready for prime time yet (you can
<a href="http://code.google.com/p/om3controller/source">take a look on the source</a> though, comments welcome). I hope you found the article interesting, my first one.
</p>
<h4>Bio</h4>
Harald has more than 5 years experience developing .net solutions and has been coding for fun for as long as he can remember. Works currently as an architect in the travel industry, building web based solutions. Outside the world of coding he is enjoying good
 books and lately he's working hard to improve his wii tennis skills. He can be reached through his
<a href="http://www.toolz.at">website</a>. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Harald-Rxeisen/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:1f19f9d09edd4a99be1b9e7600d348dd">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Using-Optimus-Mini-Three-with-net</comments>
      <itunes:summary>



&amp;nbsp;
Even though the device is connected to an usb port the communication is done through a (virtual) serial port. The protocol specification is available in
the developer section on Art.Lebedev Studio&#39;s website. There&#39;s also some c sample code available which proved to be very useful to build this class. The document lists the following
 commands to send data to the device:

Switch the device on and off Send image data for a specific key Show sent image for a specific key Change the brightness 
There&#39;re two additional commands available, to read and write the internal id of the device. We&#39;re not going to use them for this article. They could be used if you&#39;ve multiple devices connected to differentiate them.


All the commands we&#39;re sending have a length of 197 bytes, the last byte being the checksum. The response to a command consists of two bytes: a 0 to tell us this is a command confirmation and as second byte the checksum. Ideally that checksum matches the one
 of the sent command - if not the data was somehow corrupted and we&#39;ve to send it again.


And the device is not just waiting until we send it something, it will also send something to us: the keys which are currently pressed - of course, wouldn&#39;t qualify as keyboard otherwise. These messages are also 2 bytes long, first byte being a 1 and the second
 byte is the 1-based index of the pressed key. We can get them anytime and very often - as long as one or more keys are pressed they&#39;re repeatedly send. When commands are send at the same time we get a mix of key messages and command confirmations.






Harald R&#246;xeisen 

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Optimus mini three software
Hardware: Optimus mini three keyboard
Download: Download








Getting started: the serial port
First we need to know the serial port to connect to. Usb devices are stored in the windows registry in
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB, and the device id we&#39;re looking f</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Using-Optimus-Mini-Three-with-net</link>
      <pubDate>Fri, 13 Jul 2007 16:00:53 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Using-Optimus-Mini-Three-with-net</guid>      
      <dc:creator>Harald R&#246;xeisen</dc:creator>
      <itunes:author>Harald R&#246;xeisen</itunes:author>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Using-Optimus-Mini-Three-with-net/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>utility</category>
    </item>    
</channel>
</rss>