<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-18785914</id><updated>2007-02-28T00:20:28.552-05:00</updated><title type='text'>justinhenry.com log</title><link rel='alternate' type='text/html' href='http://www.justinhenry.com/index.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default'></link><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.justinhenry.com/atom.xml'></link><author><name>Justin</name></author><generator version='7.00' uri='http://www2.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>tag:blogger.com,1999:blog-18785914.post-4714377767271303983</id><published>2007-02-27T23:36:00.000-05:00</published><updated>2007-02-28T00:20:28.593-05:00</updated><title type='text'>DIY Sirius FM Direct Adapter Installation</title><content type='html'>I've had Sirius satellite radio for a few months, and it's been a great addition to the daily commute and my in-office work environment (via the web). I own the cheapest possible Sirius "plug and play" radio, the &lt;a href="http://shop.sirius.com/edealinv/servlet/ExecMacro?nurl=control/StoreItem.vm&amp;ctl_nbr=2640&amp;siId=605899&amp;catParentID=7875&amp;scId=7875&amp;oldParentID=7870"&gt;Sirius One&lt;/a&gt; (I think it was $20 from Circuit City), and it uses a built-in FM transmitter to send the signal to the radio wirelessly. However, in my truck (a 1996 Ford Ranger), I've always found it difficult to find an "unused" station that does not have some type of interference at some time of the day. The antenna is on the passenger side of the vehicle for one thing, and a preset that was clear in the morning always seems to become horrible at night (and vice-versa).&lt;br&gt;&lt;br&gt;Sirius offers a product to solve this problem: the &lt;a href="http://shop.sirius.com/edealinv/servlet/ExecMacro?nurl=control/StoreItem.vm&amp;ctl_nbr=2640&amp;siId=1998401&amp;catParentID=7872&amp;scId=7872&amp;oldParentID=7872"&gt;FM Direct Adapter&lt;/a&gt;. Essentially, you pull your radio out, unplug the antenna, plug the antenna into the adapter, then plug the adapter into the radio instead of the antenna. Then you plug the other end of the adapter into your Sirius unit. Done. When the Sirius One is on, the radio only receives what the Sirius One is sending via the adapter. When the Sirius One is off, the radio uses the external car antenna as usual. I picked one up on eBay for less than $20 shipped. Here are a few pics of how I installed it.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/184/405352178_14f291d2ba_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;In this picture, I've inserted the "DIN tools" into the front of the radio, applied some pressure on the tools toward the doors, and slipped the radio partially out. You can get DIN tools or whatever is required to remove the radio in your vehicle from eBay for under $5 shipped. That's what I did.&lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://farm1.static.flickr.com/134/405353038_2df41f1fd8_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;Here, the radio is completely out, and you can see the antenna input into the radio on the right side of the radio.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/171/405353374_603ae12e64_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;Now I've unplugged the antenna, plugged the adapter into the radio's antenna input, and plugged the antenna into the adapter. At this point, you can test that the adapter works by plugging the adapter cable into your Sirius radio, turning on your Sirius radio, and tuning the car radio to the correct preset. Make note of that support bar in the crevice that the radio slides into for reference in the next picture.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/182/405353694_0301237832_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;In order to run the adapter cable down to the floor (where I've run the cigarette adapter that powers the Sirius One unit, I found this nice hole just to the left of the support bar in the previous picture. The adapter cable headed to the Sirius One is just to the right of the two red wires. I pulled it down through the hole.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/147/405354395_6e49405973_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;Near the gas pedal underneath the dash, here comes the cable out of the other end of the hole. The adapter cable is the one that runs over the top of the coiled cable at the bottom of the picture (a CB handset cable).&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/150/405354692_f55ba4d12a_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;Now that everything is connected and working, I just need to mount the adapter and slide the radio back in. Luckily there is plenty of clearance on top of the radio since the factory radio's face is twice the size of the actual internal unit. I used a piece of the double-sided adhesive strip originally provided with the Sirius One to attach the antenna to the roof (since I never used it for its intended purpose) - the red strip in this picture.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://farm1.static.flickr.com/183/405355123_a99c1f19ea_m.jpg"&gt;&lt;/center&gt;&lt;br&gt;Now I'm ready to slide the radio back in and remove the DIN tools. Total installation time: 5 minutes. Total cost: $25 shipped to my door. No static: priceless.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2007/02/diy-sirius-fm-direct-adapter.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/4714377767271303983'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/4714377767271303983'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-115135356421866162</id><published>2006-06-26T15:04:00.000-04:00</published><updated>2006-11-13T00:09:21.601-05:00</updated><title type='text'>Diagnosing "Serious Errors" with Windows Memory Diagnostic</title><content type='html'>We use fast user switching in Windows XP at my house so I don't have to close all of my running apps just to let another family member check their email. One of the greatest annoyances which up until recently had been very rare was to sit down to click my username and not see any indication of how many programs I had running listed underneath it - a sure sign that the computer had rebooted on its own.&lt;br&gt;&lt;br&gt;Once you log on after an "unanticipated" reboot, XP tells you that the system has recovered from a "serious error" - i.e. a BSOD happened and Windows rebooted as configured. You can happily send the error report off to &lt;a href="http://oca.microsoft.com/en/welcome.aspx"&gt;Microsoft Windows Crash Analyis&lt;/a&gt; and they will give you some info on what might be wrong, but in some cases, the cause of these reboots might keep changing. In my case, I would awaken to find several reboots had happened, and the diagnosed causes would range from an IE plugin (I don't even use IE) to an error in an unknown driver. I took this as a sign that there was actually some kind of hardware problem - most likely a memory issue.&lt;br&gt;&lt;br&gt;I burned some self-booting memory testing ISO images to a few CD's (namely OCZ's &lt;a href="http://www.ocztechnology.com/displaypage.php?name=ocz_memtest"&gt;modified memtest86&lt;/a&gt; and Microsoft's &lt;a href="http://oca.microsoft.com/en/windiag.asp"&gt;Windows Memory Diagnostic&lt;/a&gt;). I started with WMD, running the extended tests, and saw hundreds of errors happen almost immediately on the first run of one of the tests. So now that I had found these memory errors, what was the next step? Microsoft suggests in their documentation that their tests will try to determine which memory bank caused the errors if possible, and that you should then flip your DIMM's around to see if you get the errors in the same bank. This would indicate a bad bank. If the errors move to the other bank, that would indicate a bad memory module. So where were my errors happenning? WMD was unable to determine that, so I was left on my own.&lt;br&gt;&lt;br&gt;Luckily, WMD does show you the hexidecimal memory addresses as the errors occur. Since I knew I had two 1GB modules installed, my adressable memory space was something like 2 * 1024(mb in a gb) * 1024(kb in a mb) * 1024(bytes in a kb) = 2147483648 decimal bytes or 0x80000000 hex bytes. Since I was using two DIMM modules, slot 0 would map to adressable memory up to 0x40000000 and anything above would be in slot 1. Armed with this information, I could tell that all of the errors being reported by WMD could be attributed to slot 1 (not sure why WMD itself could not make this determination).&lt;br&gt;&lt;br&gt;The next step was to flip the modules and see if the errors jumped to slot 0. I tried this and the errors stayed in slot 1. I then moved one of the modules to slot 2 (my mobo has three slots, slot 0 is DIMMA and slots 1 and 2 are designated as DIMMB1 and DIMMB2). Slots 1 and 2 were grouped together, apart from slot 0, so I was not surprised that slot 2 also showed many errors.&lt;br&gt;&lt;br&gt;Looks like it's time for a new motherboard. For the time being, I am left with two perfectly good 1GB memory modules but only one reliable DIMM slot. &lt;a href="http://www.newegg.com"&gt;Newegg&lt;/a&gt; only sells a handful of AMD Socket A mobos these days (the defective board in question is a Biostar M7NCD Pro) since Athlon XP processors are getting up there in age, but I found a cheap replacement in a used Albatron KX400-8X for $20 from a seller on &lt;a href="http://forums.anandtech.com/categories.aspx?catid=45"&gt;Anandtech's Sale/Trade Forum&lt;/a&gt; which should arrive later this week.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2006/06/diagnosing-serious-errors-with-windows.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/115135356421866162'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/115135356421866162'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-114081865723121277</id><published>2006-02-24T16:29:00.000-05:00</published><updated>2006-11-13T00:09:21.535-05:00</updated><title type='text'>SQL Replication and Renamed Imaged Servers</title><content type='html'>I've run into various issues when rolling out Microsoft SQL Server 2000 to multiple locations using disk imaging. The roll-out process usually involves creating a disk image with SQL Server already installed, applying that image on multiple server machines at a production center, then distributing and renaming each server once it gets to its final destination (no, I'm not involved with the licensing issues). There are multiple locations, each with one server with a handful of clients.&lt;br&gt;&lt;br&gt;The problems arise when we need to have SQL Server replication (a pushed one-way merge publication) deployed at each location. I now know the best strategy is to install replication via some scripts &lt;b&gt;after&lt;/b&gt; the server and clients are all renamed and deployed. However, I recently ran into a case where replication had been installed before the master image was created, then the image was deployed to a server, then the machine name of the server was changed. Here are the issues and how I dealt with them.&lt;br&gt;&lt;br&gt;Because all of the names of the machines had changed, I needed to uninstall and re-install the replication setup. The common strategy is to script out the current publication, drop and disable publishing, then reinstall replication using the generated scripts. However, when the machine name was changed and the machine was rebooted, the value of the server property "ServerName" was updated, but the value of @@servername was not changed. If you run the queries "select @@servername" and "select ServerProperty('ServerName')," you will see that they return different values. If you do a select from sysservers, you will also see that server id 0 still has the value of the previous machine name. To correct this, run sp_dropserver with the old machine name, then run sp_addserver with the new machine name (see &lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;818334"&gt;this MS article&lt;/a&gt; for more info).&lt;br&gt;&lt;br&gt;Before adjusting those values, I did a few other things. First, I right-clicked on my publication and scripted it out. Then I used Enterprise Manager to completely disable publishing at the server (Tools-&gt;Replication-&gt;Disable Publishing). You may have to register the new server name in EM if you had explicitly referred to the previous server name. When you then disable publishing, you will receive an error about MSX server jobs. This is due to the fact that sysjobs in the msdb database contains jobs that have an originating server value referencing the previous server name. At this point, I adjusted the server name using the dropserver/addserver steps above. Then I restarted the MSSQLSERVER service.&lt;br&gt;Now that the servername values were in sync, I deleted all rows in sysjobs, sysjobsteps, and sysjobschedules. Then I tried to disable publishing again. This time it completed with no errors.&lt;br&gt;&lt;br&gt;At this point, I had to clean up the subscriber machines who still thought they were being pushed a subscription from the old server name. I ran sp_removedbreplication on all of the subscribers. Next, I edited the replication scripts I had generated to make sure the correct publisher and subscriber names were in them. Finally, I was then able to execute the scripts to recreate the publication. No errors. YMMV.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2006/02/sql-replication-and-renamed-imaged.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/114081865723121277'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/114081865723121277'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113924243646316467</id><published>2006-02-06T10:52:00.000-05:00</published><updated>2006-11-13T00:09:21.466-05:00</updated><title type='text'>IE7: Flickr tag search in the Search bar</title><content type='html'>In the latest IE7 beta, it's simple to add a search provider to the new integrated Search bar using OpenSearch description documents and &lt;a href="http://opensearch.a9.com/"&gt;A9's OpenSearch&lt;/a&gt; specification. You just link an onClick event to window.external.AddSearchProvider('URL') where URL is the link to the OpenSearch description document (see &lt;a href="http://www.microsoft.com/windows/ie/searchguide/default_new.mspx#"&gt;this Microsoft page for more info&lt;/a&gt;). I think the spec and the IE implementation actually expect some kind of formatted XML back.&lt;br&gt;&lt;br&gt;As far as I know, Flickr doesn't support the OpenSearch spec, but I  but I put together a description document that just sticks your search term into the Flickr search results URL. You can add it to your IE7 search bar by &lt;a href="#" onClick="window.external.AddSearchProvider(&amp;quot;http://www.justinhenry.com/xml/flickr.xml&amp;quot;);"&gt;clicking here&lt;/a&gt;. It's a simple one-term search (if you put two terms in, Flickr just concats them). The XML for the OpenSearch description doc looks like this:&lt;br&gt;&lt;br&gt;&lt;pre class="csharpcode"&gt;&amp;lt;OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"&amp;gt;
  &amp;lt;ShortName&amp;gt;Flickr&amp;lt;/ShortName&amp;gt;
  &amp;lt;Description&amp;gt;Search for pictures on Flickr&amp;lt;/Description&amp;gt;
  &amp;lt;Url type="text/html"
  template="http://www.flickr.com/photos/search/tags:{searchTerms}/tagmode:all/"/&amp;gt;
