blob: 08875d5b9a682607e71975cb2c5080520f1d9633 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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);
}
}
}
|