Skip to content

Commit d64ac36

Browse files
committed
Merge branch 'multiplex' into main
2 parents 1d3e19e + 6372dfb commit d64ac36

File tree

5 files changed

+106
-19
lines changed

5 files changed

+106
-19
lines changed

lib/constants.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const String C2_ROWING_GENERAL_STATUS_CHARACTERISTIC2_UUID =
1515
const String C2_ROWING_END_OF_WORKOUT_SUMMARY_CHARACTERISTIC_UUID =
1616
"CE060039-43E5-11E4-916C-0800200C9A66";
1717

18+
const String C2_ROWING_END_OF_WORKOUT_SUMMARY_CHARACTERISTIC2_UUID =
19+
"CE06003A-43E5-11E4-916C-0800200C9A66";
20+
1821
// CE060010-43E5-11E4-916C-0800200C9A66 //C2 device info service uuid
1922
// CE060012-43E5-11E4-916C-0800200C9A66 //C2 serial number string characteristic
2023
// CE060013-43E5-11E4-916C-0800200C9A66 //C2 hardware revision string characteristic

lib/models/ergometer.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import 'dart:typed_data';
2+
13
import 'workoutsummary.dart';
24
import 'package:c2bluetooth/constants.dart' as Identifiers;
35
import 'package:flutter_ble_lib/flutter_ble_lib.dart';
6+
import 'package:rxdart/rxdart.dart';
47

