Saturday, January 16, 2010

Linux on the Real User's Desktop: TV Tuners

Continuing with the experiment to run Linux as much as possible at home, I ran into something that I had completely overlooked when thinking about the "media center" applications: the actual TV tuner! Having a home theater PC isn't quite as much use without a tuner.

I've discovered that setting up the tuner is one of the most frustrating aspects of the entire system configuration. The whole process is beyond arcane, and it reminds me of similar issues I went through with things like wi-fi about 5 years ago. (That, by the way, was the reason I ditched Linux back then.)

I understand that for the majority of users, TV capture is not part of everyday life. I'm on the other end of that spectrum. The kids and I have a couple shows each that we all like to watch, and they're not on when we're home, so no DVR = a very unhappy home.

I've been struggling with my USB stick tuner for much of the morning. All indications are that this is a Pinnacle PCTV 800e. (We know how difficult it can be to determine the true name of any piece of hardware at times.) Anyway, my experience over the past year is that this is a really reliable little gadget under Windows.

Under Linux? I didn't know where to begin. I read. I downloaded. I compiled. I did a zillion things, only to find out that driver support for the device is already set up in Karmic (that's Ubuntu 9.10). Yeah, that part works, and I checked it with lsusb to confirm that it's there.

So the next step is to scan for channels. I tried scan and w_scan, and neither were able to get the tuner to successfully scan for channels. I also tried loading a ton of the sample channel configs, with the same level of success.

It occurs to me that, after reading a lot of forums, these USB tuners may not be the best suited for the kind of setup I'm aiming for. Under normal circumstances, I would do the legwork of getting this thing working, but I don't have the time I'd normally like to devote to this task. Also, the point of this experiment is to make Linux an easy experience that the average user can partake in. So... I'm abandoning the USB tuner unless someone can come up with an easy way to get this thing working.

