Commit 4758db0
Changed files (5)
app
app/lib/bluetooth/characteristics/ble_measurement_data.dart
@@ -0,0 +1,23 @@
+import 'ble_measurement_status.dart';
+
+class BleMeasurementData {
+ BleMeasurementData({
+ required this.systolic,
+ required this.diastolic,
+ required this.meanArterialPressure,
+ required this.isMMHG,
+ required this.pulseRate,
+ required this.userID,
+ required this.status,
+ required this.timestamp,
+ });
+
+ final double systolic;
+ final double diastolic;
+ final double meanArterialPressure;
+ final bool isMMHG; // mmhg or kpa
+ final double? pulseRate;
+ final int? userID;
+ final BleMeasurementStatus status;
+ final DateTime? timestamp;
+}
app/lib/bluetooth/characteristics/ble_measurement_status.dart
@@ -0,0 +1,21 @@
+
+class BleMeasurementStatus {
+ BleMeasurementStatus({
+ required this.bodyMovementDetected,
+ required this.cuffTooLose,
+ required this.irregularPulseDetected,
+ required this.pulseRateInRange,
+ required this.pulseRateExceedsUpperLimit,
+ required this.pulseRateIsLessThenLowerLimit,
+ required this.improperMeasurementPosition,
+ });
+
+
+ final bool bodyMovementDetected;
+ final bool cuffTooLose;
+ final bool irregularPulseDetected;
+ final bool pulseRateInRange;
+ final bool pulseRateExceedsUpperLimit;
+ final bool pulseRateIsLessThenLowerLimit;
+ final bool improperMeasurementPosition;
+}
app/lib/bluetooth/characteristics/measurement.dart
@@ -1,6 +1,7 @@
/// Blood pressure measurement according to default GATT.
///
/// https://developer.nordicsemi.com/nRF51_SDK/nRF51_SDK_v4.x.x/doc/html/structble__bps__meas__s.html
+/// https://github.com/NordicSemiconductor/Kotlin-BLE-Library/blob/6b565e59de21dfa53ef80ff8351ac4a4550e8d58/profile/src/main/java/no/nordicsemi/android/kotlin/ble/profile/bps/BloodPressureMeasurementParser.kt
class MeasurementCharacteristic {
/// Create a blood pressure measurement with default GATT fields.
const MeasurementCharacteristic({
app/lib/bluetooth/characteristic_decoder.dart
@@ -1,3 +1,7 @@
+import 'dart:math';
+
+import 'package:blood_pressure_app/bluetooth/characteristics/ble_measurement_data.dart';
+import 'package:blood_pressure_app/logging.dart';
import 'package:blood_pressure_app/model/blood_pressure/record.dart';
/// Decoder for blood pressure values.
@@ -9,4 +13,47 @@ class CharacteristicDecoder {
print(data);
return BloodPressureRecord(DateTime.now(), data[1], data[3], data[14], '');
}
+
+ static BleMeasurementData? decodeMeasurementV2(List<int> data) {
+ // https://github.com/NordicSemiconductor/Kotlin-BLE-Library/blob/6b565e59de21dfa53ef80ff8351ac4a4550e8d58/profile/src/main/java/no/nordicsemi/android/kotlin/ble/profile/bps/BloodPressureMeasurementParser.kt
+
+ // Reading specific bits: `(byte & (1 < bitIdx))`
+
+ if (data.length < 7) {
+ Log.trace('BleMeasurementData decodeMeasurement: Not enough data, $data has less than 7 bytes.');
+ return null;
+ }
+
+ int offset = 0;
+
+ final int flagsByte = data[offset];
+ offset += 1;
+
+ final bool isMMHG = ((flagsByte & (1 << 0)) == 0);
+ final bool timestampPresent = ((flagsByte & (1 << 1)) == 0);
+ final bool pulseRatePresent = ((flagsByte & (1 << 2)) == 0);
+ final bool userIdPresent = ((flagsByte & (1 << 3)) == 0);
+ final bool measurementStatusPresent = ((flagsByte & (1 << 4)) == 0);
+
+ if (data.length < (7
+ + (timestampPresent ? 7 : 0)
+ + (pulseRatePresent ? 2 : 0)
+ + (userIdPresent ? 1 : 0)
+ + (measurementStatusPresent ? 2 : 0)
+ )) {
+ Log.trace("BleMeasurementData decodeMeasurement: Flags don't match, $data has less bytes than expected.");
+ return null;
+ }
+
+ final double systolic = _readSFloat(data, offset)!; //TODO
+ }
+}
+
+/// Attempts to read an IEEE-11073 16bit SFloat starting at data[offset].
+double? _readSFloat(List<int> data, int offset) {
+ if (data.length < offset + 2) return null;
+ // TODO: special values (NaN, Infinity)
+ final mantissa = data[offset] + ((data[offset + 1] & 0x0F) << 8); // TODO: https://github.com/NordicSemiconductor/Kotlin-BLE-Library/blob/6b565e59de21dfa53ef80ff8351ac4a4550e8d58/core/src/main/java/no/nordicsemi/android/kotlin/ble/core/data/util/DataByteArray.kt#L392
+ final exponent = data[offset + 1] >> 4;
+ return (mantissa * (pow(10, exponent))).toDouble();
}
app/lib/bluetooth/device_scan_cubit.dart
@@ -55,17 +55,14 @@ class DeviceScanCubit extends Cubit<DeviceScanState> {
Future<void> _startScanning() async {
_scanResultsSubscription = _flutterBluePlus.scanResults
- .listen(_onScanResult,
- onError: _onScanError,
+ .listen(_onScanResult,
+ onError: _onScanError,
);
try {
await _flutterBluePlus.startScan(
// no timeout, the user knows best how long scanning is needed
withServices: [service],
// Not all devices are found using this configuration (https://pub.dev/packages/flutter_blue_plus#scanning-does-not-find-my-device).
- // As long as no significant issues arise from this these devices are
- // considered unsupported.
- androidUsesFineLocation: true,
);
} catch (e) {
_onScanError(e);