&amp;lt;/OpenSearchDescription&amp;gt;&lt;/pre&gt;</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2006/02/ie7-flickr-tag-search-in-search-bar.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113924243646316467'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113924243646316467'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113690824304761314</id><published>2006-01-10T10:49:00.000-05:00</published><updated>2006-11-13T00:09:21.383-05:00</updated><title type='text'>Embedding a Google Map</title><content type='html'>Took a shot at the quick tutorial on how to &lt;a href="http://blog.explorationage.com/articles/2006/01/08/how-to-add-a-google-map-to-any-web-page-in-less-than-10-minutes"&gt;embed a Google map into a web page in 10 minutes&lt;/a&gt; by Joshua Siler. Simple enough that it can be done just using the sample code provided by Google when you get your map key (though Joshua does provide a tweak and a couple of additional tips). Don't know why I never bothered to check out the API. Perhaps I just never needed an embedded map. Certainly the one I've provided below is completely pointless.&lt;br&gt;&lt;br&gt;&lt;div id="map1" style="width: 500px; height: 400px"&gt;&lt;/div&gt;</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2006/01/embedding-google-map.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113690824304761314'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113690824304761314'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113617464197029026</id><published>2006-01-01T22:38:00.000-05:00</published><updated>2006-11-13T00:09:21.316-05:00</updated><title type='text'>New Application/User Settings Interface in VS2005</title><content type='html'>While thinking about how to keep track of various configurable application settings in the X10 application, I came across &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/10/AdvancedBasics/default.aspx"&gt;an article in MSDN Magazine&lt;/a&gt; from October about a match-making game. The author referenced a previous article where he talked about user and application settings and how to store and retrieve them. Following his links, I came across an article from Emad Ibrahim that explained &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/vbmysettings.asp"&gt;the easiest way to keep track of settings in Visual Studio 2005&lt;/a&gt; - it's built in!&lt;br&gt;&lt;br&gt;First, here's my current list of simple properties:&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://static.flickr.com/39/80635100_c1ca6c4eba_o.jpg"&gt;&lt;/center&gt;&lt;br&gt;So in the project properties, I have defined these settings under the appropriately-named Settings tab:&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://static.flickr.com/37/80635143_2e7e50a001.jpg"&gt;&lt;/center&gt;&lt;br&gt;As you can see, you just specify the name of the property, the type, whether it's user- or application-level, and the default value. Simple. Then, you can even tie controls on the form to specific settings! Under the properties for a control, such as a checkbox, you see this:&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://static.flickr.com/36/80634041_80d13ebdb3_o.jpg"&gt;&lt;/center&gt;&lt;br&gt;You just click on the box next to Property Binding to bring up a box allowing you to bind control properties to application settings:&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://static.flickr.com/37/80634968_46624b5833_o.jpg"&gt;&lt;/center&gt;&lt;br&gt;I want to bind the checked property of this checkbox control to an application setting. Clicking the dropdown on the checked property shows the various application settings I've defined:&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;img src="http://static.flickr.com/40/80635026_9ca793cf35_o.jpg"&gt;&lt;/center&gt;&lt;br&gt;The checked property is automatically set during startup based on the application setting, and the settings file is automatically updated when the checked property is changed by the user. It's like magic.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2006/01/new-applicationuser-settings-interface.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113617464197029026'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113617464197029026'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113468623830004948</id><published>2005-12-15T17:23:00.000-05:00</published><updated>2006-11-13T00:09:21.250-05:00</updated><title type='text'>Using HttpListener Asynchronously</title><content type='html'>My previous entry about creating a mini-web server application to take X10 device requests used HttpListener to wait for and respond to HTTP requests synchronously. However, as I develop a user interface for my X10Listener service, I'll need to be able to respond to those requests in the background while the user configures other areas of the service. So I've switched to an asynchronous use of HttpListener. First, in my load subroutine, I start the listener as before, but use BeginGetContext instead of GetContext.&lt;br&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; listener &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; System.Net.HttpListener

