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.
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 scan-cvt.pl 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.)
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.
Tag: thok tech 1
t:3023627682 *0201877007* type: 22(16) Tag: thok tech 1 Scan: 0201877007 Saved record 1 size 27The 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.
PILOTPORT=/dev/pilot PILOTRATE=115200 pilot-xfer -f Scans-KtnTand then activate HotSync to let pilot-xfer slurp down the file. You should see something like:
Waiting for connection on /dev/pilot (press the HotSync button now)... Connected Fetching 'Scans-KtnT.pdb'... OK Fetch done.
perl scan-cvt.pl Scans-KtnT.pdb. You should see basic comma-separated-value output like this:
940869730, "thok tech 2", "020163337X" 940869727, "thok tech 2", "0079113362" 940869721, "thok tech 2", "0937175641" 940869715, "thok tech 2", "1565922220" 940869708, "thok tech 2", "1565920562" 940869598, "thok tech 1", "0471597562" 940869596, "thok tech 1", "NR" 940869596, "thok tech 1", "NR" 940869592, "thok tech 1", "0201563274" 940869588, "thok tech 1", "0198537379" 940869584, "thok tech 1", "NR" 940869578, "thok tech 1", "0134327179" 940869569, "thok tech 1", "0201403633" 940869282, "thok tech 1", "0201877007"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.
perl scan-cvt.pl Scans-KtnT.pdb htmlwhich generates output like
<table> <tr><th>Tag</th><th>Scan</th><th>Unix Time</th></tr> <tr> <td>thok tech 2</td> <td>020163337X</td> <td>940869730</td> </tr> ...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 |
perl scan-cvt.pl Scans-KtnT.pdb xmland get output of the form
<scandb> <scanrec> <scantag>thok tech 2</scantag> <scanscan>020163337X</scanscan> <scantime>940869730</scantime> </scanrec> <scanrec> <scantag>thok tech 2</scantag> <scanscan>0079113362</scanscan> <scantime>940869727</scantime> </scanrec> ... </scandb>The DTD for this is self-evident, and for most XML tools, unnecessary.
grep -v '"NR"'to strip out the unsuccessful scans,
sort -nto 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.)
#!/bin/sh ISBN=$1 HOST=z3950.loc.gov:7090 DB=VOYAGER yaz-1.4pl2/client/client -m marc-record.$ISBN tcp:$HOST << EOF base $DB format sutrs attributeset bib1 elements F find @attr 1=7 "$ISBN" show quit EOFNote 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.
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...