The Herd Of Kittens -- ScanMemo


ScanMemo is a simple but powerful barcode scanning application; it takes one significant step over the demo apps in that it records scans, and doesn't merely display them on screen. This is still a hacker-level app -- which means that while the UI isn't pretty, it is a useful piece of a complex system.

The name comes from the original design intent: in order to simplify interfacing with other tools, I thought it would be easier to drop the scans into a memo pad. It turns out that creating my own database is both more correct and simpler to implement.

This app was built with GCC (from the Debian prc-tools package.) Screen shots were made with xv and pose (Save Screen doesn't seem to do anything as of 2.1d29-1.) Note that Symbol does not yet "support" GCC -- the stub library that they provide is a CodeWarrior ".Lib" file -- but they have released a ScanMgr.o through DIKU which I've sucessfully linked this app with. If you're still interested in the reverse-engineering effort, there remain some notes on the project that might be of use in a future conversion.

UPDATE 0.03+ (2001-11-03)

I've rebuilt 0.03 (it now has a small icon, and there were minor non-visible build-environment changes.) I've also confirmed that this works not only with the SPT1700 but also with the CSM-150 Symbol "Springboard" scanner card for the Visor Handspring. The CSM-150 is a much cheaper solution for apps that don't need full armoring - and you can store the app and data in the 2M onboard the CSM-150 - they appear on insertion and you can run them directly.

One issue: the CSM-150 driver will try and grab a user-selected set of buttons as "trigger" buttons, but only in apps that open the scanner device. If you're running AppHack (a HackMaster plugin that lets you bind apps to two sequential button presses) then it simply doesn't take effect. Turning off AppHack fixes the problem, but isn't really acceptable; I'll add a "scan" screen-button to the next version of ScanMemo.


The downloads have been updated to 0.03, which has had the debugging dumps removed from the display and a "shelf code" popup added (so you can "name" an entire shelf and then advance along the numbers as you scan; I'll add a "next shelf" button later.) I haven't had time to update the screenshots or usage example, but now recognizes and emits two new fields, the Shelf Number and the Bar Code Type (see the Symbol SDK for the meaning of the values for now.)

Screen Shots

Initial screen. The [ ] regions at the top are debugging labels; the [ ] at the bottom is a status indicator which shows how many records are stored (after each scan.) The Tag: field is editable and is stored with each scan; to label a batch of things, fill in the tag field first, then scan them all. Unsuccessful scans are stored (with a value of NR) which can be useful for logging timestamps or for separating batches of scans.



Source is not available right now, but only because I've only worked on it for a few days and it is embarassingly primitive. If you really want it anyway, I'd suggest looking at the BarCode section of the O'Reilly Palm Programming book; if you're still interested, go ahead and email me.


As a worked example, consider the library application. We want to scan a few shelves of books and then get them on line somehow.

The first is a seconds-since-1904 PalmOS-style (well, MacOS-style really) timestamp; the second line is the scan result, which is also in the Scan: field. The type: is an internal type tag for what barcode was seen; 22 decimal (0x16 hex) is documented in ScanMgrDef.h as BCTYPE_BOOKLAND_EAN which is what we expect. The last line tells us that it saved this record in the internal database; that's it! We can move on to the next book. Don't worry about scan errors, we can filter them out later.

Note that the first column is a Unix-style timestamp, based in 1970, not a PalmOS-style one. The second column is your tag, the third is the scan itself. * If you find HTML easier to work with (there are some clever ways to parse an HTML table into an SQL database via perl using the DBI DataBase Interface packages) then you can instead use perl Scans-KtnT.pdb html which generates output like

<tr><th>Tag</th><th>Scan</th><th>Unix Time</th></tr>
<td>thok tech 2</td>

which formats like this:

Tag Scan Unix Time
thok tech 2 020163337X 940869730
thok tech 2 0079113362 940869727
thok tech 2 0937175641 940869721
thok tech 2 1565922220 940869715
thok tech 2 1565920562 940869708
thok tech 1 0471597562 940869598
thok tech 1 NR 940869596
thok tech 1 NR 940869596
thok tech 1 0201563274 940869592
thok tech 1 0198537379 940869588
thok tech 1 NR 940869584
thok tech 1 0134327179 940869578
thok tech 1 0201403633 940869569
thok tech 1 0201877007 940869282

The DTD for this is self-evident, and for most XML tools, unnecessary. * Working with the raw data, we can do a few processing tricks; grep -v '"NR"' to strip out the unsuccessful scans, sort -n to sort into timestamp order (it is an artifact of the PalmOS database handling code that records are naturally added in reverse order, so you see in these examples the most-recent scans first.) * Now that we have the data, we need one more trick to get meaning out of it. To start with the biggest hammer, we use YAZ (Yet Another Z39.50 package) to bounce our ISBN off of the Library Of Congress:

yaz-1.4pl2/client/client -m marc-record.$ISBN tcp:$HOST 
base $DB
format sutrs
attributeset bib1
elements F
find @attr 1=7 "$ISBN"

Note in particular that this script actually shows the record in text form to standard output, but the marc-record.* file actually has a raw USMARC electronic card-catalog entry, which is what we really want. * What do we do with a MARC record if we're not already a library? Use perl, of course. First, use perl -MCPAN -e 'get MARC' to download the latest MARC package, then perl -I ~/.cpan/build/MARC-0.91/ -e 'use MARC; $x=MARC->new("marc-record.0079113362"); $x->output({file=>">marc-output.txt",format=>"ascii"});' and we have a nice text-formatted card catalog entry. Tweaking the last bit to say {file=>">marc-output.html",format=>"html"} gives primitive html (a little bit nicer than the ascii format if you're dumping this out onto a web page); better yet, {file=>">marc-output.xml",format=>"xml"} gives heavily-tagged XML output, which is probably more suitable for futher processing and searching than the raw MARC record was.

Whew. Lots of detail; at this point, you could take any of the above data and dump it into a database, or a big web page, or build a sophisticated signout and reservation system. I'm not sure how far I'll go with that part, but the pieces described here are well on the way...