listener.Prefixes.Add(&lt;span class="str"&gt;"http://*:33333/"&lt;/span&gt;)

&lt;span class="kwrd"&gt;Try&lt;/span&gt;
    listener.Start()
&lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
    MsgBox(ex.Message)
    &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;

listener.BeginGetContext(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.AsyncCallback(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; &lt;span class="kwrd"&gt;Me&lt;/span&gt;.ProcessRequest), _&lt;br&gt;listener)
&lt;/pre&gt;Now I can go on and set up the UI and handle UI events. Note that I pass a reference to the address of another routine called ProcessRequest along with a reference to the listener object. Here is the routine to process the request, which is automatically called when an HTTP request comes in.&lt;br&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ProcessRequest(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; System.IAsyncResult)

    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; listener &lt;span class="kwrd"&gt;As&lt;/span&gt; Net.HttpListener
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; context &lt;span class="kwrd"&gt;As&lt;/span&gt; Net.HttpListenerContext

    listener = result.AsyncState
    context = listener.EndGetContext(result)

    &lt;span class="rem"&gt;' use context.Request to explore the incoming HTTP request&lt;/span&gt;

    listener.BeginGetContext(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.AsyncCallback(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; _&lt;br&gt;    &lt;span class="kwrd"&gt;Me&lt;/span&gt;.ProcessRequest), listener)

