Socket, the Socket logo, Battery Friendly, Socket Bluetooth Cordless Hand Scanner, and SocketScan are trademarks or
registered trademarks of Socket Mobile, Inc. Bluetooth and the Bluetooth logos are registered trademarks owned by Bluetooth
SIG, Inc., U.S.A. and licensed to Socket Mobile, Inc. All other brand and product names are trademarks of their respective
holders.
The Socket Bluetooth Cordless Hand Scanner includes technology licensed under United States Patent Numbers 5,902,991,
7,429,000 B1 and D526,320 S.
Reproduction of the contents of this manual without the permission of Socket Mobile is expressly prohibited. Please be aware
that the products described in this manual may change without notice. Feel free to contact Socket Mobile at:
Other than the above, Socket Mobile can assume no responsibility for anything resulting from the application of information
contained in this manual.
Please refrain from any applications of the Socket Bluetooth Cordless Hand Scanner that are not described in this manual.
Please refrain from disassembling the Bluetooth Cordless Hand Scanner. Disassembly of this device will void the product
warranty.
You can track new product releases, software updates and technical bulletins by visiting the Socket Mobile website at:
http://www.socketmobile.com.
Socket Mobile, Inc.
39700 Eureka Drive, Newark, CA 94560-4808, USA
+1-510-933-3000
USA/Canada Toll-free: 1-800-552-3300
This SDK is designed for use with the Socket CHS 7 series scanners on several
OS platforms including Apple iOS, Android, RIM, Windows Desktop and
Windows Mobile 6.x. The intended usage is to develop a native application that
includes built in support for the Socket 7 series scanners. This SDK gives the full
programmatic access to a connected 7 series scanner to customize the scanner
Symbology and data support, manages scanner feedback messages and
functions or modifies default scanner behavior.
Before beginning the process of implementing the ScanAPI into an application it
is first recommended reading through this intro regarding the connection process
of the scanner as this might answer many questions in regards to how an
application communicates with the scanner.
1.1 Scanner connection information
The connection information below applies mainly to the Android, RIM and
Windows operating systems.
For the iOS platform the connection is simplified based on the host iOS handling
the connection. It is recommended to refer to the readme.rtf file from the ScanAPI
SDK DMG install that is part of the ScanAPI iOS SDK..
1.1.1 Scanner HID mode
The CHS 7 series scanners are shipped by default in HID profile mode and will
display the following friendly name:
For the 7Xi series:
Socket 7Xi [xxxxxx] (where x’s are the last 6 digits of the BD address of the
scanner)
Or for the 7Ci/M/P series:
Socket CHS [xxxxxx]
In this mode the scanner functions as a standard HID keyboard device and can
be tested in this mode as if it is a keyboard.
It will NOT work with an application using ScanAPI.
NOTE: if the scanner in HID mode is discovered and tested it may cause conflicts
with discovering and using the scanner in SPP mode due to the fact that some
devices will cache the name and service information of the device.
Socket recommends that the pairing information is removed by deleting or
unpairing the device using the host device Bluetooth manager before connecting
the scanner in a different mode.
1.1.2 SPP Mode for the SDK
The SPP Mode is the required mode for the Scanner to be able to communicate
with an application using ScanAPI.
The SPP Mode has 2 configurations. One configuration called Acceptor, and
another called Initiator.
In Acceptor configuration, the scanner is discoverable and connectable and
basically waits for a host to connect. The scanner indicates that it is in this mode
by a slow blue LED flashing.
In Initiator configuration, the scanner knows the Bluetooth address of the host to
connect to.
Each time the scanner is powered on in this configuration, it will try to connect to
the host corresponding to the Bluetooth address it has in memory.
The scanner indicates that it is in this mode by a fast blue LED flashing. The
scanner stays in this mode until it successfully connects to the host or after a
2minutes timeout occurs, which it will signal by doing a long beep.
At this point the scanner can be powered off and on to retry to connect to the
host.
1.1.3 Initial connection to iOS host or to any host for a 7Ci,M and P
series
The process of connecting a scanner to an iOS host device or a 7Ci, M and P
scanner to any host device is the same and can be summarized to these simple
steps.
Step 1: The scanner must be in Acceptor mode.
For an iOS device, the scanner can be in configured in Acceptor mode by
scanning a barcode that has the value of “#FNC IOS ACCEPTOR
000000000000#” for a 7Xi or “#FNB00F40002#” for a 7Ci.
For any other host Device (not iOS) the scanner can be configured in Acceptor
mode by scanning a barcode that has the value of “#FNB00F40000#” for a 7 P,M or Ci series, or “#FNC SPP ACCEPTOR 0000000000#” for a 7Xi series scanner.
The barcode can be a 2D barcode for a 7Xi scanner only.
Step 2: Discover and pair the scanner from the host.
By using the Bluetooth settings of your host device, discover and pair the
scanner. If a PIN code is request use “0000” (4 zeros) and the pairing should
complete.
For iOS host device this is the final step. The scanner can now be used by the
application using ScanAPI.
Step 3: (For all hosts but iOS devices) Instruct the scanner to connect back to the
host by using Socket EZ Pair application.
Once the scanner is configured correctly, it will always try to reconnect back to
the host each time it is powered on or back in range.
1.1.4 Simplified connection process to any host but iOS devices
There is a simplified process that can be used when the host Bluetooth device
address is known either by printing out barcode or by using 7xi with Socket
EzPair.
This process isn’t possible for iOS device as there is no API to retrieve the iOS
Bluetooth address and the iOS devices won’t authorize a scanner to connect
and pair unless the Bluetooth Settings page is displayed on the screen.
The following steps for 7Xi series is as simple as scanning a 2D barcode that has
the value: “#FNC SPP INITIATOR xxxxxxxxxxxx#” with xxxxxxxxxxxx replaced by
the host Bluetooth address, or by scanning out of the Socket EZ Pair screen the
2D barcode.
The same principle for 7 P, M and Ci series scanner, by scanning a Code 128
barcode that has the value: “#FNIxxxxxxxxxxxx#” with xxxxxxxxxxxx replaced by
the host Bluetooth address. NOTE the 7 P, M and Ci series scanner shoud be
first and only once set to SPP mode by scanning the “#FNB00F40000#” Code
128 barcode.
1.1.5 Connection Process integration
For the 7P, M and Ci series scanners there are two methods that canbe used to
configure the scanner to be an initiator to the host device:
Implement the 1D EZ Pair process in your app to select a pre discovered scanner
and configure it to be an initiator to the host device. This process is explained in
paragraph 8.6 Socket EZ Pair feature.
Method 2:
-Manually create an EZ Pair barcode with each host system Bluetooth address
so that the 1D scanner simply needs to scan the barcode to configure it as an
initiator to the host device
For the 7Xi series scanners you can just present the EZ pair barcode as part of
your application setup process.
Either way once that part is done your app just needs to have ScanAPI initialized
and waiting to receive the incoming connection of the scanner.
2 ScanAPI Introduction
ScanAPI delivers an application programming interface (API) to control and
configure Socket Bluetooth Cordless Handled Scanners (CHS) connected to a host
computer.
A ScanApi Helper component is provided for Objective C, C# and Java platforms to
integrate more easily ScanAPI into an application. ScanAPI Helper handles the
asynchronous events through callbacks, and gives an easy way to manipulate the
asynchronous commands an application can send to a CHS by providing a callback
mechanism that is invoked when the command response is received.
A CHS has severall properties that can be retrieved, modified or actioned.
CHS properties can be by example a symbology state, its friendly name, or triggering
a scan.
This API is asynchronous. The property operation is therefore a 2-step process. The
application sends a property get or set command and if this is successful, a property
get or set complete event is received with the CHS result of that property command.
At any time a CHS can send events to the host that are retrieved using the same
mechanism as the completion of the property operation.
ScanAPI has only one entry point to receive these asynchronous events making it
very easy to manage.
The other benefit of this asynchronous API is to be able to drive a scanner from a
graphical user interface (GUI) application without danger of blocking the user
interface while waiting for a lengthy operation to complete.
The SoftScan is a feature that makes the host device built-in camera acting as a
barcode scanner. This feature is implemented using third-party technology and
therefore the developer should comply to the third-party license agreement.
Currently the SoftScan feature is available on for iOS and Android based devices.
This feature is not activated by default. In order to activate it, the application should
set the ScanAPI kSktScanPropIdSoftScanStatus to kSktScanEnableSoftScan. As soon
as ScanAPI is initialized and SoftScan is enabled, a SoftScanner device arrival event
is generated.
A device removal event is generated when the SoftScan feature is disabled by using
the same ScanAPI property with its value sets to kSktScanDisableSoftScan.
The SoftScanner doesn’t support all the properties described in this document and
returns a ESKT_NOTSUPPORTED error for them.
3.1 Licensing requirements
The third-party used for implementing the SoftScan feature is RedLaser from eBay
corporation. The RedLaser requires a license to be purchased in order to offer
unlimited scan. Without the license the SoftScanner is limited to 25 scans on a
particular host.
The License should be purchase on RedLaser portal, and the license file should be
part of the application package.
3.2 iOS requirements
The ScanAPI library for iOS is split in to 2 versions; one that supports the SoftScan
feature and one that doesn’t.
In the version that doesn’t support the SoftScan feature the required frameworks
are:
- externalAccessory.framework
- audioToolbox.framework
In the version that does support the SoftScan feature the extra frameworks required
are:
- libstdc++.dylib or libstd++6.0.9.dylib if you’re using OS6.x SDK.
3.3 Android requirements
The overlay view is a requirement for the SoftScanner in order to display the video
output in the application. This is implemented through an Activity that must be
added to the application manifest. This activity is defined as
com.SocketMobile.ScanAPI.SoftScanActivity.
The manifest should also have the following permissions:
- android.permission.CAMERA,
- android.permission.ACCESS_NETWORK_STATE
- android.permission.INTERNET
A specific layout should be created that will be displayed as the overlay view of the
SoftScan. This layout can have a white rectangle that is called a “View Finder” that is
used as a scanning guide but also is use by the softscan scanner to improve the
barcode recognition in this region. The “View Finder” ID can be passed in the hash
table of the kSktScanPropIdOverlayViewDevice property. A flash button can be
added as well and its ID should be also specified in the same hash table of the same
property. If the flash feature is not available the SoftScan scanner will disable it
automatically.
The RedLaser libraries must be added to the Android application. The simplest way
for doing this is to copy the redlasersdk.jar and the armeabi/libredlaser.so in the
“libs” directory of the Android application. That “libs” subdirectory is automatically
taking in consideration by Android Development tools (ADT 18 or higher).
4 Concept
This API defines 3 main objects: ScanAPI object, Device object and ScanObject.
4.1 ScanAPI object
This object controls the API.
In order to use ScanAPI, this object must be opened first and this first open
initializes ScanAPI. The handle returned from this open must be used for any
subsequent ScanAPI operations.
All asynchronous events are received through this ScanAPI object.
The ScanAPI object has few properties that can be retrieved or modified.
When an application is ready to use ScanAPI, it can open it by using the ScanAPI
Open API with no device name in the parameter.
4.2 Device object
The Device object represents a CHS. In order to use and receive events from a CHS,
its corresponding Device object must be opened.
The handle returned from opening a Device object is used by the application to
retrieve or modify a particular property of the CHS.
ScanAPI notifies the application each time a Device Object is available by sending a
Device Arrival event with a UUID identifying the Device Object. The application can
open this particular Device Object by specifying this UUID in the ScanAPI open API.
If a CHS disconnects from the host, a Device Removal is sent by ScanAPI to the
application to indicate that the matching Device Object is no longer valid and the
application should close it if it has it opened.
4.3 ScanObject
The ScanObject is a data placeholder used for exchanging information between the
application and the CHS or ScanAPI object.
A ScanObject holds 2 kinds of information: a property and a message.
When a ScanObject is sent from the application to ScanAPI, only the property
information in ScanObject is relevant.
When a ScanObject is received from ScanAPI by the application, the message
information is always relevant and depending on the message received the property
information might be relevant.
ScanAPI creates a ScanObject each time it receives an asynchronous event, and in
this case the application must release this ScanObject by calling a ScanAPI release
API.
The application can create a ScanObject to send specific information to either a
Device or ScanAPI. In this case the application is responsible for releasing the
ScanObject correctly.
An application has two things to do in order to setup ScanAPI correctly. It needs first
to open ScanAPI by specifying no name in the open parameter API, and then starts
either a timer or a thread to consume the asynchronous events coming from
ScanAPI.
When a CHS connects to the host, ScanAPI sends a Device Arrival event to the
application through the application ScanAPI consumer logic.
The Device Arrival event contains an UUID identifying a Device Object that
represents a CHS. The application can open the Device Object by specifying this
UUID in the ScanAPI open function.
Once the Device Object is opened, the application can retrieve or modify the CHS
properties by using the get property or set property API.
The get property and set property APIs are asynchronous. These APIs return
success if the property has been sent correctly to the CHS. The property completion
event is received in the application consumer.
If the CHS doesn't respond to a get or set property within the timeout period (about
5 seconds), for whatever reason, a matching property get or set complete event is
generated with a timeout error.
Only one property can be sent at the time to the CHS. An error occurs if a property is
sent prior the completion of the previous property operation.
ScanAPI sends a Device Removal event when a CHS disconnects from the host. The
application should close the matching Device Object if it has it opened.
4.5 ScanAPI configuration
ScanAPI has one thread listening on a serial communication port. This configuration
can be retrieved or modified by creating a ScanObject and setting its property to
ScanAPI configuration property. The ScanObject can be sent to ScanAPI using the get
property or set property API to respectively retrieve or modify this property.
Modifying the ScanAPI configuration will prompt the listener thread to restart. An
error event is generated if the configuration is incorrect.
Each time the listener starts, a Listener Start event is generated.
ScanAPI drops the connection to a CHS if it was connected during the process of
changing the ScanAPI configuration.
Please refer to the ScanAPI object properties paragraph for more information.
4.6 Get or Set a property
The ScanAPI object and the Device object have both properties that can be retrieved
or altered by using the get property or set property API.
The process of getting or setting a property is simple. A ScanObject holds a Property
field. The application must create a ScanObject instance and fill its Property member
according to the property of the object it would like to modify.
A property has an ID, a data type,data value and a context. They must be specified
accordingly to the characteristics of the property that needs to be retrieved or
modified.
The context is a field an application can use for maintaining a context. This context is
returned when a property set or get operation completes.
Once the property member of the ScanObject has been filled correctly, the
application can call the get or set API with the reference of the object to which it
wishes to retrieve or modify the property.
If the API returns success, the application can wait for the completion to be received
through the wait API.
An application cannot send multiple properties to the same object before the
previous set or get property operation has been fully completed. An error is
generated during the Set or Get API call if the previous property of the same object
hasn’t been completed yet.
The application receives the complete event through its ScanAPI consumer logic that
uses the wait API with the ScanAPI object reference.
A ScanObject that is received from ScanAPI has always its message field filled out.
The property complete event is received in a ScanObject with a Message ID set to a
Get Complete ID or Set Complete ID.
The Message has a result field that indicates if the completion of the get or set
property has been successful or not. The Property member of the ScanObject
contains the Property ID matching to the one that has been set, and in case of
success, the data type and value are filled as expected.
An important point is the fact that a property set or get can fail for many reasons,
and some of them will require the application to retry the operation and some
should just be taken into consideration. For example, if a property returns a
REQUEST TIMEOUT error because the scanner is out of the range for a brief instant
or busy receiving decoded data, having retry logic can fix this issue.
4.7 Example of sending a command
This section describes the steps for sending a command to a device.
Let’s imagine an application using ScanAPI has a button on its UI to trigger a scan.
For clarity purposes we assume the application correctly handles the connection of
the scanner and has kept a handle to ScanAPI and to this scanner accessible.
The application has ScanAPI consumer logic that will receive the messages from
ScanAPI.
This consumer logic uses the wait API with the ScanAPI object reference that has
been previously opened with the open API with NULL as device name.
The button handler creates a ScanObject, and fills the Property part with a property
ID set to kSktScanPropIdTriggerDevice, a property type set to byte, and the property
byte value set to kSktScanTriggerStart as explained in the paragraph 14.5 Property kSktScanPropIdTriggerDevice.
This button handler uses the set API to send this property to the device identified by
its reference. If the return code of this API is successful, the button handler can then
disable the trigger button indicating the trigger is in progress.
The application’s ScanAPI consumer logic that was waiting for ScanAPI messages by
using the wait API should receive the Set Complete message with the property ID set
to kSktScanPropIdTriggerDevice.
The result indicates if the trigger worked. At that point the device should have the
aim light turned on and should be ready to scan and decode data. The application
trigger button can then be enabled.
// initialize a ScanObject to // trigger the device ScanObj.Property.ID=kSktScanPropIdTriggerDevice;
ScanObj.Property.Type=kSktScanPropTypeByte;
ScanObj.Property.Byte=kSktScanTriggerStart;
// set the property with the // device handle Result=SktScanSet(m_hDevice,&ScanObj);
// check the Set result if(SKTSUCCESS(Result))
m_TriggerBtn.Enable(FALSE);
else {
// display an error message DisplayError(_T("Unable to trigger: %d"),Result);
}
}
SKTRESULT CMyAppDlg::Consume(
IN SKTHANDLE hScanAPI,
IN unsignedlong ulTimeoutInMilliseconds,
OUT BOOL* pbContinue)
{
SKTRESULT Result;
TSktScanObject* pSktObject=NULL;
Result=SktScanWait(hScanAPI,&pSktObject,ulTimeoutInMilliseconds);
if(SKTSUCCESS(Result))
{
if(Result!=ESKT_WAITTIMEOUT)
{
if(pSktObject)
{
switch(pSktObject->Msg.MsgID)
{
case kSktScanMsgIdDeviceArrival:
Result=HandleDeviceArrival(pSktObject);
break;
case kSktScanMsgIdDeviceRemoval:
Result=HandleDeviceRemoval(pSktObject);
break;
case kSktScanMsgIdTerminate:
// we are done with ScanAPI, somebody // called SktSet with Abort MsgId if(pbContinue)
*pbContinue=FALSE;// quit the for TraceInfo(_T("Receive a Terminate Msg, \
then shutdown the App receiving \ thread"));
break;
case kSktScanMsgSetComplete:
case kSktScanMsgGetComplete: Result=
// set the property with the device // reference long result = _device.SetProperty(scanObj);
if (SktScanErrors.SKTSUCCESS(result))
{
buttonTrigger.Enabled = false;
}
else
{
// display an error message
DisplayError("Unable to trigger: " + result);
}
}
// timer to checking and consuming ScanObject from ScanAPI privatevoid timerScanAPIConsumer_Tick(object sender,
{
ISktScanObject scanObj=null;
// wait for ScanAPI ScanObject long result = _scanApi.WaitForScanObject(out scanObj, 10);
if (SktScanErrors.SKTSUCCESS(result))
{
if (result != SktScanErrors.ESKT_WAITTIMEOUT)
{
int propId = scanObj.Msg.ID;
switch (propId)
{
caseISktScanMsg.kSktScanMsgIdDeviceArrival:
result = HandleDeviceArrival(scanObj);
break;
caseISktScanMsg.kSktScanMsgIdDeviceRemoval:
result = HandleDeviceRemoval(scanObj);
break;
caseISktScanMsg.kSktScanMsgIdTerminate:
// we are done with ScanAPI, somebody
result = HandleTerminate(scanObj);
break;
caseISktScanMsg.kSktScanMsgGetComplete:
caseISktScanMsg.kSktScanMsgSetComplete:
result = HandleGetOrSetComplete(scanObj);
break;
caseISktScanMsg.kSktScanMsgEvent:
result = HandleEvent(scanObj);
break;
}
// release the ScanObject we received in the wait
_scanApi.ReleaseScanObject(scanObj);
}
}
}
privatelong HandleGetOrSetComplete(ISktScanObject scanObj)
{
long result = SktScanErrors.ESKT_NOERROR;
ISktScanProperty property = scanObj.Property;
switch (property.ID)
{
// set the property with the device// referencelong result=_device.SetProperty(scanObj);
// check the set resultif(SktScanErrors.SKTSUCCESS(result)){
_button.setVisualState(VISUAL_STATE_DISABLED);
}
else{
// display an error messageDisplayError("Unable to trigger: "+result);
}
}
switch(propId){
case ISktScanMsg.kSktScanMsgIdDeviceArrival:
result=
HandleDeviceArrival(scanObj[0]);
break;
case ISktScanMsg.kSktScanMsgIdDeviceRemoval:
result=
HandleDeviceRemoval(scanObj[0]);
break;
case ISktScanMsg.kSktScanMsgIdTerminate:
// we are done with ScanAPI, somebody// called Set with Abort as MsgIDresult=
HandleTerminate(scanObj[0]);
break;
case ISktScanMsg.kSktScanMsgSetComplete:
case ISktScanMsg.kSktScanMsgGetComplete:
result=
HandleGetOrSetComplete(scanObj[0]);
break;
case ISktScanMsg.kSktScanMsgEvent:
break;
}
// release the ScanObj we received in the wait_scanApi.ReleaseScanObject(scanObj[0]);
}
}
}
// called from the ScanAPI consumer logic// that is using the wait APIprivatelong HandleGetOrSetComplete(ISktScanObject scanObj) {
long result=SktScanErrors.ESKT_NOERROR;
ISktScanProperty property=scanObj.getProperty();
switch(property.getID()){
case ISktScanProperty.propId.
kSktScanPropIdTriggerDevice:
// ungray out the trigger btn_appRef.getTriggerBtn().
setVisualState(VISUAL_STATE_NORMAL);
4.8 Handling asynchronous events or completion events
The ScanAPI object maintains a queue to receive asynchronous events and property
operation complete events waitting for the application to consume them.
An application can retrieve these events by using the wait API.
This API returns a ScanObject that will need to get released once the application is
done with it by calling the release API.
The wait API returns immediately if there is an event in the queue, or it will wait the
specified input parameter time if the queue is empty.
Completion events or asynchronous events can arrive at any time and in any order.
The recommended way for handling these events is to create a switch statement on
the message ID received in the ScanObject.
There are only 6 possible message types: kSktScanMsgIdDeviceArrival,
kSktScanMsgIdDeviceRemoval, kSktScanMsgIdTerminate,
kSktScanMsgSetComplete, kSktScanMsgGetComplete and kSktScanMsgEvent.
For each of these message types a handler function can be called. Inside the handler
function, the Result member of the Message received should be checked to be sure
the process can continue.
The handler functions for the Set Property Complete or Get Property Complete
event can also have a switch statement on the property ID. If the application used
the context member of a property, the same context is then returned in the complete
property.
The decoded data or the CHS button’s press status is received in the handler
functions for the messages that have kSktScanMsgEvent as message ID.
4.9 Termination
When ScanAPI is no longer needed it can be terminated by setting an Abort property
to the ScanAPI object.
At that point, if there are any devices open, ScanAPI sends a Removal event for each
of the Device objects open, upon which the Device object should be closed by the
application using the close API.
Once all the Device objects have been closed, ScanAPI sends a Terminate event and
at that point it is safe to close ScanAPI.
5 ScanAPI Helper (available for Java, C# and Objective C)
ScanAPI Helper has been created to facilitate the integration of ScanAPI into an
application.
It is released as source code and therefore can be highly customizable for the need
of your application. Some basic and common features are provided as sample on
how to use ScanAPI.
NOTE: ScanAPI Helper is available for Java, C# and Objective C base code.
ScanAPI Helper maintains a list of commands to send to ScanAPI. Since properties
cannot be sent before the completion of the previous one, it offers an easy way to
queue the commands and provides a callback for each command completion.
A command in this context is either a “Set Property” or a “Get Property”.
By example, if an application wants to retrieve the friendly name and the version of
the connected device, it uses ScanAPIHelper to do a “PostGetFriendlyName” and a
“PostGetDeviceVersion” in a row, and for each of these functions, a callback is
passed, so when the Get Friendly Name completes, the callback is called and the
application can refresh the UI with the new friendly name, and it follows the same
logic when Get Device Version completes.
It retries sending the command up to 3 times if the command completion failed in
time out error.
The Java version of ScanAPI Helper creates a timer task to consume asynchronous
ScanObject coming from ScanAPI.
The C# and Objective C version of ScanAPI Helper does not create a timer, but
instead provides a method, DoScanAPIReceive, that has to be called from a timer
function or a thread.
The following paragraph describes the steps required for using ScanAPI Helper.
5.1 Handling the ScanAPI Helper notifications
Since most of the ScanAPI operations are asynchronous, it is very important to setup
a way for handling notifications. ScanAPI Helper provides a
ScanAPIHelperNotification interface or a ScanApiHelperDelegate protocol for
Objective C environment that must be implemented in order to handle the various
notifications correctly.
Here is how Scanner Settings for Android is using this interface: