Refactor USB connection handling and improve notification setup

This commit is contained in:
just_stuff_tm
2026-03-02 00:57:28 -05:00
committed by just-stuff-tm
parent 5f4333398e
commit f462815775
+48 -36
View File
@@ -738,16 +738,14 @@ class MeshCoreConnector extends ChangeNotifier {
}); });
await FlutterBluePlus.startScan( await FlutterBluePlus.startScan(
withKeywords: ["MeshCore-", "Whisper-", "Wismesh-", "WisCore-"], withKeywords: ["MeshCore-", "Whisper-"],
webOptionalServices: [Guid(MeshCoreUuids.service)], webOptionalServices: [Guid(MeshCoreUuids.service)],
timeout: timeout, timeout: timeout,
androidScanMode: AndroidScanMode.lowLatency, androidScanMode: AndroidScanMode.lowLatency,
); );
await Future.delayed(timeout); await Future.delayed(timeout);
if (!PlatformInfo.isWeb) { await stopScan();
await stopScan();
}
} }
Future<void> stopScan() async { Future<void> stopScan() async {
@@ -836,30 +834,17 @@ class MeshCoreConnector extends ChangeNotifier {
throw Exception("MeshCore characteristics not found"); throw Exception("MeshCore characteristics not found");
} }
if (PlatformInfo.isWeb) { bool notifySet = false;
debugPrint('Starting setNotifyValue(true)'); for (int attempt = 0; attempt < 3 && !notifySet; attempt++) {
debugPrint('Web: Calling setNotifyValue(true) without awaiting'); try {
unawaited(() async { if (attempt > 0) {
try { await Future.delayed(Duration(milliseconds: 500 * attempt));
await _txCharacteristic!.setNotifyValue(true);
} catch (error) {
debugPrint('Web setNotifyValue error (ignoring): $error');
}
}());
debugPrint('setNotifyValue(true) configuration completed');
} else {
bool notifySet = false;
for (int attempt = 0; attempt < 3 && !notifySet; attempt++) {
try {
if (attempt > 0) {
await Future.delayed(Duration(milliseconds: 500 * attempt));
}
await _txCharacteristic!.setNotifyValue(true);
notifySet = true;
} catch (e) {
debugPrint('setNotifyValue attempt ${attempt + 1}/3 failed: $e');
if (attempt == 2) rethrow;
} }
await _txCharacteristic!.setNotifyValue(true);
notifySet = true;
} catch (e) {
debugPrint('setNotifyValue attempt ${attempt + 1}/3 failed: $e');
if (attempt == 2) rethrow;
} }
} }
_notifySubscription = _txCharacteristic!.onValueReceived.listen( _notifySubscription = _txCharacteristic!.onValueReceived.listen(
@@ -867,8 +852,6 @@ class MeshCoreConnector extends ChangeNotifier {
); );
_setState(MeshCoreConnectionState.connected); _setState(MeshCoreConnectionState.connected);
_hasReceivedDeviceInfo = false;
_pendingInitialChannelSync = true;
await _requestDeviceInfo(); await _requestDeviceInfo();
_startBatteryPolling(); _startBatteryPolling();
@@ -882,6 +865,9 @@ class MeshCoreConnector extends ChangeNotifier {
// Keep device clock aligned on every connection. // Keep device clock aligned on every connection.
await syncTime(); await syncTime();
// Fetch channels so we can track unread counts for incoming messages
unawaited(getChannels());
} catch (e) { } catch (e) {
debugPrint("Connection error: $e"); debugPrint("Connection error: $e");
await disconnect(manual: false); await disconnect(manual: false);
@@ -904,6 +890,7 @@ class MeshCoreConnector extends ChangeNotifier {
await stopScan(); await stopScan();
_cancelReconnectTimer(); _cancelReconnectTimer();
_manualDisconnect = false; _manualDisconnect = false;
_resetConnectionHandshakeState();
_activeTransport = MeshCoreTransportType.usb; _activeTransport = MeshCoreTransportType.usb;
_activeUsbPort = portName; _activeUsbPort = portName;
unawaited(_backgroundService?.start()); unawaited(_backgroundService?.start());
@@ -929,16 +916,20 @@ class MeshCoreConnector extends ChangeNotifier {
); );
_setState(MeshCoreConnectionState.connected); _setState(MeshCoreConnectionState.connected);
_hasReceivedDeviceInfo = false;
_pendingInitialChannelSync = true; _pendingInitialChannelSync = true;
await _requestDeviceInfo(); await _requestDeviceInfo();
_startBatteryPolling(); _startBatteryPolling();
final gotSelfInfo = await _waitForSelfInfo( var gotSelfInfo = await _waitForSelfInfo(
timeout: const Duration(seconds: 3), timeout: const Duration(seconds: 3),
); );
if (!gotSelfInfo) { if (!gotSelfInfo) {
await refreshDeviceInfo(); await refreshDeviceInfo();
await _waitForSelfInfo(timeout: const Duration(seconds: 3)); gotSelfInfo = await _waitForSelfInfo(
timeout: const Duration(seconds: 3),
);
}
if (!gotSelfInfo) {
throw StateError('Timed out waiting for SELF_INFO during connect');
} }
await syncTime(); await syncTime();
@@ -980,6 +971,19 @@ class MeshCoreConnector extends ChangeNotifier {
return result; return result;
} }
void _resetConnectionHandshakeState() {
_selfPublicKey = null;
_selfName = null;
_selfLatitude = null;
_selfLongitude = null;
_awaitingSelfInfo = false;
_selfInfoRetryTimer?.cancel();
_selfInfoRetryTimer = null;
_hasReceivedDeviceInfo = false;
_pendingInitialChannelSync = false;
_hasReceivedDeviceInfo = false;
}
bool get _shouldAutoReconnect => bool get _shouldAutoReconnect =>
!_manualDisconnect && !_manualDisconnect &&
_lastDeviceId != null && _lastDeviceId != null &&
@@ -2119,12 +2123,16 @@ class MeshCoreConnector extends ChangeNotifier {
// Auto-fetch contacts after getting self info // Auto-fetch contacts after getting self info
getContacts(); getContacts();
_maybeStartInitialChannelSync(); if (_activeTransport == MeshCoreTransportType.usb) {
_maybeStartInitialChannelSync();
}
} }
void _handleDeviceInfo(Uint8List frame) { void _handleDeviceInfo(Uint8List frame) {
if (frame.length < 4) return; if (frame.length < 4) return;
_hasReceivedDeviceInfo = true; if (_activeTransport == MeshCoreTransportType.usb) {
_hasReceivedDeviceInfo = true;
}
_firmwareVerCode = frame[1]; _firmwareVerCode = frame[1];
// Parse client_repeat from firmware v9+ (byte 80) // Parse client_repeat from firmware v9+ (byte 80)
@@ -2148,13 +2156,17 @@ class MeshCoreConnector extends ChangeNotifier {
if (nextMaxChannels > previousMaxChannels) { if (nextMaxChannels > previousMaxChannels) {
unawaited(loadChannelSettings(maxChannels: nextMaxChannels)); unawaited(loadChannelSettings(maxChannels: nextMaxChannels));
unawaited(loadAllChannelMessages(maxChannels: nextMaxChannels)); unawaited(loadAllChannelMessages(maxChannels: nextMaxChannels));
if (isConnected && !_pendingInitialChannelSync) { if (isConnected &&
(_activeTransport != MeshCoreTransportType.usb ||
!_pendingInitialChannelSync)) {
unawaited(getChannels(maxChannels: nextMaxChannels)); unawaited(getChannels(maxChannels: nextMaxChannels));
} }
} }
} }
notifyListeners(); notifyListeners();
_maybeStartInitialChannelSync(); if (_activeTransport == MeshCoreTransportType.usb) {
_maybeStartInitialChannelSync();
}
} }
void _maybeStartInitialChannelSync() { void _maybeStartInitialChannelSync() {