&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;Note that I never have to instantiate a new HttpListener except during the initial load. I can pass the single listener object around via the asynchronous handler. At the end of the ProcessRequest routine, I simply set up to handle the next incoming request by calling BeginGetContext again. Next, I'll be building the UI and sending a more complex response that will include a configurable, simple HTML menu of X10 commands.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2005/12/using-httplistener-asynchronously.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113468623830004948'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113468623830004948'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113384774010004727</id><published>2005-12-06T00:18:00.000-05:00</published><updated>2006-11-13T00:09:21.180-05:00</updated><title type='text'>Using HttpListener For X10 Web Interface</title><content type='html'>When I created my &lt;a href="http://justinhenry.com/2005/11/vbnet-cm17a-x10-library-from-scratch.html"&gt;VB.NET library for the X10 CM17A&lt;/a&gt;, I really didn't know what I was going to use it for. It was a learning exercise. I intended my next step to be creating an ASP.NET app that I could access from the network to send X10 commands "remotely" from another machine on the wireless connection in the house. When I started that, I quickly realized that the latest version of IIS that supported the ASP.NET 2.0 applications I would be creating in VS 2005 was not available for Windows XP. Not interested in upgrading to a new operating system, I put the idea aside, noting that I could still do it some day by implementing some kind of client/server messasing protocol in a couple of separate applications.&lt;br&gt;&lt;br&gt;Well today I stumbled upon the new HttpListener class while browsing through an article on streams in the latest issue of MSDN. HttpListener seemed to be just what I needed - a way to listen to and respond to HTTP requests easily. I could run a small app (kind of a mini webserver) that would listen for incoming requests on a certain port, decode the query string from the URL, and instantiate and manipulate a CM17A device via my existing module.&lt;br&gt;&lt;br&gt;Keep in mind that this implementation is synchronous, but the HttpListener does allow for asynchronous operation using BeginGetContext. First, create your listener and point him at the right port.&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; listener &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; System.Net.HttpListener
listener.Prefixes.Add(&lt;span class="str"&gt;"http://*:33333/"&lt;/span&gt;)
listener.Start()&lt;/pre&gt;Then, sit in a loop waiting for incoming requests. Once I receive a request in the proper format, I split up the string to get the house, device, and commands. Then I simply send these to the CM17A Firecracker unit using my class. Note there is not much error checking at all. I'm assuming the incoming URL has all three parameters, etc.
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Do&lt;/span&gt;
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; context &lt;span class="kwrd"&gt;As&lt;/span&gt; Net.HttpListenerContext = listener.GetContext
    &lt;span class="kwrd"&gt;If&lt;/span&gt; context.Request.Url.LocalPath = &lt;span class="str"&gt;"/X10"&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; paramslist &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = context.Request.Url.Query.Split(&lt;span class="str"&gt;"?"&lt;/span&gt;)(1)
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; params() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = paramslist.Split(&lt;span class="str"&gt;"&amp;amp;"&lt;/span&gt;)

        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; msg &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = DateTime.Now.ToString() &amp;amp; &lt;span class="str"&gt;": "&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; nDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; strHouse &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="str"&gt;""&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; strCommand &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="str"&gt;""&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; strVal &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;

        &lt;span class="kwrd"&gt;For&lt;/span&gt; &lt;span class="kwrd"&gt;Each&lt;/span&gt; stringpair &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; &lt;span class="kwrd"&gt;In&lt;/span&gt; params
            strVal = stringpair.Split(&lt;span class="str"&gt;"="&lt;/span&gt;)(1)
            &lt;span class="kwrd"&gt;Select&lt;/span&gt; &lt;span class="kwrd"&gt;Case&lt;/span&gt; stringpair.Split(&lt;span class="str"&gt;"="&lt;/span&gt;)(0).ToUpper
                &lt;span class="kwrd"&gt;Case&lt;/span&gt; &lt;span class="str"&gt;"DEVICE"&lt;/span&gt;
                    nDevice = strVal.ToUpper
                &lt;span class="kwrd"&gt;Case&lt;/span&gt; &lt;span class="str"&gt;"HOUSE"&lt;/span&gt;
                    strHouse = strVal
                &lt;span class="kwrd"&gt;Case&lt;/span&gt; &lt;span class="str"&gt;"COMMAND"&lt;/span&gt;
                    strCommand = strVal.ToUpper
                &lt;span class="kwrd"&gt;Case&lt;/span&gt; &lt;span class="kwrd"&gt;Else&lt;/span&gt;
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Select&lt;/span&gt;
        &lt;span class="kwrd"&gt;Next&lt;/span&gt;

        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; FC &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; X10.CM17A(1)
        &lt;span class="kwrd"&gt;If&lt;/span&gt; FC.SendCommand(strHouse, nDevice, strCommand) &lt;span class="kwrd"&gt;Then&lt;/span&gt;
            msg += &lt;span class="str"&gt;"Command sent."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Else&lt;/span&gt;
            msg += &lt;span class="str"&gt;"Error sending command."&lt;/span&gt;
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; b() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt; = System.Text.Encoding.ASCII.GetBytes(msg)
        context.Response.OutputStream.Write(b, 0, b.Length)
        context.Response.Close()
   &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
