Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 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
6bd2028
Initial connection with usb serial achieved, missing data formatting
MouradLachhab Oct 4, 2020
a44ca17
Merge branch 'bluetooth' into serial
MouradLachhab Oct 6, 2020
4a4fecd
Renamed serial port
MouradLachhab Oct 6, 2020
7561a4d
Moved back flutter instance into repository initialization and created
MouradLachhab Oct 6, 2020
e237995
Merge branch 'bluetooth' into serial
MouradLachhab Oct 8, 2020
f3719b6
Switched to AcquisitionDevice interface usage
MouradLachhab Oct 8, 2020
303a8df
Merge branch 'master' into serial
MouradLachhab Oct 12, 2020
c68745b
Seperated data formatting into stream transformer
MouradLachhab Oct 12, 2020
9c08814
Implemented Cyton transformer
MouradLachhab Oct 13, 2020
469cd05
Small convention changes and changed BaseTransformer to an abstract c…
MouradLachhab Oct 14, 2020
3b865b7
Made async function into future
MouradLachhab Oct 16, 2020
6abde11
Removed transformer interface
MouradLachhab Oct 16, 2020
b63d3b9
Dynamically changing repositories and transformers
MouradLachhab Oct 16, 2020
326db2e
Added missing file
MouradLachhab Oct 18, 2020
60cdf14
Fixed negative handling in cyton transformer and cleaned up a bit
MouradLachhab Oct 19, 2020
c252b57
Added unit testing
MouradLachhab Oct 19, 2020
254e647
Awaiting stream in serial
MouradLachhab Oct 19, 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
5 changes: 5 additions & 0 deletions mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
Expand Down
7 changes: 7 additions & 0 deletions mobile/android/app/src/main/res/xml/device_filter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<!-- 0x0403 / FTDI -->
<usb-device vendor-id="1027" />

</resources>
13 changes: 13 additions & 0 deletions mobile/lib/src/application/device/device_selector_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ 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 'package:streaming_shared_preferences/streaming_shared_preferences.dart';
import 'device_selector_state.dart';

