Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
254 commits
Select commit Hold shift + click to select a range
f60c3c0
syntax and stuff
MoralCode May 10, 2022
9b16ef5
use fromBytes in super call
MoralCode May 10, 2022
1f9f93d
move WorkoutSummary to internal packets folder
MoralCode May 10, 2022
4e0f13d
move base packet classes to a base file
MoralCode May 10, 2022
26bc846
update helpers import
MoralCode May 10, 2022
035a177
bring in status data stub classes
MoralCode May 10, 2022
1fec0b1
document the data multiplex thing
MoralCode May 15, 2022
6d905e2
create a basic passthrough wrapper for a stream controller
MoralCode May 15, 2022
4ffa22d
rename and expand on dartdoc
MoralCode May 15, 2022
306bcac
add datapoint identifiers field
MoralCode May 15, 2022
730927e
deprecate monitorForWorkoutSummary
MoralCode May 15, 2022
876f86e
move src underneath lib per https://dart.dev/guides/libraries/create-…
MoralCode May 15, 2022
514b919
move definitions from internal to src folder
MoralCode May 15, 2022
567e14d
add and hook up initial stubs of the internal dataplex class
MoralCode May 15, 2022
2b2758f
add basic stream creation flow to Dataplex
MoralCode May 15, 2022
c0ae411
pass peripheral to dataplex
MoralCode May 15, 2022
5b14581
add some basic methods for creating new subscriptions to data from th…
MoralCode May 15, 2022
9da47eb
add a base class covering all concept2 data packet types
MoralCode May 15, 2022
5d9b70c
inject a data identifier into packets that dont have it
MoralCode May 15, 2022
a6680c4
fix fromBytes WorkoutSummary Constructor
MoralCode May 15, 2022
90d99b4
rename workoutsummary to workoutsummarypacket
MoralCode May 15, 2022
0551f9a
uncomment packet type parsing function and update types
MoralCode May 15, 2022
fe2340e
parse packet type when reading incoming packet from erg
MoralCode May 15, 2022
8226ec6
rename second packet
MoralCode May 15, 2022
17d4158
update byte parsing syntax for WorkoutSummaryPacket2
MoralCode May 15, 2022
380943b
add TODO notes for expanding statusdata types
MoralCode May 15, 2022
6e2d0c9
update second workout summary packet to inherit from TimestampedData
MoralCode May 15, 2022
60a5be8
remove string implementation from workoutSummary
MoralCode May 15, 2022
e90ffe6
add stub for workout summary packet 3
MoralCode May 15, 2022
65be514
stub out the remaining types
MoralCode May 16, 2022
40e7594
rename identifyPacket function
MoralCode May 16, 2022
7a9ce26
add packet parsing logic
MoralCode May 16, 2022
e70f7e1
define type for custom streamcontroller
MoralCode May 16, 2022
ee03d5e
apply filtering when adding values to the stream
MoralCode May 16, 2022
5a4e24f
generate close listener/callback
MoralCode May 16, 2022
6105ea3
add todo for converting packet to a map
MoralCode May 16, 2022
74fab4e
add maps to constants for mapping the different keys to the character…
MoralCode May 16, 2022
7f1f8c0
replace nonexistnet third packet with force curve data instead (thats…
MoralCode May 19, 2022
8ba7175
remove IdempotentCompleter helper
MoralCode May 19, 2022
5677591
return workout summary packets as maps
MoralCode May 21, 2022
07d79be
create unit test for parsing the CSV data
MoralCode May 21, 2022
adf00a5
use packet parsing/identifying function in helpers
MoralCode May 22, 2022
7ae43f5
refactor CSV retrieval into function
MoralCode May 22, 2022
fbf1694
rename DurationStampedDate -> ElapsedTimeStampedData
MoralCode May 22, 2022
119bcc4
remove printing from parsing helper
MoralCode May 22, 2022
cb11f79
use central parsing helper and separate printing
MoralCode May 22, 2022
04d9906
parse elapsedTime from more packets
MoralCode May 22, 2022
4d188e7
parse more datapoints out of segmentData
MoralCode May 22, 2022
7312975
refactor segment data to pull out a shared data field for segment Number
MoralCode May 22, 2022
38803d5
its called elapsed time in the spec i think
MoralCode May 25, 2022
919a3d9
move datatypes test to new folder
MoralCode Jun 4, 2022
7194842
start adding data keys to a constants file
MoralCode Jun 4, 2022
4740e1d
start implementing asMap() for WorkoutSummaries
MoralCode Jun 4, 2022
eccf9a7
send data to outgoing streams
MoralCode Jun 8, 2022
b89c436
add basic map of characteristics to packets
MoralCode Jun 8, 2022
97fe1d2
add some docs and tweak error messages
MoralCode Jun 8, 2022
23af539
add stub for stream validation function
MoralCode Jun 8, 2022
bc51344
import constants
MoralCode Jun 8, 2022
271b62e
close output streams too
MoralCode Jun 8, 2022
c1cf68d
change UUID to type mao into a UUID to dataKey map
MoralCode Jul 4, 2022
0b57d66
start implementing validation logic
MoralCode Jul 4, 2022
623270f
add datapointIdentifiers getter to WorkourSummary packets
MoralCode Jul 4, 2022
04a1af6
docs and some comments
MoralCode Jul 9, 2022
78f2f35
install reactive_ble
MoralCode Nov 11, 2022
345b7ad
first pass at migrating bluetooth scanning over to reactive ble
MoralCode Nov 11, 2022
707a6b9
update connection and IO related stuff to use reactive
MoralCode Nov 11, 2022
e2179dc
add flutterReactiveBle class
MoralCode Nov 11, 2022
d001e45
combine MonitorConnectionState with connection function
MoralCode Nov 11, 2022
a3cbd3a
converted to reactive calls and removed various errors
Aldaniee Nov 12, 2022
de7d632
make flutterReactiveBle property private
MoralCode Nov 12, 2022
e639294
fix other uses of the flutterReactiveBle field
MoralCode Nov 15, 2022
dae2d91
bump minsdkversion on android to make the example app compile
MoralCode Nov 15, 2022
89bb035
remove now-unused flutter_ble_lib dependency
MoralCode Nov 15, 2022
e07ba7f
add android bluetooth permissions to demo app
MoralCode Nov 15, 2022
305f47b
other android build parameter changes
MoralCode Nov 15, 2022
4a32c11
request permissions android
MoralCode Nov 15, 2022
3788c11
misc updates to settings, mainly concerning hooking up cocoapods
MoralCode Nov 16, 2022
d2750b5
xcode recommended updates
MoralCode Nov 16, 2022
3b63796
more pod stuff maybe?
MoralCode Nov 16, 2022
f6ce67a
commit podfile
MoralCode Nov 16, 2022
89b8880
fixed scanning issue and added scan button
Aldaniee Nov 16, 2022
9ae13ca
code cleaning
Aldaniee Nov 17, 2022
1942a5f
some updates to README
MoralCode Nov 16, 2022
91aad2d
missed setState
Aldaniee Nov 17, 2022
339db59
Merge remote-tracking branch 'origin/reactive-rewrite' into reactive-…
Aldaniee Nov 17, 2022
712e537
ignore use of old deprecated functions
MoralCode Nov 17, 2022
897f30b
misc formatting
MoralCode Nov 17, 2022
5ebad8b
unused import
MoralCode Nov 18, 2022
a5b5698
add location permission to android manifest
MoralCode Nov 19, 2022
42a3c85
remove old doc comment
MoralCode Nov 19, 2022
0801f51
update doc comments for Ergometer and ErgBleManager to account for ne…
MoralCode Nov 19, 2022
d61a021
update READMEs to reflect the newer version of the demo app
MoralCode Nov 19, 2022
e5554a6
update scanning to work more asynchronously
MoralCode Nov 19, 2022
8bd7250
updates to standalone docs
MoralCode Nov 19, 2022
7b6cea1
Merge branch 'reactive-rewrite' into dataplex-api
MoralCode Nov 19, 2022
11c4d17
add a deprecation notice to monitorForWorkoutSummary
MoralCode Nov 19, 2022
da92321
swap bluetooth backend in dataplex class
MoralCode Nov 19, 2022
d199551
make dataplex device object private
MoralCode Nov 19, 2022
d1a0d9d
remove monitorForWorkoutSummary method
MoralCode Nov 19, 2022
bc82877
remove docs on data objects (they are being replaced with the dataplex)
MoralCode Nov 19, 2022
27b8738
remove README documentation relating to how monitorForWorkoutSummary …
MoralCode Nov 19, 2022
94d0794
Add Core Values section to API docs
MoralCode Nov 19, 2022
166d56c
rename core api concepts heading
MoralCode Nov 19, 2022
9fcdc15
tweak the "table of contents" for the new sections
MoralCode Nov 19, 2022
7def01f
more silent protector stuff
MoralCode Nov 19, 2022
e2148e5
rename segment distance to elapsedDistance
MoralCode Nov 19, 2022
a410a72
fix byte index of the segment count
MoralCode Nov 19, 2022
666bdd0
rename SegmentData to SharedSegmentData
MoralCode Nov 19, 2022
84f94ad
finish parsing out the bytes for the SegmentData packets
MoralCode Nov 19, 2022
d3f6e4f
commit silent protector image for the docs
MoralCode Nov 19, 2022
676388a
document the use of the term "segment" from SegmentData packet name
MoralCode Nov 19, 2022
40d0fec
update example app to use the new dataplex api
MoralCode Nov 19, 2022
6e05164
formatting
MoralCode Nov 22, 2022
1b41f85
add keys for SegmentData
MoralCode Dec 21, 2022
bdecbb8
add a list of all data keys to the dataplex
MoralCode Dec 21, 2022
20eace4
add definitions for segmentData.zero() functions
MoralCode Dec 21, 2022
08e7f1b
add more zero() and datapointIdentifiers functions
MoralCode Dec 24, 2022
decae2d
update elapsed time key
MoralCode Dec 24, 2022
1fd5c18
add elapsed distance key
MoralCode Dec 24, 2022
c9e8bcb
formatting for allDatapoints set
MoralCode Dec 24, 2022
dbc032f
include elapsed time and distance in the map for workout summaries
MoralCode Dec 24, 2022
bbc16bf
use keys for monitoring for workout summary
MoralCode Dec 24, 2022
5cca58b
encapsulate Keys in a Keys class so they can be exported for end user…
MoralCode Dec 24, 2022
111afa4
monitor for interval summaries
MoralCode Dec 24, 2022
1bd9dd7
actually subscribe to receiving the data
MoralCode Dec 24, 2022
2c156cf
correct the SegmentData keys for distance
MoralCode Dec 24, 2022
26cbcc7
correct the values for erg machine type (0 is actually allowed)
MoralCode Dec 24, 2022
9fac002
add multiplexed characteristic ID to constants
MoralCode Dec 24, 2022
7e1eb4c
display both general and segment distance in the UI
MoralCode Dec 24, 2022
f489af3
remove extra parameter to sublist call when parsing workout summaries
MoralCode Dec 24, 2022
b18c976
Migration to a flutter 3 android compatible config.
MonsieurRz Apr 6, 2025
0337d81
updating gitignore from up-to-date template
MonsieurRz Apr 6, 2025
ebab62e
Updating Manifest according to current state of flutter_reactive_ble
MonsieurRz Apr 6, 2025
8a734f1
dart formatting
MonsieurRz Apr 6, 2025
6123646
migrate permission handling
MonsieurRz Apr 7, 2025
2035c47
adding static analysis
MonsieurRz Apr 7, 2025
f0e58f5
ignore vscode folder
MonsieurRz Apr 7, 2025
08a78bb
update permission handling
MonsieurRz Apr 12, 2025
6f8cbfa
change app title
MonsieurRz Apr 12, 2025
6d8f392
implement flutter_reactive_ble with previously existing method Ergom…
MonsieurRz Apr 12, 2025
4e3e92e
fixing flutter analyze
MonsieurRz Apr 12, 2025
5e47b81
first bluetooth tests making use of the mocktail library
MonsieurRz Apr 16, 2025
6805935
fixing workout value as futures
MonsieurRz Apr 16, 2025
d6ea2a8
Migration to a flutter 3 android compatible config.
MonsieurRz Apr 6, 2025
a54ba74
updating gitignore from up-to-date template
MonsieurRz Apr 6, 2025
2cba017
Updating Manifest according to current state of flutter_reactive_ble
MonsieurRz Apr 6, 2025
94069c6
migrate permission handling
MonsieurRz Apr 7, 2025
c67a08d
ignore vscode folder
MonsieurRz Apr 7, 2025
5289074
fixing workout value as futures
MonsieurRz Apr 16, 2025
aeb59f1
first bluetooth tests making use of the mocktail library
MonsieurRz Apr 16, 2025
1a42d30
implement flutter_reactive_ble with previously existing method Ergom…
MonsieurRz Apr 12, 2025
265e494
fixing flutter analyze
MonsieurRz Apr 12, 2025
712b34b
fix all flutter analyze issues to have branch stabilized
MonsieurRz Apr 22, 2025
fda8184
removing unused import
MonsieurRz Apr 26, 2025
26a8dae
adding mocktail test for ErgBleManager
MonsieurRz Apr 26, 2025
53b1fc5
fixing issue where subscribtion is triggered when scaning
MonsieurRz Apr 26, 2025
02ce312
explicitely telling the output are Ergometer objects
MonsieurRz Apr 26, 2025
51df352
Single instance of FlutterReactiveBle in memory owned by ErgBleManager
MonsieurRz Apr 29, 2025
1b9ef41
Allow testing when using a mock in place of the reactive package
MonsieurRz Apr 29, 2025
8e2685a
keep track of all Ergometer objects and ensure they are cleared from …
MonsieurRz Apr 30, 2025
dc751c8
Monitor the status of the bluetooth on the device
MonsieurRz Apr 30, 2025
61295d6
Single instance of FlutterReactiveBle in memory owned by ErgBleManager
MonsieurRz Apr 29, 2025
09bd6bb
Allow testing when using a mock in place of the reactive package
MonsieurRz Apr 29, 2025
f1a3ad8
keep track of all Ergometer objects and ensure they are cleared from …
MonsieurRz Apr 30, 2025
e2909e1
Monitor the status of the bluetooth on the device
MonsieurRz Apr 30, 2025
aa4e6b0
adding mocktail test for ErgBleManager
MonsieurRz Apr 26, 2025
015c348
fixing mock for statusStream
MonsieurRz Apr 30, 2025
c8e88f0
removing typo
MonsieurRz Apr 30, 2025
0760592
create public exception to handle edge cases
MonsieurRz Apr 30, 2025
07ec234
throw C2Connection error when a connection problem occurs
MonsieurRz Apr 30, 2025
d5cbce1
keep the connection Stream so we can dispose of it for disconnection
MonsieurRz May 1, 2025
5df0852
New example
MonsieurRz May 1, 2025
348ba98
Renaming fresh_example to c2bluetooth_example
MonsieurRz May 2, 2025
a4518b3
Complete overhaul of the example app to be very simple and clean
MonsieurRz May 2, 2025
e7bfe01
updating example's readme
MonsieurRz May 2, 2025
fec8565
fixing some readme issues
MonsieurRz May 2, 2025
2290991
Merge branch 'reactive-rewrite' into dataplex-api
MonsieurRz May 5, 2025
6b754ff
using a map rather than a switch for readability
MonsieurRz May 6, 2025
2a1c57f
renaming characteristic to resemble the documentation
MonsieurRz May 10, 2025
90087df
adding remaining characteristics constants
MonsieurRz May 10, 2025
427f36e
use streamcontrollers to be more flexible during testing
MonsieurRz May 11, 2025
76ab247
test packet parser
MonsieurRz May 11, 2025
76ee32b
test dataplex
MonsieurRz May 11, 2025
79e7040
adding stroke data
MonsieurRz May 11, 2025
247b8e2
fixing index error
MonsieurRz May 12, 2025
07a4967
testing strokeData2
MonsieurRz May 12, 2025
ca40ed3
WORK -> ENERGY
MonsieurRz May 13, 2025
1d21d99
fix concurrent modification occuring in dataplex dispose
MonsieurRz May 13, 2025
d514d1d
allow mock test for parsePacket
MonsieurRz May 13, 2025
9e493bf
test dataplex outgoing stream
MonsieurRz May 13, 2025
4927012
addSubscription just in time for stream creation and the ergometer is…
MonsieurRz May 13, 2025
220d925
improving test information
MonsieurRz May 13, 2025
3fb292d
typo
MonsieurRz May 13, 2025
1f36cdb
fixing some definitions
MonsieurRz May 15, 2025
5ef8f25
fixing value on DurationType enum
MonsieurRz May 15, 2025
60734c3
adding StatusData definitions
MonsieurRz May 15, 2025
8d28767
log unkown packet data as list of RadixString
MonsieurRz May 15, 2025
54739df
adding StatusData3
MonsieurRz May 16, 2025
d36f09b
removing stuff that wasn't supposed to be pushed
MonsieurRz May 16, 2025
a46a541
fix: screen number is an integer
MonsieurRz May 16, 2025
c26f13f
install reactive_ble
MoralCode Nov 11, 2022
0233168
first pass at migrating bluetooth scanning over to reactive ble
MoralCode Nov 11, 2022
665f8ca
update connection and IO related stuff to use reactive
MoralCode Nov 11, 2022
5fb52f8
add flutterReactiveBle class
MoralCode Nov 11, 2022
40d01b0
combine MonitorConnectionState with connection function
MoralCode Nov 11, 2022
6d93fcb
converted to reactive calls and removed various errors
Aldaniee Nov 12, 2022
7b78be1
make flutterReactiveBle property private
MoralCode Nov 12, 2022
f49aa73
fix other uses of the flutterReactiveBle field
MoralCode Nov 15, 2022
32484a3
bump minsdkversion on android to make the example app compile
MoralCode Nov 15, 2022
c8f5b4d
remove now-unused flutter_ble_lib dependency
MoralCode Nov 15, 2022
65ce5cc
add android bluetooth permissions to demo app
MoralCode Nov 15, 2022
7982926
other android build parameter changes
MoralCode Nov 15, 2022
058fa9c
request permissions android
MoralCode Nov 15, 2022
3595f01
misc updates to settings, mainly concerning hooking up cocoapods
MoralCode Nov 16, 2022
0c9d457
xcode recommended updates
MoralCode Nov 16, 2022
9477b81
commit podfile
MoralCode Nov 16, 2022
f942488
fixed scanning issue and added scan button
Aldaniee Nov 16, 2022
516acbd
code cleaning
Aldaniee Nov 17, 2022
16a09b0
missed setState
Aldaniee Nov 17, 2022
c072ed7
some updates to README
MoralCode Nov 16, 2022
5beb2bd
ignore use of old deprecated functions
MoralCode Nov 17, 2022
2148c79
misc formatting
MoralCode Nov 17, 2022
3f8194a
unused import
MoralCode Nov 18, 2022
ba901c8
add location permission to android manifest
MoralCode Nov 19, 2022
544b133
remove old doc comment
MoralCode Nov 19, 2022
652ce65
update doc comments for Ergometer and ErgBleManager to account for ne…
MoralCode Nov 19, 2022
a728817
update READMEs to reflect the newer version of the demo app
MoralCode Nov 19, 2022
9633248
update scanning to work more asynchronously
MoralCode Nov 19, 2022
4a1d951
updates to standalone docs
MoralCode Nov 19, 2022
4d58051
add a deprecation notice to monitorForWorkoutSummary
MoralCode Nov 19, 2022
929d83c
Migration to a flutter 3 android compatible config.
MonsieurRz Apr 6, 2025
5431a70
deriving timestamp
MonsieurRz May 17, 2025
4816388
fixing mux mapping
MonsieurRz May 17, 2025
417e877
adding belt packet
MonsieurRz May 17, 2025
4e361db
adding WorkoutSummaryPacke2
MonsieurRz May 17, 2025
499be44
fixing key to work distance
MonsieurRz May 17, 2025
f0d1a06
adding workout distance
MonsieurRz May 17, 2025
c7cc3bd
adding raw packet data print in debug mode
MonsieurRz May 17, 2025
c3917ef
adding raw packet print only on debug
MonsieurRz May 17, 2025
d3cfca3
Merge remote-tracking branch 'upstream/reactive-rewrite' into reactiv…
MonsieurRz May 18, 2025
cacd528
Merge remote-tracking branch 'origin/reactive-rewrite' into dataplex-api
MonsieurRz May 19, 2025
fdc3771
bumping setup-dart and flutter-action versions
MonsieurRz May 19, 2025
b029373
defer subscription until after device connection
MonsieurRz May 20, 2025
c1161cf
fix: there is no known enum to SCREENNUMBER
MonsieurRz May 20, 2025
aefcd7e
display debugging when calling these mocks
MonsieurRz May 20, 2025
37bc3be
verify specific subscriptions call
MonsieurRz May 20, 2025
eff7c05
fixing documentation
MonsieurRz May 20, 2025
cbaca2a
imrpoving readability for fake data
MonsieurRz May 22, 2025
e25d948
moving test to mimic library architecture
MonsieurRz May 22, 2025
04faa83
improving coherence
MonsieurRz May 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ jobs:
# https://github.com/dart-lang/setup-dart/blob/main/README.md
- uses: dart-lang/setup-dart@v1
with:
sdk: 3.1.3
sdk: stable

- uses: subosito/flutter-action@v1
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version: 3.13.0
flutter-version: 3.19.0

- name: Install dependencies
run: flutter pub get
Expand Down
137 changes: 129 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Do not remove or rename entries in this file, only add new ones
# See https://github.com/flutter/flutter/issues/128635 for more context.

# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
Expand All @@ -15,26 +19,143 @@
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Visual Studio Code related
.classpath
.project
.settings/
.vscode/
.ccls-cache

# This file, on the master branch, should never exist or be checked-in.
#
# On a *final* release branch, that is, what will ship to stable or beta, the
# file can be force added (git add --force) and checked-in in order to effectively
# "pin" the engine artifact version so the flutter tool does not need to use git
# to determine the engine artifacts.
#
# See https://github.com/flutter/flutter/blob/main/docs/tool/Engine-artifacts.md.
/bin/internal/engine.version

# Flutter repo-specific
/bin/cache/
/bin/internal/bootstrap.bat
/bin/internal/bootstrap.sh
/bin/internal/engine.realm
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/devicelab/ABresults*.json
/dev/docs/doc/
/dev/docs/api_docs.zip
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
analysis_benchmark.json

# packages file containing multi-root paths
.packages.generated

# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-preload-cache/
.pub-cache/
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds

# Android related
**/android/**/gradle-wrapper.jar
.gradle/
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
local.properties
**/.cxx/

# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/.last_build_id
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/ephemeral
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*

# macOS
**/Flutter/ephemeral/
**/Pods/
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/ephemeral
**/xcuserdata/

# Windows
**/windows/flutter/ephemeral/
**/windows/flutter/generated_plugin_registrant.cc
**/windows/flutter/generated_plugin_registrant.h
**/windows/flutter/generated_plugins.cmake

# Linux
**/linux/flutter/ephemeral/
**/linux/flutter/generated_plugin_registrant.cc
**/linux/flutter/generated_plugin_registrant.h
**/linux/flutter/generated_plugins.cmake

# Coverage
coverage/

# Symbols
app.*.symbols

## Custom stuff
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
!.vscode/settings.json

coverage/
# Monorepo
.cipd
.gclient
.gclient_entries
.python-version
.gclient_previous_custom_vars
.gclient_previous_sync_commits
45 changes: 34 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
C2Bluetooth is a flutter package designed to provide an easy API for accessing data from Concept2 PM5 Indoor fitness machines via bluetooth. This library implements the [Concept2 Performance Monitor Bluetooth Smart Communications Interface Definition](https://www.concept2.com/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf) Specification ([newer versions](https://www.c2forum.com/viewtopic.php?f=15&t=193697#p527068) are also available). It also relies heavily on the [CSAFE specification](https://web.archive.org/web/20060718175014/http://www.fitlinxx.com/csafe/specification.htm) from FitLinxx.

## Demo
This package comes with a demo app in the `example/` directory.

![A demo showing the distance completed after a workout](docs/images/demo/demo1-small.jpg)
See the [`example/README.md`](example/README.md) for more detailed information about the demo app and how to use it.

This is a relatively old screenshot of the included example app using an older version of the library to display the completed distance from a short 20-second test workout. Many improvements to expose more datapoints have been made since this screenshot was taken.
## Key Features
## Key Library Features

Currently this library supports a few basic features such as:
- retrieving workout summary information from the erg after a workout
Expand Down Expand Up @@ -45,7 +45,6 @@ Similar to how the underlying bluetooth library works, pretty much everything be

```dart
ErgBleManager bleManager = ErgBleManager();
bleManager.init(); //ready to go!
```
### Scanning for devices
Next, you need to start scanning for available devices. This uses a Stream to return an instance of the `Ergometer` class for each erg found. Each of these instances represents an erg and should be stored for later reuse as these act as the base upon which everything else (retrieving data, sending workouts .etc) is based.
Expand All @@ -55,27 +54,51 @@ Next, you need to start scanning for available devices. This uses a Stream to re
```dart
Ergometer myErg;

bleManager.startErgScan().listen((erg) {
StreamSubscription<Ergometer> ergScanStream = bleManager.startErgScan().listen((erg) {
//your code for detecting an erg here.
myErg = erg

//you can store the erg instance somewhere
myErg = erg;

//or connect to it (see later examples)

//or stop scanning
ergScanStream.cancel();

return erg;
});
```
This block of code is where you can do things like:
- determine what erg(s) you want to work with (this can be based on name, user choice, or basicaly anything)
- store the erg instance somewhere more permanent, like the `myErg` variable to allow you to be able to access it after you stop scanning.
- call `bleManager.stopErgScan()` if you know you are done scanning early. As an example, one way to immediately connect to the first erg found is to unconditionally call `stopErgScan` within this function so the scan stops after the first erg is received. Don't forget to close the stream too!
- cancel the stream if you are done scanning.


### Connecting and disconnecting
Once you have the `Ergometer` instance for the erg you want to connect to, you can call `connectAndDiscover()` on it to connect.
Once you have the `Ergometer` instance for the erg you want to connect to, you can call `connectAndDiscover()` on it to connect. This will provide you with a stream indicating the connection state of the erg.

```dart
await myErg.connectAndDiscover();
StreamSubscription<Ergometer> ergConnectionStream = myErg.connectAndDiscover().listen((event) {
if(event == ErgometerConnectionState.connected) {
//do stuff here once the erg is connected
} else if (event == ErgometerConnectionState.disconnected) {
//handle disconnection here
}
}, onError: (Object error) {
// Handle a possible error
if (error is C2ConnectionException) {
//handle connection errors
} else if (error is C2BluetoothException) {
print("C2Bluetooth error: ${error.message}");
} else {
print("Unknown error: $error");
}
});
```

When you are done, make sure to disconnect from your erg:
When you are done, disconnect from your erg by cancelling the stream:
```dart
await myErg.disconnectOrCancel();
ergConnectionStream.cancel();
```

### Getting data from the erg
Expand Down
45 changes: 26 additions & 19 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,61 @@
This document is the starting point for learning more about the c2bluetooth API and inner workings at varying levels of detail:

- The broadest overview comes from using the API as documented in the README
- sections like [Overall API Design](#overall-api-design) explain some of the core concepts or goals that we wanted to achieve with the API.
- For people looking to get into the internals of c2bluetooth, the [Core API Concepts](#core-api-concepts) section below is a good mid-level overview of the various groups or categories of classes that are used in the API and what their purpose is.
- For summaries of how c2bluetooth works internally and all the things it "takes care of" for end users, see the [internals](internals.md) document
- sections like [Core Values](#core-values) help explain more of the "why" behind some of the design choices made in the API.
- The [Basic api details](#basic-api-details) section is a detailed, mid-level overview of as man aspects of the public API as posible and what their purpose is.
- For people looking to get into the internals of c2bluetooth or make contributions, see the [internals](internals.md) document.
- Obviously the most detailed explaination of how the code works comes from reading the code and inline comments themselves. It is helpful to understand the general goals first

## Terms used

"implementor" generally refers to users of this library. This is intended to be an audience of primarily other flutter developers looking to use this library in their apps.

## Overall API design

## Core values

These are some of the core values that were considered as part of the development of this library and forms the ethos/soul of the project. These should be used as general guidance when questions of scope or direction of the library are considered.

### The Silent Protector

This principle shares its name with the [popular meme template](https://knowyourmeme.com/memes/the-silent-protector) depicting a soldier kneeling over and protecting a sleeping child.

![A remix of the "silent protector" meme depicting c2bluetooth protecting the apps that use it from low-level details of bluetooth communications with a concept2 erg](../docs/images/silent-protector.jpg)

This is essentially a graphical analogy to represent the idea that this library aims to "take on" as much responsibility for abstracting low-level details and hiding away various "gotchas" and complexities of the Concept2 Bluetooth interface specification as possible.

To my knowledge this is not currently a software design principle found in the broader software industry. However I think it is an awesome way to explain the concept.

### Inspiration
In order for this library to be a good fit within the community and provide a good user experience for developers, the goal is to design the interface for this library after other existing libraries interfacing with Concept2 rowing machines. The libraries looked at were [Py3Row](https://github.com/droogmic/Py3Row) (Python, BSD-2), [BoutFitness/Concept2-SDK](https://github.com/BoutFitness/Concept2-SDK) (Swift, MIT), [ErgometerJS](https://github.com/tijmenvangulik/ErgometerJS) (Javascript, Apache 2).

There are likely more libraries like these available, but these were just the first few that were looked at based on a GitHub search.
There are likely more libraries like these available, but these were just the first few that were looked at based on a GitHub search at the time of writing.

### Object Oriented
These three examples all seem to use some kind of Class-based approach where a particular instance of an object represents a particular rowing machine and contains functions to make interaction with the machine easier, like getting data.
These three examples all seem to use some kind of object-oriented approach where a particular instance of an object represents a particular rowing machine and contains functions to make interaction with the machine easier, like getting data.

Designing the library in an object oriented way seemed to make the most sense given what other projects in the space seem to ave done. This should also should keep things relatively straightforward to program and maintain.
Designing the library in an object oriented way seemed to make the most sense given what other projects in the space seem to have done. This should also should keep things relatively straightforward to program and maintain.

### Subscription-based data access
Both BoutFitness/Concept2-SDK and ErgometerJS also seemed to have a way to asynchronously "subscribe" to get a callback when particular values change so the screen can be updated. Since the FlutterBleLib bluetooth library also exposes [Flutter streams](https://apgapg.medium.com/using-streams-in-flutter-62fed41662e4) for reading values in this way, it seems like a good choice to follow this model when exposing data about a PM5.
Both BoutFitness/Concept2-SDK and ErgometerJS also seemed to have a way to asynchronously "subscribe" to get a callback when particular values change so values being displayed on the screen in the implementors flutter app can be updated. Since many Flutter bluetooth libraries also expose notification data from bluetooth devices as [Flutter streams](https://apgapg.medium.com/using-streams-in-flutter-62fed41662e4), this seems like a good, clean way to expose data about a PM5.

#### Single Values
For getting single values from an erg, such as serial number, software and hardware version info, and other things that likely wont change that often, Streams may be unnecessary and it might be easier to have a simple synchronous interface for grabbing a value either from the erg or from somewhere in the memory allocated to the particular Erg object being used.

Whether or not this is actually a good solution is still TBD

<!-- ### Modularity
Since a lot of the architecture is already provided by FlutterBleLib and will likely just pass through most of the aspects of the existing bluetooth APIs, it seems like it may be useful to make this passthrough more explicit. By duplicating any of the types and methods exposed by FlutterBleLib this package will be be more able to maintain a stable API, even in the event that there is a technical need (or desire from users) to be able to change the underlying bluetooth implementation, potentially even grouping the methods that handle the actual bluetooth access into a class/interface. This is something whtat would be helpful to keep in mind during initial development but shouldn't take too much energy until later versions. -->



## Core API Concepts
## Basic API details

This library is built from a few core concepts, some of which are shared with the `csafe-fitness` library. These core concepts represent general groupings of classes that serve a particular purpose or abstract certain aspects of communicating with an erg.

These concepts are roughly divided up into "external" (i.e. those that are part of the libraries public API) and "internal". If you are just using the library in your app, the external concepts should be all you need. Anyone looking to contribute to this library might find the "internal" concepts helpful

### External Concepts
#### Data Objects
Data objects, like the WorkoutSummary class, are essentially wrappers around data provided by the PM and allow the data to be accessed as an object by an application.

Data objects are primarily one-way communication from a PM to your application.

Data objects are located in the `data` directory and represent a large chunk of the public API for c2bluetooth


#### Model Objects
This is a gairly general group of classes that represent various indoor rowing conceptsas objects for ease of use by applications looking to interact with ergs. Some examples of classses in this category are the `Ergometer` and `Workout` classes. Unlike Data Objects, they are intended to be able to enable bidirectional data flow. For example, an `Ergometer` object may have properties for getting data (like Data Objects) but also may contain methods like `sendWorkout()` that allow you to provide a `Workout` object to set up on the erg. `Workout` objects could also be returned by other methods as a way to represent a workout if needed.
This is a gairly general group of classes that represent various indoor rowing concepts (in the form of objects). Some examples of classses in this category are the `Ergometer` and `Workout` classes. Unlike Data Objects, they are intended to be able to enable bidirectional data flow. For example, an `Ergometer` object may have properties for getting data (such as Data Objects) but also may contain methods like `sendWorkout()` that allow you to provide a `Workout` object to set up on the erg. `Workout` objects could also be returned by other methods as a way to represent a workout.

Model objects are located in the `models` directory and represent a large chunk of the public API for c2bluetooth
Model objects are located in the `models` directory.
5 changes: 4 additions & 1 deletion docs/DesignDecisions.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Design Decisions

## Bluetooth Library
This library ultimately depends on some bluetooth library to function. Originally the plan was to use [flutter_blue](https://github.com/pauldemarco/flutter_blue) because thats the first [tutorial](https://lupyuen.github.io/pinetime-rust-mynewt/articles/flutter#bluetooth-le-services) I came across. However, after seeing how many open issues and PR's they still have, the decline evident in their contributor graph, [comments online](https://www.reddit.com/r/FlutterDev/comments/hm63uk/why_bluetooth_in_flutter_is_so_problematic/), and [an analysis on cauldron.io](https://cauldron.io/project/5134), I've decided to use [FlutterBleLib](https://github.com/dotintent/FlutterBleLib) instead since, even though it seems similarly unmaintained, it has less open issues and seems to have reached a later stage of maturity based on its version number being in the 2.X range, rather than the 0.X range.
This library ultimately depends on some bluetooth library to function. Originally the plan was to use [flutter_blue](https://github.com/pauldemarco/flutter_blue) because thats the first [tutorial](https://lupyuen.github.io/pinetime-rust-mynewt/articles/flutter#bluetooth-le-services) I came across at the time development was started on c2bluetooth. However, after seeing how many open issues and PR's they still have, the decline evident in their contributor graph, [comments online](https://www.reddit.com/r/FlutterDev/comments/hm63uk/why_bluetooth_in_flutter_is_so_problematic/), and [an analysis on cauldron.io](https://cauldron.io/project/5134), [FlutterBleLib](https://github.com/dotintent/FlutterBleLib) was briefly used instead, before the project ultimately switched to using [flutter_reactive_ble](https://github.com/PhilipsHue/flutter_reactive_ble) mainteined by Philips Hue because it seems to be the most likely to continue to be maintained into the future.


During the transition from FlutterBleLib to flutter_reactive_ble creating an interface to represent any bluetooth library was considered because it would give implementors the ability to use a bluetooth library that may already exist in their app. This would halp maintainers reduce app dependencies, app size, and conflicting libraries, but was ultimately never implemented because it would make the process of debugging implementor-reported issues reported against the library more difficult.

## CSAFE API Usage

Expand Down
Binary file added docs/images/demo/completed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/demo/connected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/demo/demo1-small.jpg
Binary file not shown.
Binary file added docs/images/demo/permission-denied.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/demo/pre-scan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/demo/scanning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/silent-protector.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading