diff options
Diffstat (limited to 'lib/utils/esense_input.dart')
-rw-r--r-- | lib/utils/esense_input.dart | 188 |
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); + } + } +} |