Sunday, October 24, 2010

Past, meet future


I had a difficult time trying to decide where to put this post, but as it has more to do with technology than my usual "reflection" or political bias rants, I opted for here.

A couple days ago, I had a phone conversation with my son. It's such a simple thing to say, and for millions of people, such a mundane concept. But when I hung up, I marveled at the whole process.

I just upgraded phones, so my  Google Nexus One has been sitting idle for the past week, and my son, rather than see it collect dust, decided it could be better put to use playing Angry Birds and tower defense games. It's hard to argue with that logic, knowing it's going to be another week or two before I find the time to back up the SD card, reset to factory defaults, and list it on ebay. Besides, I knew I had a couple more long nights at the office in my future, so I figured it would help keep him occupied during his time at grandma and grandpa's.

Then it hit me. He's been asking for a phone of his own, but I'm not about to give him a phone -- especially with the cost of service on an additional line and a data plan -- just so that we can talk once per week and send little text messages when he feels too lazy to come out of his bedroom. Yet, there's this very capable phone with wi-fi...

Skype.

Lucky for me, my parents are just far enough inside the tech jungle to have a wireless router and broadband internet service. So I installed Skype on both our phones, created an account for him, signed us both in, and... Viola! Test call complete.

The messaging function of Skype works while I'm on 3G, so we can text chat when I'm out of the office, and when wi-fi is available I can just call him and his phone rings. We can just talk. On cell phones. Over the internet. Without using minutes. Without a data plan. For free. And the quality was no different than an ordinary cell call.

These are amazing times we live in, and I've only just scratched the surface of the capability here. Even a friend of mine commented on it: he knows how to use Skype? Even I don't have a Skype account. Thought I'd share.

What about you? What interesting ways do you find yourself using your mobile devices?

Friday, July 16, 2010

Subsidized Fees Without the Subsidized Product

I realize that this is a deviation from the tech norm, but it's a rant that I've been wanting to vent for quite some time, and is loosely connected with technology, so here goes:

Those who know my "love" for cellular carriers understand that I abhor being tied to a carrier for the duration of a two-year contract.  I'll admit that I am often with a carrier for far longer, but I don't like being under contract for that length of time.  If I get furious with a carrier's service, or if a must-have gadget comes along on another carrier, I want the ability to switch without paying early termination fees.

To this end, I usually purchase my phones outright.  Yes, it's expensive, but it guarantees that I'm not locked in to a contract.  The carrier recovers the full cost of the device over time by charging a higher rate for service.  The problem?  There's no LOWER rate for subscribers who haven't purchased a subsidized device.

A user who is only paying $200 for a $600 device should expect their monthly service fee to be higher to cover that cost over the life of the two-year contract.  Likewise, a user who has paid the full retail price of the device up front should expect to NOT pay the same monthly fees as the one under contract.

There are consumer protection laws in place to stop things like this from happening, yet I haven't heard of anyone employing them, and that is long overdue.  People are being double-charged for a product, and in some cases, being charged for a product that was not even purchased from the cellular service provider in the first place.  (The case of the Google Nexus One is a prime example, as is any case of a person activating a device purchased used from a third party.)

To be fair, T-Mobile is the only carrier I'm aware of that has different pricing plans for contract vs. non-contract pricing, and the non-contract pricing (using your own device) is in fact $10-40/month lower than the pricing plans for those who purchase subsidized devices.

AT&T?  Verizon?  Are you listening?  If not, make sure your attorney retainer fees are paid...

Monday, June 7, 2010

How many ways can I say it?

My son, nearing the ripe old age of seven, has been a sponge for all things scientific these past months, so I've been feeding his appetite in any way that he can absorb.  He's chomping at the bit to put his recently acquired knowledge (and his new multimeter) to practical use.  Over the weekend, we were discussing plans for some summer projects, one of which involves developing a small amount of code to drive an Arduino board.  (The Arduino, a small and very affordable I/O board, is the heart and soul of a lot of planned tinkering sessions.)  He had expressed his desire to learn enough of what I do to be helpful in the software development part of these projects, so we sat down and reviewed some of the more rudimentary aspects of code.

I teach by abstract functionality, not by the nuances of a given language, so in this instance, I used Javascript due to the ability to show him things in a rapid environment without the need to worry about compilers and what not.

In this case, we were drawing a box on the screen and populating it with text.  Your typical "Hello, world!" sample, but with the expansion of a for loop, displaying the text in enumerated fashion.  The next phase of the sample code was to replace the text in our box, not simply append to it (as would be useful in something like a status box).

