Skip to content

Commit cafcfc7

Browse files
rahul31124marcnause
authored andcommitted
added csv data handling for compass
1 parent dc45757 commit cafcfc7

6 files changed

Lines changed: 610 additions & 22 deletions

File tree

lib/models/compass_config.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class CompassConfig {
2+
final bool includeLocationData;
3+
4+
const CompassConfig({
5+
this.includeLocationData = false,
6+
});
7+
8+
CompassConfig copyWith({
9+
bool? includeLocationData,
10+
}) {
11+
return CompassConfig(
12+
includeLocationData: includeLocationData ?? this.includeLocationData,
13+
);
14+
}
15+
16+
factory CompassConfig.fromJson(Map<String, dynamic> json) {
17+
return CompassConfig(
18+
includeLocationData: json['includeLocationData'] as bool? ?? false,
19+
);
20+
}
21+
22+
Map<String, dynamic> toJson() {
23+
return {
24+
'includeLocationData': includeLocationData,
25+
};
26+
}
27+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'dart:convert';
3+
import 'package:shared_preferences/shared_preferences.dart';
4+
import 'package:pslab/models/compass_config.dart';
5+
6+
class CompassConfigProvider extends ChangeNotifier {
7+
CompassConfig _config = const CompassConfig();
8+
9+
CompassConfig get config => _config;
10+
11+
CompassConfigProvider() {
12+
_loadConfigFromPrefs();
13+
}
14+
15+
Future<void> _loadConfigFromPrefs() async {
16+
final prefs = await SharedPreferences.getInstance();
17+
final jsonString = prefs.getString('compass_config');
18+
if (jsonString != null) {
19+
final Map<String, dynamic> jsonMap = json.decode(jsonString);
20+
_config = CompassConfig.fromJson(jsonMap);
21+
notifyListeners();
22+
}
23+
}
24+
25+
Future<void> _saveConfigToPrefs() async {
26+
final prefs = await SharedPreferences.getInstance();
27+
await prefs.setString('compass_config', json.encode(_config.toJson()));
28+
}
29+
30+
void updateConfig(CompassConfig newConfig) {
31+
_config = newConfig;
32+
notifyListeners();
33+
_saveConfigToPrefs();
34+
}
35+
36+
void updateIncludeLocationData(bool includeLocationData) {
37+
_config = _config.copyWith(includeLocationData: includeLocationData);
38+
notifyListeners();
39+
_saveConfigToPrefs();
40+
}
41+
42+
void resetToDefaults() {
43+
_config = const CompassConfig();
44+
notifyListeners();
45+
_saveConfigToPrefs();
46+
}
47+
}

lib/providers/compass_provider.dart

Lines changed: 226 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import 'dart:async';
22
import 'dart:math';
33
import 'package:flutter/material.dart';
44
import 'package:sensors_plus/sensors_plus.dart';
5-
import 'package:flutter/foundation.dart';
5+
import 'package:geolocator/geolocator.dart';
6+
import 'package:intl/intl.dart';
67
import 'package:pslab/others/logger_service.dart';
78

89
import '../l10n/app_localizations.dart';
910
import 'locator.dart';
11+
import 'compass_config_provider.dart';
1012

1113
class CompassProvider extends ChangeNotifier {
1214
AppLocalizations appLocalizations = getIt.get<AppLocalizations>();
@@ -21,12 +23,69 @@ class CompassProvider extends ChangeNotifier {
2123
int _direction = 0;
2224
double _smoothedHeading = 0.0;
2325

26+
bool _isRecording = false;
27+
List<List<dynamic>> _recordedData = [];
28+
Timer? _recordTimer;
29+
30+
bool _isPlayingBack = false;
31+
List<List<dynamic>>? _playbackData;
32+
int _playbackIndex = 0;
33+
Timer? _playbackTimer;
34+
bool _isPlaybackPaused = false;
35+
Function? onPlaybackEnd;
36+
double _playbackDegree = 0.0;
37+
38+
CompassConfigProvider? _configProvider;
39+
Position? currentPosition;
40+
StreamSubscription? _locationStream;
41+
2442
MagnetometerEvent get magnetometerEvent => _magnetometerEvent;
2543
AccelerometerEvent get accelerometerEvent => _accelerometerEvent;
2644
String get selectedAxis => _selectedAxis;
2745
double get currentDegree => _currentDegree;
2846
int get direction => _direction;
2947
double get smoothedHeading => _smoothedHeading;
48+
bool get isRecording => _isRecording;
49+
bool get isPlayingBack => _isPlayingBack;
50+
bool get isPlaybackPaused => _isPlaybackPaused;
51+
52+
void setConfigProvider(CompassConfigProvider configProvider) {
53+
_configProvider = configProvider;
54+
}
55+
56+
Future<void> _startGeoLocationUpdates() async {
57+
bool serviceEnabled;
58+
LocationPermission permission;
59+
60+
serviceEnabled = await Geolocator.isLocationServiceEnabled();
61+
if (!serviceEnabled) {
62+
logger.w('Location services are disabled.');
63+
return;
64+
}
65+
66+
permission = await Geolocator.checkPermission();
67+
if (permission == LocationPermission.denied) {
68+
permission = await Geolocator.requestPermission();
69+
if (permission == LocationPermission.denied) {
70+
logger.w('Location permissions are denied');
71+
return;
72+
}
73+
}
74+
75+
if (permission == LocationPermission.deniedForever) {
76+
logger.w(
77+
'Location permissions are permanently denied, we cannot request permissions.');
78+
return;
79+
}
80+
81+
_locationStream = Geolocator.getPositionStream(
82+
locationSettings: const LocationSettings(
83+
accuracy: LocationAccuracy.high,
84+
),
85+
).listen((Position position) {
86+
currentPosition = position;
87+
});
88+
}
3089

3190
void initializeSensors() {
3291
_magnetometerSubscription = magnetometerEventStream().listen(
@@ -57,11 +116,173 @@ class CompassProvider extends ChangeNotifier {
57116
void disposeSensors() {
58117
_magnetometerSubscription?.cancel();
59118
_accelerometerSubscription?.cancel();
119+
_playbackTimer?.cancel();
120+
}
121+
122+
Future<void> startPlayback(List<List<dynamic>> data) async {
123+
if (data.length <= 1) return;
124+
_isPlayingBack = true;
125+
_isPlaybackPaused = false;
126+
_playbackTimer?.cancel();
127+
_playbackData = data;
128+
_playbackIndex = 1;
129+
disposeSensors();
130+
_startPlaybackTimer();
131+
notifyListeners();
132+
}
133+
134+
void _startPlaybackTimer() {
135+
if (_playbackIndex >= _playbackData!.length) {
136+
stopPlayback();
137+
return;
138+
}
139+
140+
final currentRow = _playbackData![_playbackIndex];
141+
if (currentRow.length > 5) {
142+
final bx = double.tryParse(currentRow[2].toString()) ?? 0.0;
143+
final by = double.tryParse(currentRow[3].toString()) ?? 0.0;
144+
final bz = double.tryParse(currentRow[4].toString()) ?? 0.0;
145+
final degree = double.tryParse(currentRow[5].toString()) ?? 0.0;
146+
147+
_magnetometerEvent = MagnetometerEvent(bx, by, bz, DateTime.now());
148+
_playbackDegree = degree;
149+
150+
if (_selectedAxis == 'Z') {
151+
_currentDegree = -((_playbackDegree - 90) * pi / 180);
152+
} else {
153+
_currentDegree = -(_playbackDegree * pi / 180);
154+
}
155+
156+
_playbackIndex++;
157+
notifyListeners();
158+
} else if (currentRow.length > 4) {
159+
final bx = double.tryParse(currentRow[2].toString()) ?? 0.0;
160+
final by = double.tryParse(currentRow[3].toString()) ?? 0.0;
161+
final bz = double.tryParse(currentRow[4].toString()) ?? 0.0;
162+
163+
_magnetometerEvent = MagnetometerEvent(bx, by, bz, DateTime.now());
164+
_accelerometerEvent = AccelerometerEvent(0, 0, 9.8, DateTime.now());
165+
166+
_updateCompassDirection();
167+
_playbackIndex++;
168+
notifyListeners();
169+
} else {
170+
logger.e(
171+
'Skipping playback row at index $_playbackIndex due to insufficient columns');
172+
_playbackIndex++;
173+
notifyListeners();
174+
}
175+
176+
Duration interval = const Duration(seconds: 1);
177+
178+
if (_playbackIndex < _playbackData!.length && _playbackIndex > 1) {
179+
try {
180+
final currentTimestamp =
181+
int.tryParse(_playbackData![_playbackIndex - 1][0].toString());
182+
final nextTimestamp =
183+
int.tryParse(_playbackData![_playbackIndex][0].toString());
184+
185+
if (currentTimestamp != null && nextTimestamp != null) {
186+
final timeDiff = nextTimestamp - currentTimestamp;
187+
interval = Duration(milliseconds: timeDiff);
188+
if (interval.inMilliseconds < 100) {
189+
interval = const Duration(milliseconds: 100);
190+
} else if (interval.inMilliseconds > 10000) {
191+
interval = const Duration(seconds: 10);
192+
}
193+
}
194+
} catch (e) {
195+
interval = const Duration(seconds: 1);
196+
}
197+
}
198+
199+
_playbackTimer = Timer(interval, () {
200+
if (_isPlayingBack && !_isPlaybackPaused) {
201+
_startPlaybackTimer();
202+
}
203+
});
204+
}
205+
206+
Future<void> stopPlayback() async {
207+
_isPlayingBack = false;
208+
_isPlaybackPaused = false;
209+
_playbackData = null;
210+
_playbackIndex = 0;
211+
_playbackDegree = 0.0;
212+
_magnetometerEvent = MagnetometerEvent(0, 0, 0, DateTime.now());
213+
_accelerometerEvent = AccelerometerEvent(0, 0, 0, DateTime.now());
214+
notifyListeners();
215+
onPlaybackEnd?.call();
216+
}
217+
218+
void pausePlayback() {
219+
if (_isPlayingBack) {
220+
_isPlaybackPaused = true;
221+
_playbackTimer?.cancel();
222+
notifyListeners();
223+
}
224+
}
225+
226+
void resumePlayback() {
227+
if (_isPlayingBack && _isPlaybackPaused) {
228+
_isPlaybackPaused = false;
229+
_startPlaybackTimer();
230+
notifyListeners();
231+
}
232+
}
233+
234+
Future<void> startRecording() async {
235+
if (_configProvider?.config.includeLocationData == true) {
236+
await _startGeoLocationUpdates();
237+
}
238+
_isRecording = true;
239+
_recordedData = [
240+
[
241+
'Timestamp',
242+
'DateTime',
243+
'Bx',
244+
'By',
245+
'Bz',
246+
'Degree',
247+
'Latitude',
248+
'Longitude'
249+
]
250+
];
251+
252+
_recordTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
253+
final now = DateTime.now();
254+
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS');
255+
_recordedData.add([
256+
now.millisecondsSinceEpoch.toString(),
257+
dateFormat.format(now),
258+
_magnetometerEvent.x.toStringAsFixed(2),
259+
_magnetometerEvent.y.toStringAsFixed(2),
260+
_magnetometerEvent.z.toStringAsFixed(2),
261+
getDegreeForAxis(_selectedAxis).toStringAsFixed(1),
262+
_configProvider?.config.includeLocationData == true
263+
? currentPosition?.latitude.toString() ?? 0
264+
: 0,
265+
_configProvider?.config.includeLocationData == true
266+
? currentPosition?.longitude.toString() ?? 0
267+
: 0
268+
]);
269+
});
270+
notifyListeners();
271+
}
272+
273+
List<List<dynamic>> stopRecording() {
274+
_isRecording = false;
275+
_recordTimer?.cancel();
276+
_locationStream?.cancel();
277+
notifyListeners();
278+
return _recordedData;
60279
}
61280

62281
@override
63282
void dispose() {
64283
disposeSensors();
284+
_recordTimer?.cancel();
285+
_locationStream?.cancel();
65286
super.dispose();
66287
}
67288

@@ -135,6 +356,10 @@ class CompassProvider extends ChangeNotifier {
135356
}
136357

137358
double getDegreeForAxis(String axis) {
359+
if (_isPlayingBack) {
360+
return _playbackDegree;
361+
}
362+
138363
double radians = _getRadiansForAxis(axis);
139364
double degree = radians * (180 / pi);
140365

0 commit comments

Comments
 (0)