Skip to content

Commit f3c7503

Browse files
authored
fix: Resolve I2C communication, USB stability, and sensor state issues (#3606)
1 parent edb4283 commit f3c7503

18 files changed

Lines changed: 715 additions & 258 deletions

‎lib/communication/packet_handler.dart‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,8 @@ class PacketHandler {
7979
return "";
8080
}
8181

82-
Future<Uint8List> queryScpiBinary(String command) async {
83-
Uint8List data =
84-
await rust_api.queryScpiBinaryRust(command: command, timeoutMs: 1000);
85-
return data;
82+
Future<void> sendScpiRaw(Uint8List command) async {
83+
rust_api.sendScpiRawRust(command: command);
8684
}
8785

8886
void sendByte(int val) {
@@ -236,4 +234,21 @@ class PacketHandler {
236234
_mCommunicationHandler.write(data, _timeout);
237235
}
238236
}
237+
238+
Future<Uint8List> queryScpiBinary(String command) async {
239+
Uint8List data =
240+
await rust_api.queryScpiBinaryRust(command: command, timeoutMs: 1000);
241+
return data;
242+
}
243+
244+
void sendScpiRawCmd(Uint8List command) {
245+
rust_api.sendScpiRawRust(command: command);
246+
}
247+
248+
Future<Uint8List> queryScpiBinaryRawCmd(Uint8List command,
249+
{int timeoutMs = 1000}) async {
250+
final result = await rust_api.queryScpiBinaryRawRust(
251+
command: command, timeoutMs: timeoutMs);
252+
return Uint8List.fromList(result);
253+
}
239254
}

‎lib/communication/peripherals/i2c.dart‎

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,22 @@ class I2C {
2020
buffer = List.filled(10000, 0);
2121
commandsProto = CommandsProto();
2222
}
23-
24-
String _buildScpiBlock(String prefix, List<int> data) {
23+
Uint8List _buildScpiBlockBytes(String prefix, List<int> data,
24+
{String suffix = ""}) {
2525
String dataLen = data.length.toString();
2626
String numDigits = dataLen.length.toString();
2727
String header = "$prefix #$numDigits$dataLen";
28-
return header + String.fromCharCodes(data);
28+
29+
List<int> cmdBytes = header.codeUnits.toList();
30+
cmdBytes.addAll(data);
31+
32+
if (suffix.isNotEmpty) {
33+
cmdBytes.addAll(suffix.codeUnits);
34+
}
35+
36+
Uint8List finalBytes = Uint8List.fromList(cmdBytes);
37+
logger.i("SCPI COMMAND BUILT -> Raw array: $finalBytes");
38+
return finalBytes;
2939
}
3040

3141
Future<void> init() async {
@@ -159,11 +169,25 @@ class I2C {
159169
int deviceAddress, int registerAddress, int bytesToRead) async {
160170
if (PacketHandler.boardType == BoardType.scpi) {
161171
await packetHandler.sendScpi("BUS:I2C:CONF:ADDR $deviceAddress");
162-
String blockCmd = "${_buildScpiBlock("BUS:I2C:TRAN?", [
163-
registerAddress
164-
])}, $bytesToRead";
172+
await Future.delayed(const Duration(milliseconds: 2));
173+
174+
String prefix = "BUS:I2C:TRAN? $bytesToRead,";
175+
Uint8List blockCmd = _buildScpiBlockBytes(prefix, [registerAddress]);
176+
177+
int attempts = 0;
178+
Uint8List rxData = Uint8List(0);
179+
180+
while (attempts < 5) {
181+
rxData = await packetHandler.queryScpiBinaryRawCmd(blockCmd);
182+
183+
if (rxData.length == bytesToRead) {
184+
return rxData.toList();
185+
}
186+
187+
attempts++;
188+
await Future.delayed(const Duration(milliseconds: 10));
189+
}
165190

166-
Uint8List rxData = await packetHandler.queryScpiBinary(blockCmd);
167191
return rxData.toList();
168192
}
169193

@@ -202,8 +226,9 @@ class I2C {
202226
Future<void> writeBulk(int deviceAddress, List<int> data) async {
203227
if (PacketHandler.boardType == BoardType.scpi) {
204228
await packetHandler.sendScpi("BUS:I2C:CONF:ADDR $deviceAddress");
205-
String blockCmd = _buildScpiBlock("BUS:I2C:WRIT", data);
206-
await packetHandler.sendScpi(blockCmd);
229+
await Future.delayed(const Duration(milliseconds: 5));
230+
Uint8List blockCmd = _buildScpiBlockBytes("BUS:I2C:WRIT", data);
231+
packetHandler.sendScpiRawCmd(blockCmd);
207232
return;
208233
}
209234

‎lib/providers/ads1115_provider.dart‎

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class ADS1115Provider extends ChangeNotifier {
1313

1414
ADS1115? _ads1115;
1515
Timer? _dataTimer;
16+
17+
bool _isDisposed = false;
18+
bool _isFetching = false;
19+
1620
double _voltage = 0.0;
1721
String _currentGain = "GAIN_ONE";
1822
String _currentChannel = "UNI_0";
@@ -82,7 +86,7 @@ class ADS1115Provider extends ChangeNotifier {
8286

8387
_ads1115 = await ADS1115.create(i2c, scienceLab);
8488
_updateCurrentSettings();
85-
notifyListeners();
89+
if (!_isDisposed) notifyListeners();
8690
} catch (e) {
8791
logger.e('Error initializing ADS1115: $e');
8892
}
@@ -100,23 +104,23 @@ class ADS1115Provider extends ChangeNotifier {
100104
if (_ads1115 != null) {
101105
_ads1115!.setGain(gain);
102106
_currentGain = gain;
103-
notifyListeners();
107+
if (!_isDisposed) notifyListeners();
104108
}
105109
}
106110

107111
void setChannel(String channel) {
108112
if (_ads1115 != null) {
109113
_ads1115!.setChannel(channel);
110114
_currentChannel = channel;
111-
notifyListeners();
115+
if (!_isDisposed) notifyListeners();
112116
}
113117
}
114118

115119
void setRate(int rate) {
116120
if (_ads1115 != null) {
117121
_ads1115!.setDataRate(rate);
118122
_currentRate = rate;
119-
notifyListeners();
123+
if (!_isDisposed) notifyListeners();
120124
}
121125
}
122126

@@ -133,8 +137,13 @@ class ADS1115Provider extends ChangeNotifier {
133137

134138
_isRunning = true;
135139
_collectedReadings = 0;
140+
_isFetching = false;
141+
136142
_dataTimer =
137143
Timer.periodic(Duration(milliseconds: _timegapMs), (timer) async {
144+
if (_isFetching || _isDisposed) return;
145+
_isFetching = true;
146+
138147
try {
139148
await _fetchSensorData();
140149
_collectedReadings++;
@@ -147,29 +156,36 @@ class ADS1115Provider extends ChangeNotifier {
147156
_removeOldestDataPoints();
148157
}
149158
} catch (e) {
150-
logger.e('Error fetching sensor data: $e');
159+
String errorMsg = e.toString();
160+
if (errorMsg.contains("Expected")) {
161+
logger.w('ADS1115 dropped a frame. Skipping gracefully...');
162+
} else {
163+
logger.e('Error fetching sensor data: $e');
164+
}
165+
} finally {
166+
_isFetching = false;
151167
}
152168
});
153-
notifyListeners();
169+
if (!_isDisposed) notifyListeners();
154170
}
155171

156172
void _stopDataCollection() {
157173
_isRunning = false;
158174
_dataTimer?.cancel();
159175
_dataTimer = null;
160-
notifyListeners();
176+
if (!_isDisposed) notifyListeners();
161177
}
162178

163179
Future<void> _fetchSensorData() async {
164-
if (_ads1115 == null) return;
180+
if (_ads1115 == null || _isDisposed) return;
165181

166182
try {
167183
final rawData = await _ads1115!.getRawData();
168184
_voltage = rawData['voltage'] ?? 0.0;
169185
_currentTime += _timegapMs / 1000.0;
170186

171187
_addDataPoint(_voltageData, _voltage);
172-
notifyListeners();
188+
if (!_isDisposed) notifyListeners();
173189
} catch (e) {
174190
logger.e('Error in _fetchSensorData: $e');
175191
rethrow;
@@ -193,32 +209,31 @@ class ADS1115Provider extends ChangeNotifier {
193209

194210
void toggleLooping() {
195211
_isLooping = !_isLooping;
196-
notifyListeners();
212+
if (!_isDisposed) notifyListeners();
197213
}
198214

199215
void setTimegap(int timegapMs) {
200-
if (_timegapMs == timegapMs) {
201-
return;
202-
}
216+
if (_timegapMs == timegapMs) return;
217+
203218
_timegapMs = timegapMs;
204219
if (_isRunning) {
205220
_stopDataCollection();
206221
_startDataCollection();
207222
}
208-
notifyListeners();
223+
if (!_isDisposed) notifyListeners();
209224
}
210225

211226
void setNumberOfReadings(int numberOfReadings) {
212227
_numberOfReadings = numberOfReadings;
213-
notifyListeners();
228+
if (!_isDisposed) notifyListeners();
214229
}
215230

216231
void clearData() {
217232
_voltageData.clear();
218233
_voltage = 0.0;
219234
_currentTime = 0.0;
220235
_collectedReadings = 0;
221-
notifyListeners();
236+
if (!_isDisposed) notifyListeners();
222237
}
223238

224239
bool get isCollectionComplete {
@@ -227,6 +242,7 @@ class ADS1115Provider extends ChangeNotifier {
227242

228243
@override
229244
void dispose() {
245+
_isDisposed = true;
230246
_stopDataCollection();
231247
super.dispose();
232248
}

‎lib/providers/apds9960_provider.dart‎

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class APDS9960Provider extends ChangeNotifier {
1414
APDS9960? _apds9960;
1515
Timer? _dataTimer;
1616

17+
bool _isDisposed = false;
18+
bool _isFetching = false;
19+
1720
int _red = 0;
1821
int _green = 0;
1922
int _blue = 0;
@@ -76,7 +79,7 @@ class APDS9960Provider extends ChangeNotifier {
7679
}
7780

7881
_apds9960 = await APDS9960.create(i2c, scienceLab);
79-
notifyListeners();
82+
if (!_isDisposed) notifyListeners();
8083
} catch (e) {
8184
logger.e('Error initializing APDS9960: $e');
8285
}
@@ -96,7 +99,7 @@ class APDS9960Provider extends ChangeNotifier {
9699
_gestureString = '';
97100
}
98101

99-
notifyListeners();
102+
if (!_isDisposed) notifyListeners();
100103
}
101104
}
102105

@@ -113,9 +116,13 @@ class APDS9960Provider extends ChangeNotifier {
113116

114117
_isRunning = true;
115118
_collectedReadings = 0;
119+
_isFetching = false;
116120

117121
_dataTimer =
118122
Timer.periodic(Duration(milliseconds: _timegapMs), (timer) async {
123+
if (_isFetching || _isDisposed) return;
124+
_isFetching = true;
125+
119126
try {
120127
await _fetchSensorData();
121128
_collectedReadings++;
@@ -128,21 +135,28 @@ class APDS9960Provider extends ChangeNotifier {
128135
_removeOldestDataPoints();
129136
}
130137
} catch (e) {
131-
logger.e('Error fetching sensor data: $e');
138+
String errorMsg = e.toString();
139+
if (errorMsg.contains("Expected")) {
140+
logger.w('APDS9960 dropped a frame. Skipping gracefully...');
141+
} else {
142+
logger.e('Error fetching sensor data: $e');
143+
}
144+
} finally {
145+
_isFetching = false;
132146
}
133147
});
134-
notifyListeners();
148+
if (!_isDisposed) notifyListeners();
135149
}
136150

137151
void _stopDataCollection() {
138152
_isRunning = false;
139153
_dataTimer?.cancel();
140154
_dataTimer = null;
141-
notifyListeners();
155+
if (!_isDisposed) notifyListeners();
142156
}
143157

144158
Future<void> _fetchSensorData() async {
145-
if (_apds9960 == null) return;
159+
if (_apds9960 == null || _isDisposed) return;
146160

147161
try {
148162
final rawData = await _apds9960!.getRawData(_mode);
@@ -168,7 +182,7 @@ class APDS9960Provider extends ChangeNotifier {
168182
_gestureString = _apds9960!.getGestureString(_gesture);
169183
}
170184

171-
notifyListeners();
185+
if (!_isDisposed) notifyListeners();
172186
} catch (e) {
173187
logger.e('Error in _fetchSensorData: $e');
174188
rethrow;
@@ -194,7 +208,7 @@ class APDS9960Provider extends ChangeNotifier {
194208

195209
void toggleLooping() {
196210
_isLooping = !_isLooping;
197-
notifyListeners();
211+
if (!_isDisposed) notifyListeners();
198212
}
199213

200214
void setTimegap(int timegapMs) {
@@ -205,12 +219,12 @@ class APDS9960Provider extends ChangeNotifier {
205219
_startDataCollection();
206220
}
207221

208-
notifyListeners();
222+
if (!_isDisposed) notifyListeners();
209223
}
210224

211225
void setNumberOfReadings(int numberOfReadings) {
212226
_numberOfReadings = numberOfReadings;
213-
notifyListeners();
227+
if (!_isDisposed) notifyListeners();
214228
}
215229

216230
void clearData() {
@@ -226,7 +240,7 @@ class APDS9960Provider extends ChangeNotifier {
226240
_gestureString = '';
227241
_currentTime = 0.0;
228242
_collectedReadings = 0;
229-
notifyListeners();
243+
if (!_isDisposed) notifyListeners();
230244
}
231245

232246
bool get isCollectionComplete {
@@ -235,6 +249,7 @@ class APDS9960Provider extends ChangeNotifier {
235249

236250
@override
237251
void dispose() {
252+
_isDisposed = true;
238253
_stopDataCollection();
239254
super.dispose();
240255
}

0 commit comments

Comments
 (0)