&lt;span class="kwrd"&gt;Loop&lt;/span&gt; &lt;span class="kwrd"&gt;While&lt;/span&gt; True&lt;/pre&gt;Now, sending an OFF command to device 1 in house A is as simple as opening up a web browser and pointing it to "http://192.168.1.2:33333/X10?device=1&amp;house=A&amp;command=off" (or whatever IP address your listener is running on). You get back a simple success or failure message. It's amazing to use a little Windows Mobile 5.0 device to control X10 devices all over the house just by browsing an internal web "server." It would be simple to extend this idea by building a little client app that sends these HTTP requests based on button clicks.&lt;br&gt;&lt;br&gt;In fact, you could just write up a little HTML page that had links to URL's that would turn your various devices on or off. This HTML could live on the listener and be returned as the response to /X10?init or something similar. There are lots of UI possibilities here.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2005/12/using-httplistener-for-x10-web.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113384774010004727'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113384774010004727'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113354351109308362</id><published>2005-12-02T12:09:00.000-05:00</published><updated>2006-11-13T00:09:21.119-05:00</updated><title type='text'>Might We Suggest the Enemy?</title><content type='html'>&lt;a href="http://www.flickr.com/photos/benton/69059078/"&gt;&lt;img src="http://static.flickr.com/6/69059078_42a9b989a3_m.jpg" class="alignleft"&gt;&lt;/a&gt;There was a deal posted over at &lt;a href="http://www.slickdeals.net"&gt;SlickDeals.net&lt;/a&gt; for a collegiate hoodie + t-shirt combo for about $20, so I clicked-through to check it out. There were lots of schools available, but I found the "might we also suggest" items to be questionable. The example to the left (click for larger version) shows a suggestion of UNC slippers for someone purchasing an NC State hoodie. For those of you living outside of North Carolina that might only know about the UNC-Duke rivalry, all three of these schools hate each other. Suggesting UNC gear to a Wolfpack fan is about the most offensive suggestion you could possibly offer.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2005/12/might-we-suggest-enemy.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113354351109308362'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113354351109308362'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113289157801532817</id><published>2005-11-24T23:00:00.000-05:00</published><updated>2006-11-13T00:09:21.055-05:00</updated><title type='text'>Rebooting the Cable Modem Programmatically Using X10</title><content type='html'>I mentioned that I used my .NET X10 library to reboot my cable modem every week or so when it appears to have locked up, and now here's the simple code. I created a new VB.NET app, put this code in the Load method of a basic form with a single label object, and created a shortcut to it on the desktop for all users. Now everyone can reboot the cable modem directly from the workstation without going down to the interface room or knowing how to pull the correct plug. Plus, this code knows how long to wait before the connection should be back up, and even does a simple web request to test the connection after the reboot.&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; FC &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; X10.CM17A(1)

        Label1.Text = &lt;span class="str"&gt;"Sending Off Command ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Show()
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()

        FC.SendCommand(X10.CM17A.HouseA, 1, X10.CM17A.CommandOff)
        Label1.Text = &lt;span class="str"&gt;"Sent Off Command, Waiting 3 Seconds ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()
        System.Threading.Thread.Sleep(3000)
        Label1.Text = &lt;span class="str"&gt;"Sending On Command ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()
        FC.SendCommand(X10.CM17A.HouseA, 1, X10.CM17A.CommandOn)
        Label1.Text = &lt;span class="str"&gt;"Sent On Command, Waiting 30 Seconds ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()
        System.Threading.Thread.Sleep(30000)
        Label1.Text = &lt;span class="str"&gt;"Testing Connection ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()

        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; objHTTP &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; System.Net.WebClient
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; objIn &lt;span class="kwrd"&gt;As&lt;/span&gt; IO.Stream

        &lt;span class="kwrd"&gt;Try&lt;/span&gt;
            objIn = objHTTP.OpenRead(&lt;span class="str"&gt;"http://www.microsoft.com"&lt;/span&gt;)
            Label1.Text = &lt;span class="str"&gt;"Success! Exiting ..."&lt;/span&gt;
        &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
            MsgBox(&lt;span class="str"&gt;"Error Testing Connection! Click OK and Try Again."&lt;/span&gt;)
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;

        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Refresh()
        System.Threading.Thread.Sleep(3000)
        &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Close()
