How to read and convert Bluetooth characteristic from byte data to proper values(Bluetooth for flutter)

二次信任 提交于 2020-12-08 13:07:22

问题


I have to read and write some values to a Bike Smart trainer with BLE (Bluetooth Low Energy) used with Flutter. When I try to read the values from the GATT characteristic org.bluetooth.characteristic.supported_power_range (found on bluetooth.org site https://www.bluetooth.com/specifications/gatt/characteristics/ ) I get the return value of an Int List [0,0,200,0,1,0].

The GATT characteristic sais that there are 3 sint16 fields for Min., Max. and step size Watts (Power).

The Byte transmission order also sais that the least significant octet is transmitted first.

My guessings are, that the 3 parameters are returned in an Int array with 8bit value each. But I can't interpret the 200 for maybe the maximum Power setting. Because the smart trainer should provide max. 2300W Watts resistance (ELITE Drivo https://www.elite-it.com/de/produkte/home-trainer/rollentrainer-interaktive/drivo)

The Output results from this code snippet:

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

Maybe some one of u knows how to interpret the binary/hex/dec values of the flutter_blue characteristic output. Or some hints would be great

Edit

For future readers, I got the solution. I'm a bit asheamed because I read the wrong characteristic.

The return value [0,0,200,0,1,0] was for supported resistance level. (which is 20% and the 200 shows the 20% with a resolution of 0.1 like described in the GATT spec)

I also got a return value for the supported power level which was [0,0,160,15,1,0]. Now the solution how to read the 2 Bytes of max powre level: you get the 160,15 the spec sais LSO (least significant octet first, don't confuse it with LSB least significant bit first). In fact of that you have to read it like 15,160. now do the math with the first Byte 15*256 + 160 = 4000 and thats the correct maximum supported power of the trainer like in the datasheet.

I hope I help someone with that. Thanks for the two replys they are also correct and helped me to find my mistake.


回答1:


I had the same problem connecting to a Polar H10 to recover HR and RR intervals. It might not be 100% the same, but I think my case can guide you to solve yours.

I am receiving the same list as you like these two examples:

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

Looking at the specs of the GATT Bluetooth Heart Rate Service I figured that each element of the list retrieved matches 1 byte of the data transmitted by the characteristic you are subscripted to. For this service, the first byte, i.e., the first element of the list, has some flags to point out if there is an RR value after the HR value (16) or not (0). This is just two cases among the many different ones that can ocur depending on the flags values, but I think it shows how important this first byte can be.

After that, the HR value is coded as an unsigned integer with 8 bits (UINT8), that is, the HR values match the second element of the lists shown before. However, the RR interval is coded as an unsigned integer eith 16bits (UINT16), so it complicates the translation of those two last elements of the list #2 [16,61,524,2], because we should use 16 bits to get this value and the bytes are not in the correct order.

This is when we import the library 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);
}

Hope it helps, the key is to get the buffer view of the sorted list, get the bytes that you need, and recode them as the standard points out.




回答2:


You can use my package byte_data_wrapper to transform this data to a decimal value which you can understand:

  1. Get the buffer:
import 'dart:typed_data';

final buffer = Uint16List.fromList(result).buffer;
  1. Create the byteDataCreator:
// Don't forget to add it to your pubspec.yaml
//dependencies:
//  byte_data_wrapper:
//    git: git://github.com/Taym95/byte_data_wrapper.git

import 'byte_data_wrapper/byte_data_wrapper.dart';

final byteDataCreator = ByteDataCreator.view(buffer);
  1. Get your data :
// You can use getUint8() if valeu is Uint8
final min = byteDataCreator.getUint16();
final max = byteDataCreator.getUint16();
final stepSize = byteDataCreator.getUint16();


来源:https://stackoverflow.com/questions/56330018/how-to-read-and-convert-bluetooth-characteristic-from-byte-data-to-proper-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!