My usual code for this would be browser independent, which requires checking for the availability of the innerText method, and using innerHTML if it didn't exist, as in:
if (document.getElementById('my_element').innerText === 'undefined') {
    document.getElementById('my_element').innerHTML = txt;
} else {
    document.getElementById('my_element').innerText = txt;
}

I've always despised coding for cross-browser compatibility, and this is one of those cases that drives me nuts.  Worse than that is the fact that in certain elements (such as tables), the IE-specific innerText does not always behave properly, sometimes tossing errors, other times simply doing nothing.  Typically, I'll write a wrapper function for situations like this, so that I can call:
updateElementText(object, text);

I pushed this aside until the end of our lesson, and did a little digging, remembering some little nugget of a textNode object in the DOM.

This little guy is supported cross-browser, which I like.  What I don't like is that, unlike innerWhatever, it doesn't automatically exist; one has to create it prior to using it.  The above functionality can be crudely re-written as:
if (!document.getElementById('my_element').childNodes[0]) {
    document.getElementById('my_element').appendChild(document.createTextNode(txt));
} else {
    document.getElementById('my_element').childNodes[0].nodeValue = txt;
}

I'll give you a couple seconds to find the fatal flaw here.  Give up?  What if 'my_element' already has a child node, and that node is not a text node?  Yep.  That's bad.  And since the textNode object only has two properties -- nodeValue (aka data) and length -- the only solution I see here is to walk the child nodes, looking for my_element.nodeType == 3 (TEXT_NODE).  Definitely not an ideal solution.

So, in this case, it appears the un-sexy browser-dependent innerHTML/innerText is the practical solution.

It's a real shame that some of the simplest tasks in Javascript are anything but.

Sunday, May 16, 2010

High-Priced Wireless Repeater Bridge From a Junked Router

One of the more obscure things floating around the Internet is a little piece of software called DD-WRT.  It's a free, linux-based firmware package designed to replace the watered-down crap that comes installed on most mass-consumer retail wireless routers.

I've been meaning to tinker with this stuff for a while now, but just found myself with a few free minutes to try it out.  I have an old Linksys router (the WRT54G, v3) that was hit by lightning about a year ago and toasted one of the hardwire ports.  Rather than pitch things like this, I tend to keep them for experiments just like this one.

You flash the firmware using the router's own web-based utility, simply uploading the new firmware, followed by performing a hard reset on the router.  After that, the sky is the limit.

It took me all of 20 minutes (including time spent reading the wiki) to set this spare box up as a wireless repeater bridge.  So now my little clunker is fit for duty out in my garage, and I have a nice strong wi-fi signal throughout my property (and probably half the neighborhood) if I need it.  Better yet, I can plug in some ethernet-based devices if I want so I can stream audio and video across my lot into my man cave, and without the hassle of running a Cat-6 all the way out there.

I've tested the signal and speed by connecting a hardwire from my netbook to the router (and turning off wi-fi on the netbook), and speedtest.net shows me that my Internet speed is every bit as fast on the wireless bridged connection as it is on my desktop in the house.  (I've not benchmarked throughput between the house and the garage yet, but I don't feel any sluggishness that would indicate a poor wireless connection.)

I wish all my little projects went as smoothly as this one did.

Sunday, April 18, 2010

Linux and TV Tuners

Just a follow-up to a prior post about TV tuner cards under Linux.  Well, the prior issue was that I was working with an external USB tuner.  I've since picked up a Hauppauge HVR-1600 PCI dual-tuner board.  (This was well under $100 at Best Buy.)  It features one analog tuner (for analog cable) and one digital tuner (for ATSC over-the-air HD).

There were a couple video4linux hoops to jump through to get this card working with MythTV, but those were addressed very well in this wiki article on the MythTV wiki site.  It only took me about an hour to get the whole setup working (that included fixing some permissions issues with my NTFS formatted external USB drive).

I've since been using MythTV to schedule all my recordings, and have begun looking into streaming options to get those shows pushed out to all the other terminals in the complex without jumping through even more hoops.  I plan to add a second board soon to help eliminate the few scheduling conflicts I have where I need to record more than 1 HD show at a time.

For now, I'm limited to watching them on the living room TV because I haven't yet found a UPnP solution that works seamlessly with the XBox 360.

Sunday, March 14, 2010

unConvert?

Just shy of one year ago, I wrote of my love affair with the iPhone.

Well... I'm fickle, and she's a cheating, lying bitch.

"It just works" stops working when you're talking tethering, and save the actual phone functions, that happens to be THE main reason I keep a phone around these days. Without tethering, I'm dead in the water.

So, I switched to the Google Nexus One. I can't even begin to describe my excitement over the unrealized innovativeness of this device. Maybe I'll recap some of that down the road.

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!