I have a bluetooth barcode scanner that supports bluetooth LE and I am trying to get the barcode information from it when one is scanned.
I can connect to it fine onServicesDiscovered
gets called in my BluetoothGattCallback
but I am not sure what to do from there.
With a classic bluetooth connection you would get a InputStream
from a BluetoothSocket
and you would just wait for the read()
to give you data but I am not sure how it works with Bluetooth LE. I tried looping through the BluetoothGattCharacteristic
's checking the property and if its a read property I call gatt.readCharacteristic(characteristic);
but that just gives me useless information and that's even before I attempt to scan something.
So how do I get the barcode data from the scanner?
this is the scanner I have https://www.zebra.com/us/en/support-downloads/scanners/ultra-rugged-scanners/li3608-li3678.html
The data provided by BLE devices is called Characteristics. These data packages are specially formed, tightly packed byte arrays that encode specific values for specific Services. You can check out the Assigned Numbers at the official Bluetooth website. Here you'll find the defined (authoritative) GATT services and the belonging characteristics.
For example, you have a BLE cycling computer that reports speed and cadence. You look up the Cycling Speed and Cadence item in the assigned numbers specs. The GATT Services (chapter 3.4) contains the UUID (0x1816) of the service. You then go to the Bluetooth Specifications page and do the following:
This was the Bluetooth LE part in general, now back to Android. Note, that you'll have to look up these fields in order to get the values from the characteristics. I'm just gonna assume that you already have the characteristic that you want to get the data from. Here's a quick sample that retrieves the wheel and crank revolutions (if available).
BluetoothGattCharacteristic characteristic = ... ;
int offset = 0; // we define the offset that is to be used when reading the next field
// FORMAT_* values are constants in BluetoothGattCharacteristic
// these represent the values you can find in the "Value Fields" table in the "Format" column
int flags = characteristic.getIntValue(FORMAT_UINT8, offset);
offset += 1; // UINT8 = 8 bits = 1 byte
// we have to check the flags' 0th bit to see if C1 field exists
if ((flags & 1) != 0) {
int cumulativeWheelRevolutions = characteristic.getIntValue(FORMAT_UINT32, offset);
offset += 4; // UINT32 = 32 bits = 4 bytes
int lastWheelEventTime = characteristic.getIntValue(FORMAT_UINT16, offset);
offset += 2; // UINT16 = 16 bits = 2 bytes
}
// we have to check the flags' 1st bit to see if C2 field exists
if ((flags & 2) != 0) {
int cumulativeCrankRevolutions = characteristic.getIntValue(FORMAT_UINT16, offset);
offset += 2;
int lastCrankEventTime = characteristic.getIntValue(FORMAT_UINT16, offset);
offset += 2;
}
The flags
field needs to be checked for specific bits because it is possible that the device does not report every type of data, e.g. it doesn't count the wheel revolutions. The selected characteristic's sheet always contains the relevant information about this field (if exists).
It's also worth noting that the documentation says that
The CSC Measurement characteristic (CSC refers to Cycling Speed and Cadence) is a variable length structure containing a Flags field and, based on the contents of the Flags field, may contain one or more additional fields [...]
This is why you cannot assume that cumulative crank revolutions value is to be found at the 7 bytes (8 + 32 + 16 bits; 1 + 4 + 2 bytes respectively) offset and the offset should be counted as you progress along the fields.
This was an example for reading Cycling Speed and Cadence values from a BLE device. You'll have to look up these available fields and values for every device (or rather the service) you want to support in your application. If the device is a special one and it cannot be found in this GATT directory, you'll need to consult the device's manual, SDK, or vendor for more info.