class DeviceSelectorCubit extends Cubit<DeviceState> {
final IAcquisitionDeviceRepository _deviceRepository;

StreamSubscription<List<AcquisitionDevice>> _acquisitionDeviceStream;
// todo: remove this variable, also test that switch works correctly once UI is done
bool usingBluetooth = true;

DeviceSelectorCubit(this._deviceRepository) : super(DeviceInitial()) {
startSearching();
Expand Down Expand Up @@ -47,4 +50,14 @@ class DeviceSelectorCubit extends Cubit<DeviceState> {
_deviceRepository.disconnect();
startSearching();
}

// todo: change bluetooth preferences in the preference section of the app
void swapBluetooth() async {
print("swap");
usingBluetooth = !usingBluetooth;
StreamingSharedPreferences _prefs =
await StreamingSharedPreferences.instance;

_prefs.setBool('using_bluetooth', usingBluetooth);
}
Comment thread
MouradLachhab marked this conversation as resolved.
}
1 change: 1 addition & 0 deletions mobile/lib/src/application/eeg_data/data_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class DataCubit extends Cubit<DataState> {

Future<void> startStreaming() async {
emit(DataStateRecording());
_eegDataRepository.initialize();
_eegDataRepository
.createRecordingFromStream(await _deviceRepository.startDataStream());
}
Expand Down
1 change: 1 addition & 0 deletions mobile/lib/src/domain/eeg_data/i_eeg_data_repository.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
abstract class IEEGDataRepository {
void initialize();
void createRecordingFromStream(Stream<List<int>> stream);
void stopRecordingFromStream();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'dart:async';

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/infrastructure/connection_repositories/bluetooth_repository.dart';
import 'package:polydodo/src/infrastructure/connection_repositories/serial_repository.dart';
import 'package:streaming_shared_preferences/streaming_shared_preferences.dart';

class AcquisitionDeviceRepository implements IAcquisitionDeviceRepository {
final BluetoothRepository _bluetoothRepository = new BluetoothRepository();
final SerialRepository _serialRepository = new SerialRepository();
IAcquisitionDeviceRepository _currentRepository;

StreamSubscription _bluetoothStream;
StreamSubscription _serialStream;
StreamSubscription _currentStream;

StreamController<List<AcquisitionDevice>> _acquisitionDeviceController;
StreamingSharedPreferences _preferences;

AcquisitionDeviceRepository() {
_currentRepository = _serialRepository;
_acquisitionDeviceController = new StreamController();
}

Future<void> initializeRepository() async {
if (_preferences == null) {
_preferences = await StreamingSharedPreferences.instance;
_preferences
.getBool('using_bluetooth', defaultValue: false)
.listen((usingBluetooth) {
disconnect();
_currentStream.pause();
_currentRepository =
usingBluetooth ? _bluetoothRepository : _serialRepository;
_currentRepository.initializeRepository();
_currentStream = usingBluetooth ? _bluetoothStream : _serialStream;
_currentStream.resume();
});

_serialStream = _serialRepository.watch().listen((event) {
_acquisitionDeviceController.add(event);
});
_bluetoothStream = _bluetoothRepository.watch().listen((event) {
_acquisitionDeviceController.add(event);
});

_currentStream = _bluetoothStream;
_serialStream.pause();
}
}

void connect(AcquisitionDevice device, Function(bool, Exception) callback) {
_currentRepository.connect(device, callback);
}

void disconnect() {
_currentRepository.disconnect();
}

Future<Stream<List<int>>> startDataStream() {
return _currentRepository.startDataStream();
}

void stopDataStream() {
_currentRepository.stopDataStream();
}

Stream<List<AcquisitionDevice>> watch() {
return _acquisitionDeviceController.stream;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import 'dart:async';
import 'package:flutter_reactive_ble/flutter_reactive_ble.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/infrastructure/constants.dart';
import 'package:polydodo/src/domain/unique_id.dart';

class BluetoothRepository implements IAcquisitionDeviceRepository {
static const String BLE_SERVICE = "0000fe84-0000-1000-8000-00805f9b34fb";
static const String BLE_RECEIVE = "2d30c082-f39f-4ce6-923f-3484ea480596";
static const String BLE_SEND = "2d30c083-f39f-4ce6-923f-3484ea480596";
static const startStreamChar = 'b';
static const stopStreamChar = 's';

AcquisitionDevice _selectedDevice;
QualifiedCharacteristic _sendCharacteristic;
Expand All @@ -22,8 +21,6 @@ class BluetoothRepository implements IAcquisitionDeviceRepository {
List<AcquisitionDevice> _acquisitionDevicePersistency = [];
final streamController = StreamController<List<AcquisitionDevice>>();

BluetoothRepository();

void initializeRepository() {
if (_bluetoothScanSubscription == null) {
flutterReactiveBle = FlutterReactiveBle();
Expand All @@ -32,6 +29,7 @@ class BluetoothRepository implements IAcquisitionDeviceRepository {
withServices: []).listen((device) => addDevice(device));
} else {
_bluetoothScanSubscription.resume();
_acquisitionDevicePersistency.clear();
}
}

Expand Down Expand Up @@ -72,10 +70,8 @@ class BluetoothRepository implements IAcquisitionDeviceRepository {
}

void disconnect() async {
if (_selectedDevice != null) {
_selectedDevice = null;
_connectedDeviceStream.cancel();
}
_selectedDevice = null;
_connectedDeviceStream?.cancel();
}

void setupCharacteristics() async {
Expand All @@ -96,7 +92,7 @@ class BluetoothRepository implements IAcquisitionDeviceRepository {
priority: ConnectionPriority.highPerformance);

flutterReactiveBle.writeCharacteristicWithoutResponse(_sendCharacteristic,
value: startStreamChar.codeUnits);
value: START_STREAM_CHAR.codeUnits);

return flutterReactiveBle.subscribeToCharacteristic(_receiveCharacteristic);
}
Expand All @@ -106,7 +102,7 @@ class BluetoothRepository implements IAcquisitionDeviceRepository {
deviceId: _selectedDevice.id.toString(),
priority: ConnectionPriority.balanced);
flutterReactiveBle.writeCharacteristicWithoutResponse(_sendCharacteristic,
value: stopStreamChar.codeUnits);
value: STOP_STREAM_CHAR.codeUnits);
}

@override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:csv/csv.dart';
import 'package:path_provider/path_provider.dart';
import 'package:polydodo/src/domain/eeg_data/eeg_data.dart';
import 'package:polydodo/src/domain/eeg_data/i_eeg_data_repository.dart';
import 'package:polydodo/src/domain/unique_id.dart';
import 'package:polydodo/src/infrastructure/eeg_data_transformers/baseOpenBCITransformer.dart';
import 'package:polydodo/src/infrastructure/eeg_data_transformers/cytonTransformer.dart';
import 'package:polydodo/src/infrastructure/constants.dart';
import 'package:polydodo/src/infrastructure/eeg_data_transformers/ganglionTransformer.dart';
import 'package:streaming_shared_preferences/streaming_shared_preferences.dart';

class EEGDataRepository implements IEEGDataRepository {
EEGData _recordingData;
BaseOpenBCITransformer<List<int>, List<dynamic>> currentStreamTransformer;

final GanglionTransformer<List<int>, List> _ganglionTransformer =
new GanglionTransformer<List<int>, List>.broadcast();

final CytonTransformer<List<int>, List<dynamic>> _cytonTransformer =
new CytonTransformer<Uint8List, List>.broadcast();

BaseOpenBCITransformer<List<int>, List<dynamic>> _currentTransformer;
StreamSubscription _currentTransformerStream;

StreamingSharedPreferences _preferences;

void initialize() async {
if (_preferences == null) {
_preferences = await StreamingSharedPreferences.instance;
}

_currentTransformer =
_preferences.getBool('using_bluetooth', defaultValue: false).getValue()
? _ganglionTransformer
: _cytonTransformer;
}

void createRecordingFromStream(Stream<List<int>> stream) {
_recordingData =
EEGData(UniqueId.from(DateTime.now().toString()), List<List>());

_currentTransformer.reset();
_currentTransformerStream = stream
.asBroadcastStream()
.transform(_currentTransformer)
.listen((data) => _recordingData.values.add(data));
}

Future<void> stopRecordingFromStream() async {
// todo: move save future to another file
_currentTransformerStream.cancel();

final directory = await getExternalStorageDirectory();
final pathOfTheFileToWrite =
directory.path + '/' + _recordingData.fileName + ".txt";
File file = File(pathOfTheFileToWrite);
List<List> fileContent = [];
//todo: dynamically change header when we change transformer
fileContent.addAll(OPEN_BCI_CYTON_HEADER);
fileContent.addAll(_recordingData.values);
String csv = const ListToCsvConverter().convert(fileContent);
await file.writeAsString(csv);
}

// todo: implement export and import
void importData() {}
void exportData() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'dart:async';
import 'dart:typed_data';

import 'package:polydodo/src/domain/unique_id.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/infrastructure/constants.dart';
import 'package:usb_serial/usb_serial.dart';

class SerialRepository implements IAcquisitionDeviceRepository {
UsbDevice _selectedDevice;
UsbPort _serialPort;
List<AcquisitionDevice> _acquisitionDevicePersistency = [];
List<UsbDevice> _serialDevices = [];
final streamController = StreamController<List<AcquisitionDevice>>();

void initializeRepository() {
_acquisitionDevicePersistency.clear();
_serialDevices.clear();
UsbSerial.listDevices().then((devices) => addDevices(devices));
}

void addDevices(List<UsbDevice> serialDevices) {
for (UsbDevice serialDevice in serialDevices) {
AcquisitionDevice device = AcquisitionDevice(
UniqueId.from(serialDevice.deviceId.toString()),
serialDevice.productName);

_acquisitionDevicePersistency.add(device);
_serialDevices.add(serialDevice);
}
streamController.add(_acquisitionDevicePersistency);
}

Future<void> connect(
AcquisitionDevice device, Function(bool, Exception) callback) async {
_selectedDevice =
_serialDevices[_acquisitionDevicePersistency.indexOf(device)];
_serialPort = await _selectedDevice.create();
bool openSuccessful = await _serialPort.open();

if (!openSuccessful) {
callback(false, Exception("Could not open port"));
}

_serialPort.setPortParameters(
115200, UsbPort.DATABITS_8, UsbPort.STOPBITS_1, UsbPort.PARITY_NONE);
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.


callback(true, null);
}

Future<void> disconnect() async {
await _serialPort?.close();
_selectedDevice = null;
_serialPort = null;
}

Future<Stream<List<int>>> startDataStream() async {
await _serialPort.write(Uint8List.fromList(START_STREAM_CHAR.codeUnits));

return _serialPort.inputStream;
}

Future<void> stopDataStream() async {
await _serialPort.write(Uint8List.fromList(STOP_STREAM_CHAR.codeUnits));
}

Stream<List<AcquisitionDevice>> watch() => streamController.stream;
}
Loading