Tech Note 09: Bar Code ScanningFebruary 25, 2009© NSB Corporation. All rights reserved. |
NS Basic/Palm provides support for Symbol devices starting with version 2.0. The necessary libraries and samples are installed along with NS Basic/Palm: there are no extra files to download.
The Symbol routines work on all Palm OS devices from Symbol, as well as the Symbol Springboard for Visor. Please note that there are a few wrinkles with the Visor version: they are documented further on in this document. If you have a Symbol SPT15xx, it's a good idea to flash Palm OS 3.5 to the device. With older ROM versions, there is a potential error when using the STOP statement.
The routines are very simple to add into a program. Check out the sample called "Symbol" to see how it is done.
1. In your startup code, include the line
LoadLibrary "NSBSymbolLib"
This lets NSBasic know that you will be using the library.
2. Somewhere in the initialization, possibly in the After code of your main form, call the function
NSBSymbolLib.IsPalmSymbolUnit()
This will return 1 if the program is running on a Symbol unit and 0 otherwise. If it returns 0, do not try to use any further Symbol functions.
3. In the Events code of your main form, when you receive an event type 34815, call this string function to get the scanned value:
scannedData = NSBSymbolLib.GetLastScanData()
The Events code will be called whenever the user pushes the yellow Scan button on the Symbol device. NSBSymbolLib.GetLastScanData() returns a string giving the last barcode scanned. Do whatever is appropriate with this bar code.
4. Compile your NSBasic program and download it plus the NSBSymbolLib.prc directory to your Symbol device. Your program should behave appropriately according to the last settings of the scanner.
The Symbol.prj sample does this. It also gets the bar code type using the integer function NSBSymbolLib.GetBarType().
34815 or -30721 | A scan has been decoded. |
34816 or -30720 | The battery is low. |
34817 or -30719 | When a scan starts. |
You can display a dialog box when you recieve event 34816. Event 34817 can normally be ignored, as you will get an event 34815 after a second or two anyway. If no bar code was successfully scanned, NSBSymbolLib.GetLastScanData() returns "NR" and NSBSymbolLib.GetBarType() returns 0.
IsPalmSymbolUnit() | This function returns 1 if this is a symbol unit, 0 otherwise |
CmdScanEnable() | This procedure enables the scanner. Normally, the scanner is always enabled. You can call this to make absolutely sure, or if you also use CmdScanDisable() |
CmdScanDisable() | This procedure disables the scanner. |
CmdScanSetTriggeringModes(modes) | This procedure sets the triggering modes of the scanner. For more information, consult the Symbol documentation. |
CmdScanSetBarcodeEnabled(type, whether) | This procedure enables or disables a particular barcode. The type of barcode is given in type as an integer. If whether is 1, the barcode is enable. If it is 0, it is disabled. See table below for values. |
CmdSendParams(beep) | (obsolete) Call this procedure after a series of CmdScanSetTriggeringModes(modes) and CmdScanSetBarcodeEnabled(type, whether). If the integer beep is 1, the Symbol device will beep when this is called. If it is 0, the device will not beep. The CmdScanSetTriggeringModes() and CmdScanSetBarcodeEnabled() call this function automatically. |
CmdStartDecode() | This procedure starts a decode. The effect is the same as pressing the yellow button. To use this, you must set the triggering mode to 8. Normally, there is no reason to use this, as the yellow button is the standard way of starting a scan. |
CmdStopDecode() | This procedure stops a decode in progress. Normally, it is not used. |
GetDecodedData() | This function returns a string that contains the raw decoded data. It is only provided for debugging purposes. |
GetLastScanData() | This function returns a string that contains that last bar code scanned. You will normally call this as a response to an event type 34815. However, you can call it any time up to when the next barcode is scanned. If the last barcode was invalid, this will return "NR" as the barcode. |
GetBarType() | This function returns the type of the last scanned barcode as an integer. If the last barcode was invalid, it returns 0. See table below for return values. |
CmdScanLedOn() | This procedure turns the green LED on. Because the LED normally goes on when a scan is started, this is provided just for fun. |
CmdScanLedOff() | This procedure turns the green LED off. Because the LED normally goes on when a scan is completed, this is provided just for fun. |
GetBarType() | CmdScanSetBarcodeEnabled() | |
NOT_APPLICABLE | 0 | |
CODE39 | 1 | 0 |
CODABAR | 2 | 7 |
CODE128 | 3 | 8 |
D2OF5 | 4 | 5 |
IATA2OF5 | 5 | |
I2OF5 | 6 | 6 |
CODE93 | 7 | 9 |
UPCA | 8 | 1 |
UPCE0 | 9 | 2 |
EAN8 | 10 | 4 |
EAN13 | 11 | 3 |
MSI_PLESSEY | 14 | 11 |
EAN128 | 15 | 14 |
UPCE1 | 16 | 12 |
CODE39_FULL_ASCII | 19 | |
TRIOPTIC_CODE39 | 21 | 13 |
BOOKLAND_EAN | 22 | 83 |
COUPON_CODE | 23 | 85 |
ISBT128 | 25 | 84 |
CODE32 | 32 | |
UPCA_2SUPPLEMENTALS | 72 | |
UPCE0_2SUPPLEMENTALS | 73 | |
EAN8_2SUPPLEMENTALS | 74 | |
EAN13_2SUPPLEMENTALS | 75 | |
UPCE1_2SUPPLEMENTALS | 80 | |
UPCA_5SUPPLEMENTALS | 136 | |
UPCE0_5SUPPLEMENTALS | 137 | |
EAN8_5SUPPLEMENTALS | 138 | |
EAN13_5SUPPLEMENTALS | 139 | |
UPCE1_5SUPPLEMENTALS | 144 | |
PDF 417 | 17 | |
Use -30721 instead of 34815 Use -30720 instead of 34816 Use -30719 instead of 34817If you are trying to support both the SPTxxxx and the CSM150 devices, you will need to test for both event codes. This is caused by a bug in Symbol's code.
During project startup and termination, the normal program "event loop" processing is not performed. While it may seem natural to perform some library calls such as CmdScanEnable in the startup code after the LoadLibrary, in practice is causes events to get queued but not processed and a fatal error results.
If it is necessary to perform a Symbol library call in the project startup or termination, immediately follow the call with the following code:
Dim EventType as Variant SysTrapSub 285, 2, EventType, 1 'EvtGetEvent SysTrapSub 169, 1, EventType 'SysHandleEvent
ScanConfig is run by using AppLaunch() from within your NSB/Palm program, and supplying both a cmd integer to designate the attribute to be changed plus a data string with the associated desired value(s).
ScanConfig (and its documentation) is available in the Files section of the NS Basic web board. The URL is http://groups.yahoo.com/group/nsbasic-palm/files/ScanConfig.zip
The critical code is slightly different than in the Symbol: here is how it looks:
Startup Code:
LoadLibrary "NSBSymbolLib.inf", "NSBSymbolLib" NSBSymbolLib.cmdScanEnable()
Form Event Code
Dim foo as String Dim bar as Integer If sysInfo(9)=8459 Then 'Janam Scan Button hit foo = NSBSymbolLib.GetLastScanData() fldBarCode.Text = foo bar = NSBSymbolLib.GetBarType() fldCodeType.Text = str(bar) End IfNote: We have mixed reports whether this works properly.
Working with an Aceeca Ltd. ID::Verifi PDA API for Scanned Data
Contributed by Michael Assia SY-CON Systems, Inc.
We found the Aceeca Palm 4.1-based PDA to be an alternative to the Symbol SPT series units. Included from Aceeca is a very capable "wedge" scanner program to make entering barcoded data into any application an easy matter. Why then would you need anything else for your application?
The Aceeca wedge software reads a barcode and completes the current field where focus remains on the field. This occurs for any input field regardless of how the data is entered including the Symbol SPT series with the NSBSymbolLib. The user must tap into the next field before entering or scanning the next value. It was our desire, however, to make barcode input an intuitive process with little to no tapping, just scan to complete the field and automatically move to the next input field ready for the next scan. You may also want to perform a different operation or display messages based on the data obtained from the scan immediately after it is received. You can also get the desired results using the Aceeca wedge API by intercepting the events and characters generated by the software as it decodes the barcode characters read.
The behavior of the Aceeca API within an NSBasic written application differs from that described in the BCS2 write-up and C/C++ example. Within an NSBasic application you will need to use the GetEvent call from the NSSystemLib to detect the KeyDown event (4) that occurs for each character scanned. The GetEvent must be called in the form's Event code to handle this process. The actual decoded character is obtained by calling another NSSystemLib function, KeyEventChr.
The Aceeca API continues to generate the KeyDown event for each character it decodes until the barcode is fully decoded. However programmatically there is no way to know how many characters are to be received. To signify the end of a barcode string, you will need to use the Advanced setup for the Aceeca wedge software on the PDA and add a CR LF (carriage return & line feed) or some other special characters (2) to the end of the character string representing the barcode data read. Make sure the characters you choose are not found in any barcode symbology you are using.
Project Startup
' Define several key fields so their value exists thorough out the program ' Global dataread as String 'to hold scanned characters until all are received Global Cr as String Global Lf as String . . Cr = Chr(13) Lf = Chr(10) LoadLibrary "NSBSystemLib", "NSL"Form Code (Event) for any forms with barcode input
Sub Form1047_Event() Dim evnt as Integer ' evnt = NSL.GetEvent(500,0,0) If evnt <> 4 Then Exit Sub ' ' Event was keydown from Aceeca PDA ' Get each character one-by-one read by scanner ' keychr = NSL.KeyEventChr() If chr(keychr) <> Cr And chr(keychr) <> Lf Then dataread = dataread + Chr(keychr) Else If chr(keychr) = Lf Then Exit Sub ' ' After getting Cr, put string into appropriate input field. ' Select Case statecode Case 1 statecode = 2 in1.text = dataread In2.Setfocus in2.text = "" Case 2 statecode = 3 in2.text = dataread In3.Setfocus in3.text = "" Case 3 in3.text = dataread statecode = 4 In4.SetFocus in4.text = "" Case 4 in4.text = dataread statecode = 1 in1.SetFocus in1.text = "" Case Else End Select dataread = "" End If End Sub
In my opinion the 3E model is junk -- it is a CMOS scanner with a very slow processing speed and horrid success rate. Nearly unusable in my book.
But I do use the 3M model now -- it is a class 1 laser and works pretty well. Not quite as nice as the Symbol scanners, but WAY better than the 3E and still quite a bit better than the various Grabba models.
I've not tried the 3P model, which is a class 2 laser and should be even better.
http://www.socketmobile.com/products/handheld-computer/accessories/series3/
I think probably all of them work the same from an application perspective though. So I do know something about using the 3M from code, and the 3E probably works the same way.
In my case, I load their shared library, set various configuration options from my code, and disable their trigger button capture and control it myself from my app. My app intercepts all the hardware butons, and when the one assigned to the scanner is pushed, I make calls to their shared library to initiate the scan.
But that is at least in part because my app is ultra flexible. Users have a page where they can assign any of long list of functions to any of the hardware keys. So they can change which key triggers a scan, and my app has to accomodate it dynamically. I also support the symbol scanners (or Visor with CSM150 springboard), the Grabba line of scanners, and the SDSC 3M scanner.
Each of which requires different code to trigger the scan, accept / process a completed scan, etc (not to mention startup and shutdown changes, what library to load, etc).
Of course, I have the advantage that I am doing all of it from C, not NSB/Palm (sorry -- I need the flexibility and performance...).
Sending a keystroke from a program
Use EvtEnqueueKey, which is SysTrapSub 301 in NSB/Palm parlance.
Dim keyChar as Short Dim keyCode as Short Dim keyModifiers as Short keyChar = 516 'vchrHard1; 517-519 for buttons 2-4 instead keyCode = 0 keyModifiers = 8 'commandKeyMask 'EvtEnqueueKey SysTrapSub 301, 3, keyChar, keyCode, keyModifiersThe above should mimic the press of the first hard key (vchrHard1). The other 3 on the bottom of the Palm should be 517, 518, and 519.
Note that I have not tried this from NSB/Palm for triggering a scan. But the above is the general technique for inserting a "press" of those buttons, and since you are putting it into the system event queue, I think the scan library will probably detect it and trigger a scan.