Skip to content
Closed
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
1 change: 1 addition & 0 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ const String buttonStateCharacteristicUuid =

const String ledServiceUuid = "81040a2e-4819-11ee-be56-0242ac120002";
const String ledSetStateCharacteristic = "81040e7a-4819-11ee-be56-0242ac120002";
const String sensorErrorCharacteristicUuid = "1234567c-1234-5678-9abc-def123456789";
32 changes: 30 additions & 2 deletions lib/src/models/devices/open_earable_v2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'dart:typed_data';
import 'package:open_earable_flutter/src/constants.dart';
import 'package:open_earable_flutter/src/models/devices/bluetooth_wearable.dart';
import 'package:pub_semver/pub_semver.dart';

import 'package:open_earable_flutter/src/models/error/sensor_error.dart';
import '../../../open_earable_flutter.dart' hide Version;
import '../../managers/v2_sensor_handler.dart';
import '../capabilities/device_firmware_version.dart';
Expand Down Expand Up @@ -90,6 +90,31 @@ class OpenEarableV2 extends BluetoothWearable
@override
bool get isConnectedViaSystem => _isConnectedViaSystem;

final _errorController = StreamController<SensorError>.broadcast();
Stream<SensorError> get onError => _errorController.stream;
// Add this method after the _errorController declaration
void _subscribeToErrorNotifications() {
bleManager
.subscribe(
deviceId: deviceId,
serviceId: sensorServiceUuid,
characteristicId: sensorErrorCharacteristicUuid,
)
.listen(
(data) {
try {
final error = SensorError.fromBytes(Uint8List.fromList(data));
logger.i('Received sensor error: $error');
_errorController.add(error);
} catch (e) {
logger.e('Failed to parse sensor error: $e');
}
},
onError: (error) {
logger.e('Error in error notification stream: $error');
},
);
}
@override
Stream<Map<SensorConfiguration, SensorConfigurationValue>>
get sensorConfigurationStream {
Expand Down Expand Up @@ -279,7 +304,10 @@ class OpenEarableV2 extends BluetoothWearable
bool isConnectedViaSystem = false,
}) : _sensors = sensors,
_sensorConfigurations = sensorConfigurations,
_isConnectedViaSystem = isConnectedViaSystem;
_isConnectedViaSystem = isConnectedViaSystem {
// ADD THIS LINE HERE
_subscribeToErrorNotifications();
}

@override
String get deviceId => discoveredDevice.id;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/models/devices/wearable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:ui';

import '../../managers/wearable_disconnect_notifier.dart';

import 'package:open_earable_flutter/src/models/error/sensor_error.dart';
enum WearableIconVariant {
single,
left,
Expand Down Expand Up @@ -44,7 +44,7 @@ abstract class Wearable {
}
return null;
}

Stream<SensorError> get onError => const Stream.empty();
/// Gets a specific capability of the wearable, throwing a StateError if not supported.
T requireCapability<T>() {
final capability = getCapability<T>();
Expand Down
60 changes: 60 additions & 0 deletions lib/src/models/error/sensor_error.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'dart:typed_data';

class SensorError {
final int errorCode;
final int sensorId;
final int timestamp;
final String message;

SensorError({
required this.errorCode,
required this.sensorId,
required this.timestamp,
required this.message,
});

factory SensorError.fromBytes(Uint8List bytes) {
if (bytes.length < 70) {
throw Exception('Invalid error data length: ${bytes.length}');
}

return SensorError(
errorCode: bytes[0],
sensorId: bytes[1],
timestamp: (bytes[5] << 24) |
(bytes[4] << 16) |
(bytes[3] << 8) |
bytes[2],
message: String.fromCharCodes(bytes.sublist(6, 70)).trim(),
);
}

String get errorDescription {
switch (errorCode) {
case 0x01: return 'Error streaming is initialized';
case 0x02: return 'Sensor read failed';
case 0x03: return 'SD card error';
case 0x04: return 'Audio playback failed';
case 0x05: return 'BLE notification failed';
case 0xFF: return 'Steaming failed the queue is full!';
default: return 'Unknown error (code: ${errorCode.toRadixString(16)})';
}
}

String get sensorName {
switch (sensorId) {
case 0: return 'IMU';
case 1: return 'Barometer';
case 2: return 'PPG';
case 3: return 'Optic Temp';
case 4: return 'Bone Conduction';
case 5: return 'Microphone';
default: return 'System';
}
}

String get formattedMessage => '[$sensorName] $errorDescription: $message';

@override
String toString() => formattedMessage;
}
Loading