如何从蓝牙 LE 设备获取数据

How do you get data from a Bluetooth LE device

我有一个支持蓝牙 LE 的蓝牙条码扫描器,我正在尝试在扫描时从中获取条码信息。

我可以很好地连接到它 onServicesDiscovered 在我的 BluetoothGattCallback 中被调用,但我不确定从那里该做什么。

使用经典蓝牙连接,您会从 BluetoothSocket 获得 InputStream,您只需等待 read() 为您提供数据,但我不确定它是如何工作的与蓝牙 LE。我尝试遍历 BluetoothGattCharacteristic 检查 属性 如果它是一个读 属性 我调用 gatt.readCharacteristic(characteristic); 但这只是给了我无用的信息,甚至在我尝试之前扫描一些东西。

那么如何从扫描仪获取条码数据呢?

这是我的扫描仪https://www.zebra.com/us/en/support-downloads/scanners/ultra-rugged-scanners/li3608-li3678.html

BLE 设备提供的数据称为特征。这些数据包是特殊形式的、紧密打包的字节数组,为特定 Services 编码特定值。您可以在官方蓝牙网站查看Services。在这里您可以找到定义的(权威的)GATT 服务和所属特征。

例如,您有一台报告速度和踏频的 BLE 自行车码表。您查找 Cycling Speed and Cadence item in the list. This entry contains the UUID (0x1816) of the service and a link to the data sheet that contains the characteristics. Now if you go to the Service Characteristics table, you'll find a couple entries. You want the speed and cadence, so you'll open CSC Measurement(条目的 Type 字段),它会将您带到特征的数据 sheet。在这里,您将看到 Value Fields table,它定义了可以从特征中读取的特定值。

这是一般的蓝牙 LE 部分,现在回到 Android。请注意,您必须查找这些字段才能从特征中获取值。我只是假设您已经拥有要从中获取数据的特征。这是一个检索车轮和曲柄转数(如果可用)的快速示例。

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;
}

需要检查 flags 字段的特定位,因为设备可能不会报告所有类型的数据,例如它不计算车轮转数。所选特征的 sheet 始终包含有关此字段的相关信息(如果存在)。

还值得注意的是文档中说

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 [...]

这就是为什么您不能假定在 7 个字节(8 + 32 + 16 位;分别为 1 + 4 + 2 个字节)处可以找到累计曲柄转数的原因offset 和 offset 应该在你沿着字段前进时被计算在内。


这是一个从 BLE 设备读取骑行速度和踏频值的示例。您必须为要在应用程序中支持的每个设备(或者更确切地说是服务)查找这些可用字段和值。如果设备是特殊设备,无法在此 GATT 目录中找到,则需要查阅设备手册、SDK 或供应商以获取更多信息。