Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a37c04
Add base Flutter dependencies
abelfodil Sep 13, 2020
65cf38d
Bump minimal android sdk version
abelfodil Sep 14, 2020
0c53add
Increment and decrement with counter cubit & create main/app/locator …
Sep 15, 2020
8697b35
create and implement domain layer
Sep 15, 2020
38e939e
Connection bluetooth avec le ganglion
MouradLachhab Sep 17, 2020
15e4ab8
Create Flutter code structure example based on this [arch](https://gi…
Sep 19, 2020
ff2854f
Merge branch 'master' of https://github.com/PolyCortex/polydodo into …
Sep 19, 2020
428d554
Remove widget test specific to counter app
Sep 19, 2020
118ed85
Create an empty test for pipeline to perform build
Sep 19, 2020
baebeab
Create an empty test in order for build pipeline to pass
Sep 19, 2020
0c23975
fix mistake: move test/ under mobile/
Sep 19, 2020
37b8cc2
Requete de donnees et enregistrement sur csv
MouradLachhab Sep 20, 2020
a756532
Changement du format du fichier output pour openBCI
MouradLachhab Sep 23, 2020
6c66e52
Merge remote-tracking branch 'remotes/origin/base-arch-structure' int…
MouradLachhab Sep 23, 2020
c7929d5
Fixed some duplicates
MouradLachhab Sep 23, 2020
6663be0
Merge branch 'base-arch-structure' into bluetooth
MouradLachhab Sep 24, 2020
0809597
Finished updating bluetooth files. Missing csv feature
MouradLachhab Sep 24, 2020
437ff84
Added recording feature
MouradLachhab Sep 24, 2020
dd515c8
Removed main2 temporary file
MouradLachhab Sep 24, 2020
8a56384
Removed unecessary prints
MouradLachhab Sep 28, 2020
475aef0
Extracted variable and renamed for clarity
MouradLachhab Sep 28, 2020
3468343
Removed unecessary imports and exposed methods in bluetooth interface
MouradLachhab Sep 28, 2020
9680850
Removed unecessary bluetooth from domain
MouradLachhab Sep 28, 2020
71c36f2
Created eeg data repository
MouradLachhab Sep 28, 2020
6985672
Changed string id to UniqueID, fixed state inconsistency
MouradLachhab Sep 29, 2020
3bead5f
Fixed typo, removed unecessary delay
MouradLachhab Sep 30, 2020
5cd7bf4
Merging Master into bluetooth
MouradLachhab Oct 1, 2020
707a85f
format
abelfodil Oct 1, 2020
3c67918
Fixed typo
MouradLachhab Oct 1, 2020
80f22c5
Merge branch 'bluetooth' of https://github.com/PolyCortex/polydodo in…
MouradLachhab Oct 1, 2020
82c7b1e
Removed general export files in favor of individual import
MouradLachhab Oct 1, 2020
798d10a
Added missing files for last commit
MouradLachhab Oct 1, 2020
dd694c5
Extracted openbci header and only adding it at export time
MouradLachhab Oct 1, 2020
d9a554a
Added error handling for failed connections
MouradLachhab Oct 1, 2020
226d8e6
Handling already connected error and cleaned slightly findCharacteris…
MouradLachhab Oct 1, 2020
2af1964
Merge branch 'master' into bluetooth
MouradLachhab Oct 2, 2020
b4192ad
Switched to generic acquisiton device in application layer
MouradLachhab Oct 3, 2020
6a6edd6
Merge branch 'bluetooth' of https://github.com/PolyCortex/polydodo in…
MouradLachhab Oct 3, 2020
b95d5b2
Reverted merge with master
MouradLachhab Oct 3, 2020
351c57b
Added handling for packet id 0 and fixed data values
MouradLachhab Oct 3, 2020
bc62be0
Returning Container in view instead of new ListView
MouradLachhab Oct 3, 2020
6056901
Remove default formatter for workspace because it prevents dartfmt to…
Oct 3, 2020
436aa8e
Merge branch 'bluetooth' of https://github.com/PolyCortex/polydodo in…
Oct 3, 2020
7a463c1
Reset esbenp.prettier-vscode as default formatter, but specified dart…
Oct 3, 2020
bbe2475
Changes based on last pull request comments (injecting flutter blue i…
MouradLachhab Oct 4, 2020
fdda64d
Changed Acquisition initialization method to more generic name instea…
MouradLachhab Oct 4, 2020
7561a4d
Moved back flutter instance into repository initialization and created
MouradLachhab Oct 6, 2020
c1c192b
Fix conflicts
abelfodil Oct 8, 2020
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
4 changes: 4 additions & 0 deletions mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@
android:name="flutterEmbedding"
android:value="2" />
</application>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Comment thread
conorato marked this conversation as resolved.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
3 changes: 1 addition & 2 deletions mobile/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';

import 'src/app.dart';

void main() async {
void main() {
runApp(App());
}
7 changes: 4 additions & 3 deletions mobile/lib/src/app.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:polydodo/src/presentation/bluetooth_route/bluetoothSelector_route.dart';
import 'package:polydodo/src/presentation/wallets/wallets_route.dart';

import 'presentation/wallets/wallets_route.dart';
import 'locator.dart';
import 'theme.dart';

Expand All @@ -18,10 +19,10 @@ class App extends StatelessWidget {
child: MaterialApp(
title: 'PolyDodo',
theme: theme,
home: WalletsRoute(),
initialRoute: WalletsRoute.name,
initialRoute: BluetoothSelectorRoute.name,
routes: {
WalletsRoute.name: (context) => WalletsRoute(),
BluetoothSelectorRoute.name: (context) => BluetoothSelectorRoute(),
},
),
);
Expand Down
45 changes: 45 additions & 0 deletions mobile/lib/src/application/device/device_selector_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:polydodo/src/domain/acquisition_device/acquisition_device.dart';
import 'package:polydodo/src/domain/acquisition_device/i_acquisition_device_repository.dart';
import 'device_selector_state.dart';

class DeviceSelectorCubit extends Cubit<DeviceState> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AcquisitionDeviceConnectionCubit? et le state devrait reprendre le nom complet, même si c'est long, histoire de clareté (surtout que dans l'app on peut se ramasser avec beaucoup de noms semblable donc autant être précis 🎯 ). DeviceState => AcquisitionDeviceConnectionState.

final IAcquisitionDeviceRepository _deviceRepository;

StreamSubscription<List<AcquisitionDevice>> _acquisitionDeviceStream;

DeviceSelectorCubit(this._deviceRepository) : super(DeviceInitial()) {
startSearching();
}

void startSearching() {
_deviceRepository.initializeRepository();

if (_acquisitionDeviceStream == null) {
_acquisitionDeviceStream = _deviceRepository
.watch()
.asBroadcastStream()
.listen((devices) => emit(DeviceSearchInProgress(devices)),
onError: (e) => emit(DeviceSearchFailure(e)));
}
}

void connect(AcquisitionDevice device) async {
emit(DeviceConnectionInProgress());

_deviceRepository.connect(device).then(
(value) => {
_acquisitionDeviceStream.cancel(),
emit(DeviceConnectionSuccess())
},
onError: (e) => {emit(DeviceConnectionFailure(e)), resetSearch()});
}

void resetSearch() {
_deviceRepository.disconnect();
startSearching();
}
}
27 changes: 27 additions & 0 deletions mobile/lib/src/application/device/device_selector_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:polydodo/src/domain/acquisition_device/acquisition_device.dart';

abstract class DeviceState {}

class DeviceInitial extends DeviceState {}

class DeviceSearchInProgress extends DeviceState {
final List<AcquisitionDevice> devices;

DeviceSearchInProgress(this.devices);
}

class DeviceSearchFailure extends DeviceState {
final Exception cause;

DeviceSearchFailure(this.cause);
}

class DeviceConnectionInProgress extends DeviceState {}

class DeviceConnectionSuccess extends DeviceState {}

class DeviceConnectionFailure extends DeviceState {
final Exception cause;

DeviceConnectionFailure(this.cause);
}
27 changes: 27 additions & 0 deletions mobile/lib/src/application/eeg_data/data_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:polydodo/src/domain/acquisition_device/i_acquisition_device_repository.dart';
import 'package:polydodo/src/domain/eeg_data/i_eeg_data_repository.dart';

import 'data_states.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class DataCubit extends Cubit<DataState> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EegDataRecordingCubit?

final IAcquisitionDeviceRepository _deviceRepository;
final IEEGDataRepository _eegDataRepository;

DataCubit(this._deviceRepository, this._eegDataRepository)
: super(DataStateInitial());

void startStreaming() {
emit(DataStateRecording());
_deviceRepository
.startDataStream()
.then((stream) => _eegDataRepository.createRecordingFromStream(stream));
}

void stopStreaming() {
emit(DataStateInitial());
_deviceRepository.stopDataStream();
_eegDataRepository.stopRecordingFromStream();
}
}
5 changes: 5 additions & 0 deletions mobile/lib/src/application/eeg_data/data_states.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
abstract class DataState {}

