sense_the_rythm

rythm game for ESense Earable
git clone git://source.orangerot.dev:/university/sense_the_rythm.git
Log | Files | Refs | README | LICENSE

esense_input.dart (6615B)


      1 import 'dart:async';
      2 import 'dart:io';
      3 
      4 import 'package:esense_flutter/esense.dart';
      5 import 'package:flutter/material.dart';
      6 import 'package:permission_handler/permission_handler.dart';
      7 import 'package:sense_the_rhythm/models/arrow_direction.dart';
      8 import 'package:sense_the_rhythm/models/input_direction.dart';
      9 
     10 class ESenseInput {
     11   // create singleton that is available on all widgets so it does not have to be
     12   // carried down in the widget tree
     13   static final instance = ESenseInput._();
     14 
     15   ESenseManager eSenseManager = ESenseManager('unknown');
     16   // valuenotifier allows widgets to rerender when the value changes
     17   ValueNotifier<String> deviceStatus = ValueNotifier('Disconnected');
     18   StreamSubscription? _subscription;
     19 
     20   String eSenseDeviceName = '';
     21   bool connected = false;
     22 
     23   final int _sampleRate = 20;
     24 
     25   final InputDirection _inputDirection = InputDirection();
     26   int _x = 0;
     27   int _y = 0;
     28   int _z = 0;
     29 
     30   ESenseInput._() {
     31     _listenToESense();
     32   }
     33 
     34   /// ask and check if permissions are enabled and granted
     35   Future<bool> _askForPermissions() async {
     36     // is desktop
     37     if (!Platform.isAndroid && !Platform.isIOS) return false;
     38     // is bluetooth even enabled?
     39     if (!await Permission.bluetooth.serviceStatus.isEnabled) {
     40       deviceStatus.value = "Bluetooth is disabled!";
     41       return false;
     42     }
     43     if (!(await Permission.bluetoothScan.request().isGranted &&
     44         await Permission.bluetoothConnect.request().isGranted &&
     45         await Permission.bluetooth.request().isGranted)) {
     46       print(
     47           'WARNING - no permission to use Bluetooth granted. Cannot access eSense device.');
     48       deviceStatus.value = "Insufficiant Permissions";
     49       return false;
     50     }
     51     // for some strange reason, Android requires permission to location for Bluetooth to work.....?
     52     if (Platform.isAndroid) {
     53       if (!(await Permission.locationWhenInUse.request().isGranted)) {
     54         print(
     55             'WARNING - no permission to access location granted. Cannot access eSense device.');
     56         deviceStatus.value = "Insufficiant Permissions";
     57         return false;
     58       }
     59     }
     60     return true;
     61   }
     62 
     63   /// listen to connectionEvents and set deviceStatus
     64   void _listenToESense() {
     65     // if you want to get the connection events when connecting,
     66     // set up the listener BEFORE connecting...
     67     eSenseManager.connectionEvents.listen((event) {
     68       print('CONNECTION event: $event');
     69 
     70       // when we're connected to the eSense device, we can start listening to events from it
     71       // if (event.type == ConnectionType.connected) _listenToESenseEvents();
     72 
     73       connected = false;
     74       switch (event.type) {
     75         case ConnectionType.connected:
     76           deviceStatus.value = 'Connected';
     77           connected = true;
     78           _startListenToSensorEvents();
     79           break;
     80         case ConnectionType.unknown:
     81           deviceStatus.value = 'Unknown';
     82           break;
     83         case ConnectionType.disconnected:
     84           deviceStatus.value = 'Disconnected';
     85           _pauseListenToSensorEvents();
     86           break;
     87         case ConnectionType.device_found:
     88           deviceStatus.value = 'Device_found';
     89           break;
     90         case ConnectionType.device_not_found:
     91           deviceStatus.value = 'Device_not_found';
     92           break;
     93       }
     94     });
     95   }
     96 
     97   /// get eSenseEvent stream only containung button events
     98   Stream<ButtonEventChanged> buttonEvents() {
     99     return eSenseManager.eSenseEvents
    100         .where((event) => event.runtimeType == ButtonEventChanged)
    101         .cast();
    102   }
    103 
    104   /// sets sampling rate and listens to sensorEvents
    105   void _startListenToSensorEvents() async {
    106     // // any changes to the sampling frequency must be done BEFORE listening to sensor events
    107     print('setting sampling frequency...');
    108     bool successs = await eSenseManager.setSamplingRate(_sampleRate);
    109     if (successs) {
    110       print('setSamplingRate success');
    111     } else {
    112       print('setSamplingRate fail');
    113     }
    114 
    115     // subscribe to sensor event from the eSense device
    116     _subscription = eSenseManager.sensorEvents.listen((event) {
    117       // print('SENSOR event: $event');
    118       if (event.gyro != null) {
    119         _parseGyroData(event.gyro!);
    120       }
    121     });
    122   }
    123 
    124   /// cancels the sensorEvents listening
    125   void _pauseListenToSensorEvents() async {
    126     _subscription?.cancel();
    127   }
    128 
    129   /// add up all new gyro [data] in the form of deg/s multiplied by scaling factor
    130   /// to get real angles
    131   void _parseGyroData(List<int> data) {
    132     // Float value in deg/s = Gyro value / Gyro scale factor
    133     // The default configuration is +- 500deg/s for the gyroscope.
    134     _x = (_x + (15 * data[0] ~/ (500 * _sampleRate))) % 360;
    135     _y = (_y + (15 * data[1] ~/ (500 * _sampleRate))) % 360;
    136     _z = (_z + (15 * data[2] ~/ (500 * _sampleRate))) % 360;
    137     print('$_x, $_y, $_z');
    138     // print('${(z.toDouble() / 500.0 * (1.0 / sampleRate.toDouble())) * 7.5}');
    139     // print('${z.toDouble() / 500.0 * (1.0 / 10.0)}');
    140   }
    141 
    142   /// nulls all angles and reset inputDirection
    143   void resetAngles() {
    144     _inputDirection.reset();
    145     _x = 0;
    146     _y = 0;
    147     _z = 0;
    148   }
    149 
    150   /// get InputDirection by checking if angels are in defined ranges and
    151   /// calibrating based on the [expect]ed direction from ArrowDirection
    152   InputDirection getInputDirection(ArrowDirection expect) {
    153     // check if angle is in range
    154     _inputDirection.up = _z > 180 && _z < 340;
    155     _inputDirection.down = _z > 20 && _z < 180;
    156     _inputDirection.left = _y > 0 && _y < 180;
    157     _inputDirection.right = _y > 180 && _y < 360;
    158 
    159     // calibrate based on expected directoin from ArrowDirection
    160     if (expect == ArrowDirection.up && _inputDirection.up ||
    161         expect == ArrowDirection.down && _inputDirection.down) {
    162       _y = 0;
    163     }
    164     if (expect == ArrowDirection.left && _inputDirection.left ||
    165         expect == ArrowDirection.right && _inputDirection.right) {
    166       _z = 0;
    167     }
    168 
    169     return _inputDirection;
    170   }
    171 
    172   /// connect to ESense with [deviceName] by first asking for permissions
    173   Future<void> connectToESense(String deviceName) async {
    174     if (!connected) {
    175       bool permissionSuccessfull = await _askForPermissions();
    176       if (!permissionSuccessfull) return;
    177       print('Trying to connect to eSense device namend \'$deviceName\'');
    178       eSenseDeviceName = deviceName;
    179       eSenseManager.deviceName = deviceName;
    180       bool connecting = await eSenseManager.connect();
    181       print(
    182           'Trying to connect to eSense device namend \'${eSenseManager.deviceName}\'');
    183 
    184       deviceStatus.value = connecting ? 'connecting...' : 'connection failed';
    185       print(deviceStatus.value);
    186     }
    187   }
    188 }