Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion mobile/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ android {

defaultConfig {
applicationId "com.PolyCortex.Polydodo"
minSdkVersion 19
minSdkVersion 24
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
3 changes: 0 additions & 3 deletions mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,5 @@
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"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
2 changes: 1 addition & 1 deletion mobile/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>10.0</string>
</dict>
</plist>
6 changes: 3 additions & 3 deletions mobile/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand Down Expand Up @@ -354,7 +354,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -403,7 +403,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand Down
13 changes: 8 additions & 5 deletions mobile/lib/src/application/device/device_selector_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ class DeviceSelectorCubit extends Cubit<DeviceState> {
Future<void> connect(AcquisitionDevice device) async {
emit(DeviceConnectionInProgress());

try {
await _deviceRepository.connect(device);
_acquisitionDeviceStream.cancel();
emit(DeviceConnectionSuccess());
} catch (e) {
_deviceRepository.connect(device, connectionCallback);
}

void connectionCallback(bool connected, Exception e) {
if (e != null) {
emit(DeviceConnectionFailure(e));
resetSearch();
} else if (connected) {
_acquisitionDeviceStream.cancel();
emit(DeviceConnectionSuccess());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'acquisition_device.dart';
abstract class IAcquisitionDeviceRepository {
void initializeRepository();

Future<void> connect(AcquisitionDevice device);
void connect(AcquisitionDevice device, Function(bool, Exception) callback);
void disconnect();

Future<Stream<List<int>>> startDataStream();
Expand Down
3 changes: 1 addition & 2 deletions mobile/lib/src/domain/eeg_data/eeg_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import 'package:polydodo/src/domain/entity.dart';

class EEGData extends Entity {
List<List> _values;
int sampleCounter = 0;
final List<List> _values;

EEGData(id, this._values)
: assert(_values != null),
Expand Down
127 changes: 55 additions & 72 deletions mobile/lib/src/infrastructure/bluetooth_repository.dart
Original file line number Diff line number Diff line change
@@ -1,129 +1,112 @@
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart';
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/domain/unique_id.dart';

class BluetoothRepository implements IAcquisitionDeviceRepository {
static const String BLE_SERVICE = "fe84";
static const String BLE_RECEIVE = "2d30c082";
static const String BLE_SEND = "2d30c083";
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';

BluetoothDevice _selectedDevice;
BluetoothCharacteristic _sendCharacteristic;
BluetoothCharacteristic _receiveCharacteristic;
AcquisitionDevice _selectedDevice;
QualifiedCharacteristic _sendCharacteristic;
QualifiedCharacteristic _receiveCharacteristic;

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

BluetoothRepository();

void initializeRepository() {
if (_bluetoothScanSubscription == null) {
flutterBlue = FlutterBlue.instance;

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);
}
});
flutterReactiveBle = FlutterReactiveBle();

_bluetoothScanSubscription = flutterReactiveBle.scanForDevices(
withServices: []).listen((device) => addDevice(device));
} else {
_bluetoothScanSubscription.resume();
}
flutterBlue.startScan();
}

void addDevice(BluetoothDevice bluetoothDevice) {
void addDevice(DiscoveredDevice 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)];

void connect(
AcquisitionDevice device, Function(bool, Exception) callback) async {
_selectedDevice = device;
_acquisitionDevicePersistency.clear();
_bluetoothDevices.clear();
_bluetoothScanSubscription.pause();
flutterBlue.stopScan();

try {
await _selectedDevice.connect().timeout(Duration(seconds: 6),
onTimeout: () =>
{disconnect(), throw Exception("Connection Timed out")});

await findRelevantCharacteristics();
} catch (e) {
if (e is PlatformException) {
if (e.code != "already_connected") throw Exception(e.details);
} else
throw e;
}

_connectedDeviceStream = flutterReactiveBle
.connectToDevice(
id: _selectedDevice.id.toString(),
connectionTimeout: Duration(seconds: 10))
.listen((event) {
if (event.connectionState == DeviceConnectionState.connected) {
setupCharacteristics();
callback(true, null);
} else if (event.connectionState == DeviceConnectionState.disconnected) {
disconnect();
callback(false, Exception("Failed to connect to device"));
}
});
}

Future<void> disconnect() async {
void disconnect() async {
if (_selectedDevice != null) {
await _selectedDevice.disconnect();
_selectedDevice = null;
_connectedDeviceStream.cancel();
}
}

Future<void> findRelevantCharacteristics() async {
var characteristics = (await _selectedDevice.discoverServices())
.firstWhere((service) => service.uuid.toString().contains(BLE_SERVICE))
.characteristics;
for (BluetoothCharacteristic characteristic in characteristics) {
if (characteristic.uuid.toString().contains(BLE_RECEIVE)) {
_receiveCharacteristic = characteristic;
} else if (characteristic.uuid.toString().contains(BLE_SEND)) {
_sendCharacteristic = characteristic;
}
}
void setupCharacteristics() async {
_sendCharacteristic = QualifiedCharacteristic(
Comment thread
MouradLachhab marked this conversation as resolved.
characteristicId: Uuid.parse(BLE_SEND),
serviceId: Uuid.parse(BLE_SERVICE),
deviceId: _selectedDevice.id.toString());

if (_receiveCharacteristic == null)
throw Exception('Device is missing receive Characteristic');
if (_sendCharacteristic == null)
throw Exception('Device is missing send Characteristic');
_receiveCharacteristic = QualifiedCharacteristic(
characteristicId: Uuid.parse(BLE_RECEIVE),
serviceId: Uuid.parse(BLE_SERVICE),
deviceId: _selectedDevice.id.toString());
}

Future<Stream<List<int>>> startDataStream() async {
await _receiveCharacteristic.setNotifyValue(true);
await flutterReactiveBle.requestConnectionPriority(
deviceId: _selectedDevice.id.toString(),
priority: ConnectionPriority.highPerformance);

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

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

Future<void> stopDataStream() async {
await _receiveCharacteristic.setNotifyValue(false);
await _sendCharacteristic.write(stopStreamChar.codeUnits);
await flutterReactiveBle.requestConnectionPriority(
deviceId: _selectedDevice.id.toString(),
priority: ConnectionPriority.balanced);
flutterReactiveBle.writeCharacteristicWithoutResponse(_sendCharacteristic,
value: stopStreamChar.codeUnits);
}

@override
Expand Down
Loading