58
class Ergometer {
69
Peripheral? _peripheral;
@@ -35,10 +38,20 @@ class Ergometer {
3538

3639
/// Returns a stream of [WorkoutSummary] objects upon completion of any programmed piece or a "just row" piece that is longer than 1 minute.
3740
Stream<WorkoutSummary> monitorForWorkoutSummary() {
38-
return _peripheral!
41+
Stream<Uint8List> ws1 = _peripheral!
3942
.monitorCharacteristic(Identifiers.C2_ROWING_PRIMARY_SERVICE_UUID,
4043
Identifiers.C2_ROWING_END_OF_WORKOUT_SUMMARY_CHARACTERISTIC_UUID)
41-
.asyncMap((datapoint) =>
42-
datapoint.read().then((dp) => WorkoutSummary.fromBytes(dp)));
44+
.asyncMap((datapoint) => datapoint.read());
45+
46+
Stream<Uint8List> ws2 = _peripheral!
47+
.monitorCharacteristic(Identifiers.C2_ROWING_PRIMARY_SERVICE_UUID,
48+
Identifiers.C2_ROWING_END_OF_WORKOUT_SUMMARY_CHARACTERISTIC2_UUID)
49+
.asyncMap((datapoint) => datapoint.read());
50+
51+
return Rx.zip2(ws1, ws2, (Uint8List ws1Result, Uint8List ws2Result) {
52+
List<int> combinedList = ws1Result.toList();
53+
combinedList.addAll(ws2Result.toList());
54+
return WorkoutSummary.fromBytes(Uint8List.fromList(combinedList));
55+
});
4356
}
4457
}

lib/models/workoutsummary.dart

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import 'dart:typed_data';
33
import '../helpers.dart';
44
import 'types.dart';
55

6-
/// Processes the raw byte data from workout summary characteristics into easily accessible fields
6+
/// Represents a summary of a completed workout
77
///
8-
/// This takes care of dealing with byte endianness, combining multiple high and low bytes .etc so that applications using the data only have to deal with flutter [int] types
8+
/// This takes care of processesing the raw byte data from workout summary characteristics into easily accessible fields. This class also takes care of things like byte endianness, combining multiple high and low bytes .etc, allowing applications to access things in terms of flutter native types.
99
class WorkoutSummary {
1010
final DateTime timestamp;
1111
final double workTime;
@@ -19,7 +19,17 @@ class WorkoutSummary {
1919
//recoveryHeartRate is sent as an amended packet later. zero is not valid
2020
int? recoveryHeartRate;
2121
final WorkoutType workoutType;
22+
final double avgPace;
23+
IntervalType? intervalType;
24+
int? intervalSize;
25+
int? intervalCount;
26+
int? totalCalories;
27+
int? watts;
28+
int? totalRestDistance;
29+
int? intervalRestTime;
30+
int? avgCalories;
2231

32+
/// Construct a WorkoutSummary from the bytes returned from the erg
2333
WorkoutSummary.fromBytes(Uint8List data)
2434
: timestamp = timeFromBytes(data.sublist(0, 4)),
2535
workTime = bytesToInt(data.sublist(4, 7), Endian.little) /
@@ -32,7 +42,22 @@ class WorkoutSummary {
3242
minHeartRate = data.elementAt(13),
3343
maxHeartRate = data.elementAt(14),
3444
avgDragFactor = data.elementAt(15),
35-
workoutType = WorkoutTypeExtension.fromInt(data.elementAt(17));
45+
//recovery heart rate here
46+
workoutType = WorkoutTypeExtension.fromInt(data.elementAt(17)),
47+
avgPace = bytesToInt(data.sublist(18, 20), Endian.little) / 10 {
48+
if (data.length > 20) {
49+
var timestamp2 = timeFromBytes(data.sublist(20, 24));
50+
assert(timestamp == timestamp2);
51+
intervalType = IntervalTypeExtension.fromInt(data.elementAt(24));
52+
intervalSize = bytesToInt(data.sublist(25, 27), Endian.little);
53+
intervalCount = data.elementAt(27);
54+
totalCalories = bytesToInt(data.sublist(28, 30), Endian.little);
55+
watts = bytesToInt(data.sublist(30, 32), Endian.little);
56+
totalRestDistance = bytesToInt(data.sublist(32, 35), Endian.little);
57+
intervalRestTime = bytesToInt(data.sublist(35, 37), Endian.little);
58+
avgCalories = bytesToInt(data.sublist(37, 39), Endian.little);
59+
}
60+
}
3661

3762
@override
3863
String toString() => "WorkoutSummary ("

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
git:
1717
url: https://github.com/dotintent/FlutterBleLib
1818
ref: develop
19+
rxdart: ^0.27.3
1920

2021
dev_dependencies:
2122
flutter_test:

test/workoutsummary_test.dart

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import 'dart:typed_data';
22

3-
import 'package:c2bluetooth/models/workoutsummary.dart';
3+
import 'package:c2bluetooth/c2bluetooth.dart';
44
import 'package:flutter_test/flutter_test.dart';
55

66
void main() {
7-
test('can extract values from a workout summary byte list', () {
8-
final summary = WorkoutSummary.fromBytes(Uint8List.fromList([
7+
group("WorkoutSummary Tests", () {
8+
List<int> basicBytes = [
99
0,
1010
0,
1111
0,
@@ -23,19 +23,64 @@ void main() {
2323
190,
2424
120,
2525
0,
26+
1,
27+
100,
28+
0
29+
];
30+
31+
List<int> extendedBytes = [
32+
0,
33+
0,
34+
0,
35+
0,
36+
0,
37+
255,
38+
0,
39+
2,
40+
34,
41+
0,
42+
196,
43+
0,
44+
72,
2645
0,
2746
0,
47+
55,
2848
0,
49+
100,
2950
0
30-
]));
31-
expect(summary.timestamp, DateTime(2000, 0, 0, 0, 0));
32-
expect(summary.workTime, 1.28);
33-
expect(summary.workDistance, 25.5);
34-
expect(summary.avgSPM, 32);
35-
expect(summary.endHeartRate, 190);
36-
expect(summary.avgHeartRate, 170);
37-
expect(summary.minHeartRate, 68);
38-
expect(summary.maxHeartRate, 190);
39-
expect(summary.avgDragFactor, 120);
51+
];
52+
53+
List<int> bothSets = basicBytes + extendedBytes;
54+
55+
test('can extract basic values from a workout summary byte list', () {
56+
final summary = WorkoutSummary.fromBytes(Uint8List.fromList(basicBytes));
57+
expect(summary.timestamp, DateTime(2000, 0, 0, 0, 0));
58+
expect(summary.workTime, 1.28);
59+
expect(summary.workDistance, 25.5);
60+
expect(summary.avgSPM, 32);
61+
expect(summary.endHeartRate, 190);
62+
expect(summary.avgHeartRate, 170);
63+
expect(summary.minHeartRate, 68);
64+
expect(summary.maxHeartRate, 190);
65+
expect(summary.avgDragFactor, 120);
66+
expect(summary.workoutType, WorkoutType.WORKOUTTYPE_JUSTROW_SPLITS);
67+
expect(summary.avgPace, 10);
68+
expect(summary.watts, null);
69+
});
70+
71+
test(
72+
'can extract basic and extended values from a workout summary byte list',
73+
() {
74+
final summary = WorkoutSummary.fromBytes(Uint8List.fromList(bothSets));
75+
// expect(summary.timestamp, DateTime(2000, 0, 0, 0, 0));
76+
expect(summary.intervalType, IntervalType.INTERVALTYPE_TIME);
77+
expect(summary.intervalSize, 255);
78+
expect(summary.intervalCount, 2);
79+
expect(summary.totalCalories, 34);
80+
expect(summary.watts, 196);
81+
expect(summary.totalRestDistance, 72);
82+
expect(summary.intervalRestTime, 55);
83+
expect(summary.avgCalories, 100);
84+
});
4085
});
4186
}

0 commit comments

Comments
 (0)