summaryrefslogtreecommitdiff
path: root/lib/utils/esense_input.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils/esense_input.dart')
-rw-r--r--lib/utils/esense_input.dart188
1 files changed, 188 insertions, 0 deletions
diff --git a/lib/utils/esense_input.dart b/lib/utils/esense_input.dart
new file mode 100644
index 0000000..08875d5
--- /dev/null
+++ b/lib/utils/esense_input.dart
@@ -0,0 +1,188 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:esense_flutter/esense.dart';
+import 'package:flutter/material.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:sense_the_rhythm/models/arrow_direction.dart';
+import 'package:sense_the_rhythm/models/input_direction.dart';
+
+class ESenseInput {
+ // create singleton that is available on all widgets so it does not have to be
+ // carried down in the widget tree
+ static final instance = ESenseInput._();
+
+ ESenseManager eSenseManager = ESenseManager('unknown');
+ // valuenotifier allows widgets to rerender when the value changes
+ ValueNotifier<String> deviceStatus = ValueNotifier('Disconnected');
+ StreamSubscription? _subscription;
+
+ String eSenseDeviceName = '';
+ bool connected = false;
+
+ final int _sampleRate = 20;
+
+ final InputDirection _inputDirection = InputDirection();
+ int _x = 0;
+ int _y = 0;
+ int _z = 0;
+
+ ESenseInput._() {
+ _listenToESense();
+ }
+
+ /// ask and check if permissions are enabled and granted
+ Future<bool> _askForPermissions() async {
+ // is desktop
+ if (!Platform.isAndroid && !Platform.isIOS) return false;
+ // is bluetooth even enabled?
+ if (!await Permission.bluetooth.serviceStatus.isEnabled) {
+ deviceStatus.value = "Bluetooth is disabled!";
+ return false;
+ }
+ if (!(await Permission.bluetoothScan.request().isGranted &&
+ await Permission.bluetoothConnect.request().isGranted &&
+ await Permission.bluetooth.request().isGranted)) {
+ print(
+ 'WARNING - no permission to use Bluetooth granted. Cannot access eSense device.');
+ deviceStatus.value = "Insufficiant Permissions";
+ return false;
+ }
+ // for some strange reason, Android requires permission to location for Bluetooth to work.....?
+ if (Platform.isAndroid) {
+ if (!(await Permission.locationWhenInUse.request().isGranted)) {
+ print(
+ 'WARNING - no permission to access location granted. Cannot access eSense device.');
+ deviceStatus.value = "Insufficiant Permissions";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// listen to connectionEvents and set deviceStatus
+ void _listenToESense() {
+ // if you want to get the connection events when connecting,
+ // set up the listener BEFORE connecting...
+ eSenseManager.connectionEvents.listen((event) {
+ print('CONNECTION event: $event');
+
+ // when we're connected to the eSense device, we can start listening to events from it
+ // if (event.type == ConnectionType.connected) _listenToESenseEvents();
+
+ connected = false;
+ switch (event.type) {
+ case ConnectionType.connected:
+ deviceStatus.value = 'Connected';
+ connected = true;
+ _startListenToSensorEvents();
+ break;
+ case ConnectionType.unknown:
+ deviceStatus.value = 'Unknown';
+ break;
+ case ConnectionType.disconnected:
+ deviceStatus.value = 'Disconnected';
+ _pauseListenToSensorEvents();
+ break;
+ case ConnectionType.device_found:
+ deviceStatus.value = 'Device_found';
+ break;
+ case ConnectionType.device_not_found:
+ deviceStatus.value = 'Device_not_found';
+ break;
+ }
+ });
+ }
+
+ /// get eSenseEvent stream only containung button events
+ Stream<ButtonEventChanged> buttonEvents() {
+ return eSenseManager.eSenseEvents
+ .where((event) => event.runtimeType == ButtonEventChanged)
+ .cast();
+ }
+
+ /// sets sampling rate and listens to sensorEvents
+ void _startListenToSensorEvents() async {
+ // // any changes to the sampling frequency must be done BEFORE listening to sensor events
+ print('setting sampling frequency...');
+ bool successs = await eSenseManager.setSamplingRate(_sampleRate);
+ if (successs) {
+ print('setSamplingRate success');
+ } else {
+ print('setSamplingRate fail');
+ }
+
+ // subscribe to sensor event from the eSense device
+ _subscription = eSenseManager.sensorEvents.listen((event) {
+ // print('SENSOR event: $event');
+ if (event.gyro != null) {
+ _parseGyroData(event.gyro!);
+ }
+ });
+ }
+
+ /// cancels the sensorEvents listening
+ void _pauseListenToSensorEvents() async {
+ _subscription?.cancel();
+ }
+
+ /// add up all new gyro [data] in the form of deg/s multiplied by scaling factor
+ /// to get real angles
+ void _parseGyroData(List<int> data) {
+ // Float value in deg/s = Gyro value / Gyro scale factor
+ // The default configuration is +- 500deg/s for the gyroscope.
+ _x = (_x + (15 * data[0] ~/ (500 * _sampleRate))) % 360;
+ _y = (_y + (15 * data[1] ~/ (500 * _sampleRate))) % 360;
+ _z = (_z + (15 * data[2] ~/ (500 * _sampleRate))) % 360;
+ print('$_x, $_y, $_z');
+ // print('${(z.toDouble() / 500.0 * (1.0 / sampleRate.toDouble())) * 7.5}');
+ // print('${z.toDouble() / 500.0 * (1.0 / 10.0)}');
+ }
+
+ /// nulls all angles and reset inputDirection
+ void resetAngles() {
+ _inputDirection.reset();
+ _x = 0;
+ _y = 0;
+ _z = 0;
+ }
+
+ /// get InputDirection by checking if angels are in defined ranges and
+ /// calibrating based on the [expect]ed direction from ArrowDirection
+ InputDirection getInputDirection(ArrowDirection expect) {
+ // check if angle is in range
+ _inputDirection.up = _z > 180 && _z < 340;
+ _inputDirection.down = _z > 20 && _z < 180;
+ _inputDirection.left = _y > 0 && _y < 180;
+ _inputDirection.right = _y > 180 && _y < 360;
+
+ // calibrate based on expected directoin from ArrowDirection
+ if (expect == ArrowDirection.up && _inputDirection.up ||
+ expect == ArrowDirection.down && _inputDirection.down) {
+ _y = 0;
+ }
+ if (expect == ArrowDirection.left && _inputDirection.left ||
+ expect == ArrowDirection.right && _inputDirection.right) {
+ _z = 0;
+ }
+
+ return _inputDirection;
+ }
+
+ /// connect to ESense with [deviceName] by first asking for permissions
+ Future<void> connectToESense(String deviceName) async {
+ if (!connected) {
+ bool permissionSuccessfull = await _askForPermissions();
+ if (!permissionSuccessfull) return;
+ print('Trying to connect to eSense device namend \'$deviceName\'');
+ eSenseDeviceName = deviceName;
+ eSenseManager.deviceName = deviceName;
+ bool connecting = await eSenseManager.connect();
+ print(
+ 'Trying to connect to eSense device namend \'${eSenseManager.deviceName}\'');
+
+ deviceStatus.value = connecting ? 'connecting...' : 'connection failed';
+ print(deviceStatus.value);
+ }
+ }
+}