&lt;/pre&gt;</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2005/11/rebooting-cable-modem-programmatically.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113289157801532817'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113289157801532817'></link><author><name>Justin</name></author></entry><entry><id>tag:blogger.com,1999:blog-18785914.post-113225877705476403</id><published>2005-11-17T12:06:00.000-05:00</published><updated>2006-11-13T00:09:20.987-05:00</updated><title type='text'>VB.NET CM17A X10 Library From Scratch</title><content type='html'>Sometime back in early August, &lt;a href="http://msdn.microsoft.com/coding4fun"&gt;Coding4Fun&lt;/a&gt; started a series on using X10 home automation technology in your home with &lt;a href="http://www.northrup.org/"&gt;Tony Northrup&lt;/a&gt; as the host. Up to that point, my only experience with X10 involved purchasing a &lt;a href="http://www.x10.com/automation/firecracker.htm"&gt;firecracker starter kit&lt;/a&gt; when it was free a number of years back. I hooked up a lamp to it, poked around with the provided software, and was generally uninspired given that I was living in an apartment. The kit then gathered dust in a box for years.&lt;br&gt;&lt;br&gt;Discovering the Coding4Fun series was well-timed for me. I was preparing to brush off some programming dust and head to the &lt;a href="http://www.microsoftpdc.com/"&gt;2005 Microsoft PDC&lt;/a&gt;. The convention would be a nice break from the hectic pace of kids and work that had brought on a temporary coding stagnation. Anyway, the &lt;a href="http://msdn.microsoft.com/coding4fun/diy/usingx10/default.aspx"&gt;first entry in the series&lt;/a&gt; really had nothing to do with coding and was an intro to how you could fix a few lighthing problems in your home using X10 equipment. The tediously slow flow of the highly-detailed video and a couple of jabs at the alternative of attempting some home wiring yourself (something any good home hacker would consider) left me uninterested. I went to the PDC and had a great time.&lt;br&gt;&lt;br&gt;Then, after returning from a trip to Toronto, the &lt;a href="http://msdn.microsoft.com/coding4fun/diy/controlLights/default.aspx"&gt;second article&lt;/a&gt; in the X10 series was posted. Tony controlled some lights with X10 based on the value of a stock returned by a web service. While this fairly simple idea didn't really excite me, I realized that I had most of the parts in my ancient starter kit to attempt something similar.&lt;br&gt;&lt;br&gt;So I decided that I would just try to turn a light on and off using a simple UI - as a start. I installed the copy of Visual Studio 2005 Release Candidate that I received at the PDC and got to work. In Tony's project, he used a CM11A module, which is a two-way module as opposed to the send-only CM17A ("firecracker") module that was in my kit. For purposes of my project (and even Tony's first project), only one-way communication would be required, so I planned to use the same freely available serial port library that Tony used and just find an equivalent CM17A library.&lt;br&gt;&lt;br&gt;Fortunately, I just failed to find anything useful that wasn't written in Java and I just didn't pull things together.&lt;br&gt;&lt;br&gt;I say "fortunately" because I then decided to write my own CM17A library and try to use the new serial port communication support in the 2.0 version of the .NET framework. Armed with the &lt;a href="ftp://ftp.x10.com/pub/manuals/cm17a_protocol.txt"&gt;CM17A protocol specification&lt;/a&gt; from X10, I started from scratch.&lt;br&gt;&lt;br&gt;First, accessing the serial port:&lt;br&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; CP &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; System.IO.Ports.SerialPort

&lt;span class="rem"&gt;'set variables: port, 9600, N, 8, 1, timeout&lt;/span&gt;
CP.PortName = &lt;span class="str"&gt;"COM"&lt;/span&gt; + nPort.ToString
CP.BaudRate = 9600
CP.DataBits = 8
CP.StopBits = IO.Ports.StopBits.One
CP.Parity = IO.Ports.Parity.None
CP.WriteTimeout = 1000&lt;/pre&gt;
Next, sending a string of 1's and 0's representing an X10 command to the serial port:&lt;br&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
CP.Open()
CP.DiscardInBuffer()
CP.DiscardOutBuffer()

&lt;span class="kwrd"&gt;If&lt;/span&gt; CP.IsOpen &lt;span class="kwrd"&gt;Then&lt;/span&gt;

     &lt;span class="kwrd"&gt;Dim&lt;/span&gt; nDelay &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 30 &lt;span class="rem"&gt;'milliseconds&lt;/span&gt;
     &lt;span class="kwrd"&gt;Dim&lt;/span&gt; nBit &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 0

     &lt;span class="rem"&gt;'send reset/no power&lt;/span&gt;
     CP.DtrEnable = &lt;span class="kwrd"&gt;False&lt;/span&gt;
     CP.RtsEnable = &lt;span class="kwrd"&gt;False&lt;/span&gt;

     System.Threading.Thread.Sleep(nDelay)

     &lt;span class="rem"&gt;'send power&lt;/span&gt;
     CP.DtrEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;
     CP.RtsEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;

     System.Threading.Thread.Sleep(nDelay)

     &lt;span class="kwrd"&gt;For&lt;/span&gt; nBit = 0 &lt;span class="kwrd"&gt;To&lt;/span&gt; strCmd.Length - 1

         &lt;span class="rem"&gt;'either dtr or rts must be true at any&lt;/span&gt;
         &lt;span class="rem"&gt;'given time to maintain power to unit,&lt;/span&gt;
         &lt;span class="rem"&gt;'thus true is always set before false&lt;/span&gt;

         &lt;span class="kwrd"&gt;If&lt;/span&gt; Convert.ToInt32(strCmd.Substring(nBit, 1)) = 0 &lt;span class="kwrd"&gt;Then&lt;/span&gt;
             &lt;span class="rem"&gt;'send 0&lt;/span&gt;
             CP.DtrEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;
             CP.RtsEnable = &lt;span class="kwrd"&gt;False&lt;/span&gt;
         &lt;span class="kwrd"&gt;Else&lt;/span&gt;
             &lt;span class="rem"&gt;'send 1&lt;/span&gt;
             CP.RtsEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;
             CP.DtrEnable = &lt;span class="kwrd"&gt;False&lt;/span&gt;
         &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

         System.Threading.Thread.Sleep(nDelay)

         &lt;span class="rem"&gt;'reset for next bit&lt;/span&gt;
         CP.RtsEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;
         CP.DtrEnable = &lt;span class="kwrd"&gt;True&lt;/span&gt;

         System.Threading.Thread.Sleep(nDelay)

     &lt;span class="kwrd"&gt;Next&lt;/span&gt;

&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

&lt;span class="kwrd"&gt;If&lt;/span&gt; CP.IsOpen &lt;span class="kwrd"&gt;Then&lt;/span&gt; CP.Close()&lt;/pre&gt;I've provided the &lt;a href="http://www.justinhenry.com/code/CM17A.vb"&gt;complete VB.NET source for the library&lt;/a&gt;. Remember that this code uses the 2.0 version of the .NET framework. To send an ON command to House A, Device 1 using a CM17A attached to COM1, use the following code:&lt;br&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; FC &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; X10.CM17A(1)

&lt;span class="kwrd"&gt;If&lt;/span&gt; &lt;span class="kwrd"&gt;Not&lt;/span&gt; FC.SendCommand(X10.CM17A.HouseA, 1, X10.CM17A.CommandOn) &lt;span class="kwrd"&gt;Then&lt;/span&gt;
      MsgBox(&lt;span class="str"&gt;"Error: "&lt;/span&gt; + FC.LastError.Description, MsgBoxStyle.Exclamation)
&lt;span class="kwrd"&gt;End If&lt;/span&gt;&lt;/pre&gt;It's obviously simple to wrap a UI around this. I wrote a small app that lets me cycle my cable modem off and back on from the bonus room without having to run down to its actual physical location (it locks up every now and then). Thanks to Adam Davis for &lt;a href="http://www.ubasics.com/adam/electronics/cm17.shtml"&gt;breaking down the CM17A specification&lt;/a&gt; bit by bit.</content><link rel='alternate' type='text/html' href='http://www.justinhenry.com/2005/11/vbnet-cm17a-x10-library-from-scratch.html'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113225877705476403'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18785914/posts/default/113225877705476403'></link><author><name>Justin</name></author></entry></feed>