I've been looking for a new one anyway, but I'm also locked out of the PCI-Express tuners (which are VERY common) because my HTPC is too antiquated to have a PCI-E slot. So my next step is to hunt down a suitable, dual-tuner PCI Hauppauge card (which from what I've seen, is the best supported of the kind) and try again.

Stay tuned.

As an aside, I found that the Windows 7 Media Center records in a new file format called .wtv which isn't recognized by XBMC (or many other UPnP clients). However, there's a nifty utility in the C:\Windows\ehome folder called WTVConverter.exe that will convert those files back to the old .dvr-ms files that everything plays nice with.

This is good news for my son, as he can once again watch all the shows from the DVR up in his bedroom.

Thursday, January 7, 2010

Terminal Clients and Retro Fun

I won’t go into the story of why I wanted this except to say that computers existed before the proliferation of the Internet, and sometimes it’s fun to go back in time.  In this case, I’ve been using a large number of terminal (telnet) client packages: PuTTY, the generic telnet built into Windows, the telnet clients that come with GNOME and KDE, and so forth.

One issue I discovered is that none of them are set up to display ASCII line drawing characters, so any ANSI art comes out as a complete cluster**** of umlauts and twirliecues.

The magic answer: Code Page 437

Yes, that’s the answer.  The problem is, most clients don’t support it anymore because it’s not even close to Unicode compliant.

So, the workaround?  Set your terminal’s code page translation to one of the following:

860 (Portugese)
861 (Icelandic)
862 (Hebrew)
865 (Nordic)

I’ve been using CP 862 in all my Linux clients without issue.

In PuTTY, however, you can go to the code translation section of the window menu and type “CP437” into the code page translation box, and you get exactly what you need.

This seems to be a common problem for us old-timers, and the answers aren’t really easy to find.  (I spent well over an hour on this stupid thing just so I could getting a spinning ASCII prompt.)  Hopefully this saves someone else a headache or two.

Tuesday, January 5, 2010

Barcodes! Ack!

One would think that after all the time I spend in the office dealing with the myriad barcode issues that seem to inevitably crop up, I would be so sick of seeing black and white stripes that my head would pop at the thought of even being in the same vicinity.
Alas, I've found a use for them -- of all places -- in the home.  There is no escape.
After digging into a recent project a little deeper, I've discovered that this is by no means an original idea, but my implementation is independent of anyone else's efforts, so I'll share a little bit of that here.

What I'm attempting to do is run my home in a similar fashion as do many of today's manufacturing facilities: lean. (If you're not familiar with the philosophy, Wikipedia covers lean manufacturing quite well.) This project meshes well with one of my aims toward a more minimalist lifestyle, thus the work.

The idea is to inventory all food items in the house, and keep them stocked at optimum levels with a minimum amount of effort. I know, some people can whip up a grocery list in their head and just be done with it. I'm not one of those people.

My grocery shopping is done at odd times (and usually not even on the same day of the week), so I find it difficult to establish how many of a certain thing I need. When I discover I have the extra time to squeeze in a trip to the store, the last thing I want to do is squander that time running home to take an inventory of what I have. The result is that I'm constantly overstocked on one thing, and completely out of something else. Not very lean.

So my goal is to set up a grocery store scanner in my house. More literally, right next to the garbage can. Every time I use something up, I scan the barcode as I throw the empty wrapper or container away. When I scan the barcode, an attached computer looks up the product in a database, then adds that item to a list of things I need to buy the next time I run to the store.  When I’m there, I can have this little doodad e-mail my list to me, which I can retrieve from my phone, and I’m ready to shop.

There are certain concerns I have about initial implementation. Do I scan in my entire inventory, adjust my optimum levels, and let the list fit my ideal inventory from that point forward? Or do I watch for patterns in my consumption and let the software generate my list for me based on recent trends?

All that aside, I ran into my first obstacle this morning while testing out part of my system. There are three major barcode schemes used on U.S. packaging: UPC-A (12 digits), UPC-E (a 6-8 character compressed form of UPC-A), and EAN (a 13-character "global" scheme, which also includes country of origin). EAN is also referenced as UCC-13.  The database I'm using to look all these products up only indexes by EAN. Unfortunately, the two versions of UPC are quite prevalent, and of those, many of the smaller items I buy use UPC-E. What now?

Turns out, there is a rather clunky way to convert UPC-E to UPC-A. From there, and according to what I've been able to determine, converting from UPC-A to EAN is as simple as prefixing the string with a U.S. country code (a zero). But getting from UPC-E to UPC-A was the tough part.
I found a couple functions while sifting around online, but they were mainly written in Javascript, and were at least partially broken or not very well factored down. I needed PHP, and I wanted it clean. This function is what I pieced together, using a fairly solid foundation written in Javascript by Rob Williams on the TAL Technologies website as a jumping off point.

function convert_UPCE_to_UPCA($upce) {
 
    // Make sure its actually a numeric code -- nothing else is valid
 
    if(!is_numeric($upce)) {
        // Not a valid UPC-E code: exit
        return($upce);
    } else {
        switch (strlen($upce)) {
            case 6:
                // Perfect... Leave as-is
                break;
            case 7:
            case 8:
                // Trim leading digit (and trailing checksum, if present)
                $upce = substr($upce, 1, 6);
                break;
            default:
                // Any other length is not a valid UPC-E code: exit
                return($upce);
        }
  
        switch ($upce[5]) {
            // The sixth character (element 5 in the string) tells us how to decompress
            case "0":
            case "1":
            case "2":
                $mfr_number = $upce[0].$upce[1].$upce[5]."00";
                $item_number = "00".$upce[2].$upce[3].$upce[4];
                break;
            case "3":
                $mfr_number = $upce[0].$upce[1].$upce[2]."00";
                $item_number = "000".$upce[3].$upce[4];
                break;
            case "4":
                $mfr_number = $upce[0].$upce[1].$upce[2].$upce[3]."0";
                $item_number = "0000".$upce[4];
                break;
            default:
                $mfr_number = $upce[0].$upce[1].$upce[2].$upce[3].$upce[4];
                $item_number = "00000".$upce[5];
                break;
        }
  
        // Prefix the new UPC-A code with a "0" to denote format, then
        // add the remainder of the manufacturer and item codes
        $msg = "0".$mfr_number.$item_number;
  
        // Append the checksum digit -- should always equal the UPC-E checksum
        $msg .= calc_check_digit($msg);
  
        // Return the final result
        return($msg);
    }
}


You'll notice at the end that there's a reference to a function calc_check_digit() that I didn't include above. I discovered that the checksum digit in UPC-A should always be the same as the one provided in a UPC-E barcode. The cheap way to do that is to simply copy it if you have it, but since we sometimes don't (and even if it's provided, we lopped it off at the beginning of the function anyway), here's one solution:

// Calculates the checksum digit
// UPCA checksum digit should always be the same as the UPCE digit

function calc_check_digit($msg) {
    
 // Initialize the checksum
    $check = 0;
 
    // Loop through the message
    for($x = 1; $x <= 11; $x++) {
        // Even position digits multiplied by 9, odd by 7
        $check = $check + (intval(substr($msg, ($x - 1), 1)) * (9 - (2 * ($x % 2))));
    }
 
    // Checksum is the modulus of 10
    return($check % 10);
}


So, we've re-created the checksum. (The "$x % 2" above just returns a boolean value that tells us whether $x is odd or even, so we multiply 2 by either a 1 or 0 and subtract the resulting product from 9.  It looks a little funny, but it’s compact, and I love compact.)

We can feed our final EAN into the database lookup, and voila!, out pops our item, complete with description, size per container, &c.  If I really want to go crazy, I can assign cost-per-item in the database as well, so that when the system e-mails me my grocery list, I’ll know exactly how much I’ll be spending before I even set foot into the store.  Man, would that be slick!

If anyone is interested in more of the project details, leave me a comment, and I’ll post a bit more.  There’s a lot more currently rolling on this than just barcodes!