class DataStateInitial extends DataState {}

class DataStateRecording extends DataState {}
13 changes: 13 additions & 0 deletions mobile/lib/src/domain/acquisition_device/acquisition_device.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:equatable/equatable.dart';
import 'package:polydodo/src/domain/entity.dart';

import '../unique_id.dart';

class AcquisitionDevice extends Entity {
final String name;

AcquisitionDevice(
id,
this.name,
) : super(id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'acquisition_device.dart';

abstract class IAcquisitionDeviceRepository {
void initializeRepository();

Future<void> connect(AcquisitionDevice device);
void disconnect();

Future<Stream<List<int>>> startDataStream();
void stopDataStream();

Stream<List<AcquisitionDevice>> watch();
}
16 changes: 16 additions & 0 deletions mobile/lib/src/domain/eeg_data/eeg_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// EEGData can be extended later to add our metrics
import '../unique_id.dart';

class EEGData {
UniqueId id;
List<List> _values;
Comment thread
MouradLachhab marked this conversation as resolved.
int sampleCounter = 0;

EEGData(this.id, this._values)
: assert(id != null),
assert(_values != null);

List<List> get values => _values;

String get fileName => id.toString();
}
8 changes: 8 additions & 0 deletions mobile/lib/src/domain/eeg_data/i_eeg_data_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
abstract class IEEGDataRepository {
void createRecordingFromStream(Stream<List<int>> stream);
void stopRecordingFromStream();

// todo: implement export and import
void importData();
void exportData();
}
11 changes: 11 additions & 0 deletions mobile/lib/src/domain/entity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:equatable/equatable.dart';
import 'package:polydodo/src/domain/unique_id.dart';

abstract class Entity extends Equatable {
final UniqueId id;

Entity(this.id);

@override
List<Object> get props => [id];
}
2 changes: 1 addition & 1 deletion mobile/lib/src/domain/unique_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ class UniqueId extends Equatable {
List<Object> get props => [_id];

@override
bool get stringify => true;
toString() => _id;
}
135 changes: 135 additions & 0 deletions mobile/lib/src/infrastructure/bluetooth_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:polydodo/src/domain/acquisition_device/acquisition_device.dart';
import 'package:polydodo/src/domain/acquisition_device/i_acquisition_device_repository.dart';
import 'package:polydodo/src/domain/unique_id.dart';

class BluetoothRepository implements IAcquisitionDeviceRepository {
Comment thread
MouradLachhab marked this conversation as resolved.
static const String BLE_SERVICE = "fe84";
static const String BLE_RECEIVE = "2d30c082";
static const String BLE_SEND = "2d30c083";
static const startStreamChar = 'b';
static const stopStreamChar = 's';

BluetoothDevice _selectedDevice;
BluetoothCharacteristic _sendCharacteristic;
BluetoothCharacteristic _receiveCharacteristic;

FlutterBlue flutterBlue;
StreamSubscription<List<ScanResult>> _bluetoothScanSubscription;
List<AcquisitionDevice> _acquisitionDevicePersistency = [];
List<BluetoothDevice> _bluetoothDevices = [];
final streamController = StreamController<List<AcquisitionDevice>>();

BluetoothRepository();

void initializeRepository() {
if (_bluetoothScanSubscription == null) {
flutterBlue = FlutterBlue.instance;
Comment thread
MouradLachhab marked this conversation as resolved.

flutterBlue.connectedDevices
.asStream()
.asBroadcastStream()
.listen((List<BluetoothDevice> devices) {
for (BluetoothDevice device in devices) {
addDevice(device);
}
});
_bluetoothScanSubscription =
flutterBlue.scanResults.listen((List<ScanResult> results) {
for (ScanResult result in results) {
addDevice(result.device);
}
});
} else {
_bluetoothScanSubscription.resume();
}
flutterBlue.startScan();
}

void addDevice(BluetoothDevice bluetoothDevice) {
AcquisitionDevice device = AcquisitionDevice(
UniqueId.from(bluetoothDevice.id.toString()), bluetoothDevice.name);

final idx = _acquisitionDevicePersistency.indexOf(device);

if (idx == -1) {
_acquisitionDevicePersistency.add(device);
_bluetoothDevices.add(bluetoothDevice);
} else {
_acquisitionDevicePersistency[idx] = device;
_bluetoothDevices[idx] = bluetoothDevice;
}

streamController.add(_acquisitionDevicePersistency);
}

Future<void> connect(AcquisitionDevice device) async {
_selectedDevice =
_bluetoothDevices[_acquisitionDevicePersistency.indexOf(device)];

_acquisitionDevicePersistency.clear();
_bluetoothDevices.clear();
_bluetoothScanSubscription.pause();
flutterBlue.stopScan();

try {
await _selectedDevice
.connect()
.then((value) => findRelevantCharacteristics())
.timeout(Duration(seconds: 6),
onTimeout: () =>
{disconnect(), throw Exception("Connection Timed out")});
} catch (e) {
if (e is PlatformException) {
if (e.code != "already_connected") throw Exception(e.details);
} else
throw e;
}

return;
}

void disconnect() async {
if (_selectedDevice != null) {
await _selectedDevice.disconnect();
_selectedDevice = null;
}
}

void findRelevantCharacteristics() {
_selectedDevice.discoverServices().then((services) => {
for (BluetoothCharacteristic characteristic in (services.where(
(service) => service.uuid.toString().contains(BLE_SERVICE)))
.first
.characteristics)
{
if (characteristic.uuid.toString().contains(BLE_RECEIVE))
{_receiveCharacteristic = characteristic}
else if (characteristic.uuid.toString().contains(BLE_SEND))
{_sendCharacteristic = characteristic}
},
if (_receiveCharacteristic == null)
throw Exception('Device is missing receive Characteristic'),
if (_sendCharacteristic == null)
throw Exception('Device is missing send Characteristic')
});
}

Future<Stream<List<int>>> startDataStream() async {
await _receiveCharacteristic.setNotifyValue(true);

await _sendCharacteristic.write(startStreamChar.codeUnits);
return _receiveCharacteristic.value;
}

void stopDataStream() async {
await _receiveCharacteristic.setNotifyValue(false);
await _sendCharacteristic.write(stopStreamChar.codeUnits);
}

@override
Stream<List<AcquisitionDevice>> watch() => streamController.stream;
}
23 changes: 23 additions & 0 deletions mobile/lib/src/infrastructure/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const OPEN_BCI_HEADER = [
["%OpenBCI Raw EEG Data"],
["%Number of channels = 4"],
["%Sample Rate = 200 Hz"],
["%Board = OpenBCI_GUI\$BoardGanglionBLE"],
[
"Sample Index",
" EXG Channel 0",
" EXG Channel 1",
" EXG Channel 2",
" EXG Channel 3",
" Accel Channel 0",
" Accel Channel 1",
" Accel Channel 2",
" Other",
" Other",
" Other",
" Other",
" Other",
" Timestamp",
" Timestamp (Formatted)"
]
];
Loading