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
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?
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
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
Sunday, March 14, 2010
unConvert?
Saturday, January 16, 2010
Linux on the Real User's Desktop: TV Tuners
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!
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!