flutter - 如何从字节数据中读取蓝牙特征并将其转换为适当的值(用于 flutter 的蓝牙)

我必须通过与 Flutter 一起使用的 BLE(蓝牙低功耗)读取和写入 Bike Smart 训练器的一些值。当我尝试从 GATT 特征 org.bluetooth.characteristic.supported_power_range (在 bluetooth.org 站点 https://www.bluetooth.com/specifications/gatt/characteristics/ 上找到)读取值时,我得到一个 Int 列表 [0,0,200,0,1,0] 的返回值。

GATT 特性表明 Min.、Max 有 3 个 sint16 字段。和步长瓦特(功率)。

字节传输顺序也是先传输最低有效八位字节。

我的猜测是,这 3 个参数在一个 Int 数组中返回,每个数组都有 8 位值。但我无法解释 200 可能是最大功率设置。因为聪明的教练应该提供最大。 2300W 瓦电阻(ELITE Drivo https://www.elite-it.com/de/produkte/home-trainer/rollentrainer-interaktive/drivo)

此代码段的输出结果:

device.readCharacteristic(savedCharacteristics[Characteristics.SUPPORTED_POWER_RANGE]).then((List<int> result) {
  result.forEach((i) {
    print(i.toString());
  });
});
// result: [0,0,200,0,1,0]

也许你们中的某个人知道如何解释 flutter_blue 特征输出的二进制/十六进制/十进制值。 或者一些提示会很棒

编辑

对于 future 的读者,我得到了解决方案。我有点惭愧,因为我读错了特征。

返回值 [0,0,200,0,1,0] 用于支撑阻力位。 (即 20%,200 显示 20%,分辨率为 0.1,如 GATT 规范中所述)

我还得到了支持的功率级别的返回值,即 [0,0,160,15,1,0]。现在解决如何读取最大功率级别的 2 字节:你得到 160,15 规范 sais LSO(首先是最低有效 octet,不要将它与 LSB 最低有效 位混淆 首先)。事实上,你必须像 15,160 一样阅读它。现在用第一个字节 15*256 + 160 = 4000 进行数学运算,这就是数据表中训练器支持的正确最大功率。

我希望我能帮助某人。感谢您的两个回复,他们也是正确的,并帮助我找到了我的错误。

最佳答案

我在连接到 Polar H10 以恢复 HR 和 RR 间隔时遇到了同样的问题。它可能不是 100% 相同,但我认为我的案例可以指导您解决您的问题。

我收到的列表和你一样,喜欢这两个例子:

  1. [0,60]
  2. [16,61,524,2]

查看 GATT Bluetooth Heart Rate Service 的规范我认为检索到的列表中的每个元素都与您下标的特征传输的数据的 1 个字节匹配。对于此服务,第一个字节,即列表的第一个元素,有一些标志来指出 HR 值 (16) 之后是否有 RR 值 (0)。这只是根据标志值可能发生的许多不同情况中的两种情况,但我认为它显示了第一个字节的重要性。

之后,HR 值被编码为一个 8 位的无符号整数 (UINT8),即 HR 值与前面显示的列表的第二个元素匹配。但是,RR 区间被编码为 16 位 (UINT16) 的无符号整数,因此列表 #2 [16,61,524,2] 的最后两个元素的翻译变得复杂,因为我们应该使用 16 位来获取这个值,并且字节的顺序不正确。

这是我们导入库的时候 dart:typed_data

import 'dart:typed_data';

...

_parseHr(List<int> value) {

// First sort the values in the list to interpret correctly the bytes
List<int> valueSorted = [];
valueSorted.insert(0, value[0]);
valueSorted.insert(1, value[1]);
for (var i=0; i< (value.length-3); i++) {
  valueSorted.insert(i+2, value[i+3]);
  valueSorted.insert(i+3, value[i+2]);
}

// Get flags directly from list
var flags = valueSorted[0];

// Get the ByteBuffer view of the data to recode it later
var buffer = new Uint8List.fromList(valueSorted).buffer; // Buffer bytes from list

if (flags == 0) {
  // HR
  var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
  var hr = hrBuffer.getUint8(0);                  // Recode as UINT8
  print(hr);
}

if (flags == 16) {
  // HR
  var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
  var hr = hrBuffer.getUint8(0);                  // Recode as UINT8

  // RR (more than one can be retrieved in the list)
  var nRr = (valueSorted.length-2)/2; // Remove flags and hr from byte count; then split in two since RR is coded as UINT16
  List<int> rrs = [];
  for (var i = 0; i < nRr; i++) {
    var rrBuffer = new ByteData.view(buffer, 2+(i*2), 2); // Get pairs of bytes counting since the 3rd byte
    var rr = rrBuffer.getUint16(0);                       // Recode as UINT16
    rrs.insert(i,rr);
  }
  print(rrs);
}

希望对您有所帮助,关键是获取排序列表的缓冲区 View ,获取您需要的字节,并按照标准指出的那样重新编码。

https://stackoverflow.com/questions/56330018/

相关文章:

dart - 如何在 Dart 中将 Class 对象转换为数据结构 `Map` 或 `List o

dart - 向 Flutter 中的计算函数发送多个参数

dart - Flutter,如何让我的原 Material 纽扣更大更紧密地组合在一起。

dart - Column 内展开的小部件未展开,而是不可见

dart - 如何在 Dart 中通过 async* 传输错误?

flutter - 在 SafeArea 中获取小部件高度的正确方法

android - Flutter:使用 Sliver 小部件时如何在滚动时隐藏 BottomApp

dart - 在 SnackBarAction onPressed 上 flutter 小吃吧

dart - Flutter如何将容器背景设置为透明色

generics - 如何从 Dart/Flutter 中的泛型函数调用命名构造函数